]> git.jsancho.org Git - lugaru.git/commitdiff
Initial import.
authorRyan C. Gordon <icculus@icculus.org>
Fri, 5 Aug 2005 12:06:08 +0000 (12:06 +0000)
committerRyan C. Gordon <icculus@icculus.org>
Fri, 5 Aug 2005 12:06:08 +0000 (12:06 +0000)
87 files changed:
Lugaru.sln [new file with mode: 0644]
Lugaru.vcproj [new file with mode: 0644]
Source/Carbon Include.h [new file with mode: 0644]
Source/Carbon.r [new file with mode: 0644]
Source/CarbonStdCLib.h [new file with mode: 0644]
Source/Constants.h [new file with mode: 0644]
Source/DRIVER.CC [new file with mode: 0644]
Source/Frustum.cpp [new file with mode: 0644]
Source/Frustum.h [new file with mode: 0644]
Source/Game.h [new file with mode: 0644]
Source/GameDraw.cpp [new file with mode: 0644]
Source/GameInitDispose.cpp [new file with mode: 0644]
Source/GameTick.cpp [new file with mode: 0644]
Source/Globals.cpp [new file with mode: 0644]
Source/Lights.cpp [new file with mode: 0644]
Source/Lights.h [new file with mode: 0644]
Source/LinkedList.h [new file with mode: 0644]
Source/MD5.CC [new file with mode: 0644]
Source/MacInput.cpp [new file with mode: 0644]
Source/MacInput.h [new file with mode: 0644]
Source/Models.cpp [new file with mode: 0644]
Source/Models.h [new file with mode: 0644]
Source/MoreFilesX.c [new file with mode: 0644]
Source/MoreFilesX.h [new file with mode: 0644]
Source/Objects.cpp [new file with mode: 0644]
Source/Objects.h [new file with mode: 0644]
Source/OpenGL_Full_Screen.cpp [new file with mode: 0644]
Source/OpenGL_Windows.cpp [new file with mode: 0644]
Source/Person.cpp [new file with mode: 0644]
Source/Person.h [new file with mode: 0644]
Source/PhysicsMath.h [new file with mode: 0644]
Source/Pointer.h [new file with mode: 0644]
Source/Quaternions.cpp [new file with mode: 0644]
Source/Quaternions.h [new file with mode: 0644]
Source/Random.c [new file with mode: 0644]
Source/Random.h [new file with mode: 0644]
Source/Skeleton.cpp [new file with mode: 0644]
Source/Skeleton.h [new file with mode: 0644]
Source/Skybox.cpp [new file with mode: 0644]
Source/Skybox.h [new file with mode: 0644]
Source/Sprites.cpp [new file with mode: 0644]
Source/Sprites.h [new file with mode: 0644]
Source/TGALoader.cpp [new file with mode: 0644]
Source/TGALoader.h [new file with mode: 0644]
Source/Terrain.cpp [new file with mode: 0644]
Source/Terrain.h [new file with mode: 0644]
Source/Text.cpp [new file with mode: 0644]
Source/Text.h [new file with mode: 0644]
Source/Weapons.cpp [new file with mode: 0644]
Source/Weapons.h [new file with mode: 0644]
Source/WinDefs.cpp [new file with mode: 0644]
Source/WinDefs.h [new file with mode: 0644]
Source/WinInput.cpp [new file with mode: 0644]
Source/WinInput.h [new file with mode: 0644]
Source/binio.h [new file with mode: 0644]
Source/fmod.h [new file with mode: 0644]
Source/fmod_errors.h [new file with mode: 0644]
Source/fmod_header.h [new file with mode: 0644]
Source/fmoddyn.h [new file with mode: 0644]
Source/gl.h [new file with mode: 0644]
Source/logger/Copy of logger.cpp [new file with mode: 0644]
Source/logger/Copy of logger.h [new file with mode: 0644]
Source/logger/logger.cpp [new file with mode: 0644]
Source/logger/logger.h [new file with mode: 0644]
Source/md5.h [new file with mode: 0644]
Source/mmgr.cpp [new file with mode: 0644]
Source/mmgr.h [new file with mode: 0644]
Source/nommgr.h [new file with mode: 0644]
Source/nsp_network.c [new file with mode: 0644]
Source/pack.c [new file with mode: 0644]
Source/pack_private.c [new file with mode: 0644]
Source/pack_private.h [new file with mode: 0644]
Source/private.c [new file with mode: 0644]
Source/private.h [new file with mode: 0644]
Source/res/Lugaru.aps [new file with mode: 0644]
Source/res/Lugaru.png [new file with mode: 0644]
Source/res/Lugaru.psd [new file with mode: 0644]
Source/res/Lugaru.rc [new file with mode: 0644]
Source/res/Untitled-1.jpg [new file with mode: 0644]
Source/res/icon1.ico [new file with mode: 0644]
Source/res/icon2.ico [new file with mode: 0644]
Source/res/lugaru.ico [new file with mode: 0644]
Source/res/resource.h [new file with mode: 0644]
Source/unpack.c [new file with mode: 0644]
Source/unpack_private.c [new file with mode: 0644]
Source/unpack_private.h [new file with mode: 0644]
Source/wincompat.h [new file with mode: 0644]

diff --git a/Lugaru.sln b/Lugaru.sln
new file mode 100644 (file)
index 0000000..cd2144e
--- /dev/null
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 8.00\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Lugaru", "Lugaru.vcproj", "{71D87E45-76A7-497F-9176-DA2600007A65}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+       EndProjectSection\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfiguration) = preSolution\r
+               Debug = Debug\r
+               Release = Release\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfiguration) = postSolution\r
+               {71D87E45-76A7-497F-9176-DA2600007A65}.Debug.ActiveCfg = Debug|Win32\r
+               {71D87E45-76A7-497F-9176-DA2600007A65}.Debug.Build.0 = Debug|Win32\r
+               {71D87E45-76A7-497F-9176-DA2600007A65}.Release.ActiveCfg = Release|Win32\r
+               {71D87E45-76A7-497F-9176-DA2600007A65}.Release.Build.0 = Release|Win32\r
+       EndGlobalSection\r
+       GlobalSection(ExtensibilityGlobals) = postSolution\r
+       EndGlobalSection\r
+       GlobalSection(ExtensibilityAddIns) = postSolution\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/Lugaru.vcproj b/Lugaru.vcproj
new file mode 100644 (file)
index 0000000..7661834
--- /dev/null
@@ -0,0 +1,360 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.10"\r
+       Name="Lugaru"\r
+       ProjectGUID="{71D87E45-76A7-497F-9176-DA2600007A65}"\r
+       RootNamespace="Lugaru"\r
+       Keyword="Win32Proj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="./Source;./Source/devil/include"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS"\r
+                               MinimalRebuild="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="5"\r
+                               BufferSecurityCheck="TRUE"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="FALSE"\r
+                               DebugInformationFormat="4"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/Lugaru.exe"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(OutDir)/Lugaru.pdb"\r
+                               SubSystem="2"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="./Source;./Source/devil/include"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"\r
+                               BasicRuntimeChecks="0"\r
+                               RuntimeLibrary="4"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="FALSE"\r
+                               DebugInformationFormat="3"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/Lugaru.exe"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="TRUE"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
+                       <File\r
+                               RelativePath=".\Source\Frustum.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\GameDraw.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\GameInitDispose.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\GameTick.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Globals.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Lights.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Models.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Objects.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\OpenGL_Windows.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\pack.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\pack_private.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Person.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\private.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Quaternions.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Random.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Skeleton.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Skybox.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Sprites.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Terrain.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Text.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\TGALoader.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\unpack.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\unpack_private.c">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Weapons.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\WinDefs.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\WinInput.cpp">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
+                       <File\r
+                               RelativePath=".\Source\binio.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Constants.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Frustum.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Game.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\gl.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Lights.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\LinkedList.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\md5.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Models.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Objects.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\pack_private.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Person.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\PhysicsMath.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Pointer.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\private.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Quaternions.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Random.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Skeleton.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Skybox.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Sprites.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Terrain.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Text.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\TGALoader.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\unpack_private.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\Weapons.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\wincompat.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\WinDefs.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\WinInput.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">\r
+                       <File\r
+                               RelativePath=".\Source\res\lugaru.ico">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\res\Lugaru.rc">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\res\resource.h">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="fmod"\r
+                       Filter="">\r
+                       <File\r
+                               RelativePath=".\Source\fmod.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\fmod_errors.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\fmod_header.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\fmoddyn.h">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\fmodvc.lib">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="devil"\r
+                       Filter="">\r
+                       <Filter\r
+                               Name="lib"\r
+                               Filter="">\r
+                               <File\r
+                                       RelativePath=".\Source\devil\lib\DevIL.lib">\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\Source\devil\lib\ILU.lib">\r
+                               </File>\r
+                               <File\r
+                                       RelativePath=".\Source\devil\lib\ILUT.lib">\r
+                               </File>\r
+                       </Filter>\r
+               </Filter>\r
+               <Filter\r
+                       Name="logger"\r
+                       Filter="">\r
+                       <File\r
+                               RelativePath=".\Source\logger\logger.cpp">\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\Source\logger\logger.h">\r
+                       </File>\r
+               </Filter>\r
+               <File\r
+                       RelativePath=".\Data\config.txt">\r
+               </File>\r
+               <File\r
+                       RelativePath=".\Source\Driver.cc">\r
+               </File>\r
+               <File\r
+                       RelativePath=".\Source\Md5.cc">\r
+               </File>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/Source/Carbon Include.h b/Source/Carbon Include.h
new file mode 100644 (file)
index 0000000..5fee235
--- /dev/null
@@ -0,0 +1,6 @@
+// Carbon Include.h
+
+// Put Carbon specific stuff here to maintain 9/Carbon buildability...
+
+
+#define TARGET_API_MAC_CARBON 1
\ No newline at end of file
diff --git a/Source/Carbon.r b/Source/Carbon.r
new file mode 100644 (file)
index 0000000..ca7d3dd
--- /dev/null
@@ -0,0 +1 @@
+/*\r *  Permit this Carbon application to launch on OS X\r *\r *  Copyright Â© 1997-2001 Metrowerks Corporation\r *\r *  Questions and comments to:\r *       <mailto:support@metrowerks.com>\r *       <http://www.metrowerks.com/>\r */\r\r\r\r/*----------------------------carb Â¥ Carbon on OS X launch information --------------------------*/\rtype 'carb' {\r};\r\r\rresource 'carb'(0) {\r};
\ No newline at end of file
diff --git a/Source/CarbonStdCLib.h b/Source/CarbonStdCLib.h
new file mode 100644 (file)
index 0000000..aa67ef0
--- /dev/null
@@ -0,0 +1,54 @@
+/************************************************************
+
+    CarbonStdCLib.h
+    Assorted helper functions associated with CarbonStdClib.o.
+
+    Copyright Apple Computer,Inc.  2001
+    All rights reserved
+
+ * Warning:  This interface is NOT a part of the ANSI C standard.
+ *           This header file is not POSIX compliant.
+ *           For portable code, don't use this interface.
+
+************************************************************/
+
+
+#ifndef __CARBONSTDCLIB__
+#define __CARBONSTDCLIB__
+
+#ifndef __CONDITIONALMACROS__
+#include <ConditionalMacros.h>
+#endif
+
+#if defined (__powerc) || defined (powerc) || defined (__CFM68K__)
+    #pragma import on
+#endif
+
+#if __cplusplus
+extern "C" {
+#endif  /* __cplusplus */
+
+#if !(CALL_NOT_IN_CARBON || __MPWINTERNAL__)
+
+extern void InitCarbonStdCLib( void ) ;
+extern void TermCarbonStdCLib( void ) ;
+
+extern void ConvertUnixPathToHFSPath(const char *unixPath, char *hfsPath) ;
+extern void ConvertHFSPathToUnixPath(const char *hfsPath, char *unixPath) ;
+
+/* BSD functions */
+
+int bsd_chdir(const char *path) ;
+int bsd_chmod(const char *path , int mode) ;
+
+#endif
+
+#if __cplusplus
+}
+#endif  /* __cplusplus */
+
+#if defined (__powerc) || defined (powerc) || defined (__CFM68K__)
+    #pragma import off
+#endif
+
+#endif  /* __CARBONSTDCLIB__ */
diff --git a/Source/Constants.h b/Source/Constants.h
new file mode 100644 (file)
index 0000000..e063d36
--- /dev/null
@@ -0,0 +1,328 @@
+#ifndef _CONSTANTS_H_
+#define _CONSTANTS_H_
+
+#define awardklutz 0
+#define awardflawless 1
+#define awardalldead 2
+#define awardnodead 3
+#define awardstealth 4
+#define awardswordsman 5
+#define awardkungfu 6
+#define awardknifefighter 7
+#define awardcoward 8
+#define awardevasion 9
+#define awardacrobat 10
+#define awardlongrange 11
+#define awardbrutal 12
+#define awardhyper 13
+#define awardaikido 14
+#define awardrambo 15
+#define awardfast 16
+#define awardrealfast 17
+#define awarddamnfast 18
+#define awardstrategy 19
+#define awardbojutsu 20
+
+#define mapkilleveryone 0
+#define mapgosomewhere 1
+#define mapkillsomeone 2
+#define mapkillmost 3
+
+#define wpkeepwalking 0
+#define wppause 1
+
+#define typeactive 0
+#define typesitting 1
+#define typesittingwall 2
+#define typesleeping 3
+#define typedead1 4
+#define typedead2 5
+#define typedead3 6
+#define typedead4 7
+
+#define tracheotomy 1
+#define backstab 2
+#define spinecrusher 3
+#define ninja 4
+#define style 5
+#define cannon 6
+#define aimbonus 7
+#define deepimpact 8
+#define touchofdeath 9
+#define swordreversebonus 10
+#define staffreversebonus 11
+#define reverseko 12
+#define solidhit 13
+#define twoxcombo 14
+#define threexcombo 15
+#define fourxcombo 16
+#define megacombo 17
+#define Reversal 18
+#define Stabbonus 19
+#define Slicebonus 20
+#define Bullseyebonus 21
+#define Slashbonus 22
+#define Wolfbonus 23
+#define FinishedBonus 24
+#define TackleBonus 25
+#define AboveBonus 26
+
+#define boneconnect 0
+#define constraint 1
+#define muscle 2
+
+#define head 0
+#define neck 1
+#define leftshoulder 2
+#define leftelbow 3
+#define leftwrist 4
+#define lefthand 5
+#define rightshoulder 6
+#define rightelbow 7
+#define rightwrist 8
+#define righthand 9
+#define abdomen 10
+#define lefthip 11
+#define righthip 12
+#define groin 13
+#define leftknee 14
+#define leftankle 15
+#define leftfoot 16
+#define rightknee 17
+#define rightankle 18
+#define rightfoot 19
+
+#define max_joints 50
+#define max_frames 50
+#define max_muscles 100
+
+#define animation_count 140
+
+#define runanim 0
+#define bounceidleanim 1
+#define stopanim 2
+#define jumpupanim 3
+#define jumpdownanim 4
+#define landanim 5
+#define climbanim 6
+#define hanganim 7
+#define spinkickanim 8
+#define tempanim 9
+#define getupfromfrontanim 10
+#define getupfrombackanim 11
+#define crouchanim 12
+#define sneakanim 13
+#define rollanim 14
+#define flipanim 15
+#define spinkickreversedanim 16
+#define spinkickreversalanim 17
+#define lowkickanim 18
+#define sweepanim 19
+#define sweepreversedanim 20
+#define sweepreversalanim 21
+#define rabbitkickanim 22
+#define rabbitkickreversedanim 23
+#define rabbitkickreversalanim 24
+#define upunchanim 25
+#define staggerbackhighanim 26
+#define upunchreversedanim 27
+#define upunchreversalanim 28
+#define hurtidleanim 29
+#define backhandspringanim 30
+#define fightidleanim 31
+#define walkanim 32
+#define fightsidestep 33
+#define killanim 34
+#define sneakattackanim 35
+#define sneakattackedanim 36
+#define drawrightanim 37
+#define knifeslashstartanim 38
+#define crouchstabanim 39
+#define crouchdrawrightanim 40
+#define knifefollowanim 41
+#define knifefollowedanim 42
+#define knifethrowanim 43
+#define removeknifeanim 44
+#define crouchremoveknifeanim 45
+#define jumpreversedanim 46
+#define jumpreversalanim 47
+#define landhardanim 48
+#define staggerbackhardanim 49
+#define dropkickanim 50
+#define winduppunchanim 51
+#define winduppunchblockedanim 52
+#define blockhighleftanim 53
+#define blockhighleftstrikeanim 54
+#define walljumpfrontanim 55
+#define walljumpbackanim 56
+#define walljumpleftanim 57
+#define walljumprightanim 58
+#define backflipanim 59
+#define leftflipanim 60
+#define rightflipanim 61
+#define walljumprightkickanim 62
+#define walljumpleftkickanim 63
+#define knifefightidleanim 64
+#define knifesneakattackanim 65
+#define knifesneakattackedanim 66
+#define swordstabanim 67
+#define swordslashleftanim 68
+#define swordslashrightanim 69
+#define swordfightidleanim 70
+#define swordsneakattackanim 71
+#define swordsneakattackedanim 72
+#define drawleftanim 73
+#define swordslashanim 74
+#define swordgroundstabanim 75
+#define dodgebackanim 76
+#define swordslashreversedanim 77
+#define swordslashreversalanim 78
+#define knifeslashreversedanim 79
+#define knifeslashreversalanim 80
+#define swordfightidlebothanim 81
+#define swordslashparryanim 82
+#define sworddisarmanim 83
+#define swordslashparriedanim 84
+#define wolfidle 85
+#define wolffightidle 86    
+#define wolfswordidle 87
+#define wolfhurtidle 88
+#define wolfcrouchanim 89
+#define wolfsneakanim 90
+#define wolfrunanim 91
+#define wolfstopanim 92
+#define wolfclawanim 93
+#define wolflandanim 94
+#define wolflandhardanim 95
+#define wolfrunninganim 96
+#define rabbitrunninganim 97
+#define frontflipanim 98
+#define rabbittackleanim 99
+#define rabbittacklinganim 100
+#define rabbittackledfrontanim 101
+#define rabbittackledbackanim 102
+#define rabbittacklereversal 103
+#define rabbittacklereversed 104
+#define wolftackleanim 105
+#define wolftacklinganim 106
+#define wolftackledfrontanim 107
+#define wolftackledbacanim 108
+#define wolftacklereversal 109
+#define wolftacklereversed 110
+#define wolfslapanim 111
+#define wolfbashanim 112
+#define staffhitanim 113
+#define staffgroundsmashanim 114
+#define staffspinhitanim 115
+#define staffhitreversedanim 116
+#define staffhitreversalanim 117
+#define staffspinhitreversedanim 118
+#define staffspinhitreversalanim 119
+#define sleepanim 120
+#define sitanim 121
+#define talkidleanim 122
+#define sitwallanim 123
+#define dead1anim 124
+#define dead2anim 125
+#define dead3anim 126
+#define dead4anim 127
+
+#define max_dialogues 20
+#define max_dialoguelength 20
+
+#define max_model_vertex                       3000            // maximum number of vertexs
+#define max_textured_triangle          3000            // maximum number of texture-filled triangles in a model
+
+#define stream_music1desert 0
+#define stream_music1grass 1
+#define stream_music1snow 2
+#define stream_music2 3
+#define stream_music3 4
+#define stream_music4 5
+#define stream_menumusic 6
+#define stream_desertambient 7
+#define stream_firesound 8
+#define stream_wind 9
+
+//#define music1desert 0
+//#define music1grass 1
+//#define music1snow 2
+//#define music2 3
+//#define music3 4
+//#define music4 5
+//#define menumusic 6
+//#define desertambient 7
+//#define firesound 8
+//#define wind 9
+#define footstepsound 10
+#define footstepsound2 11
+#define footstepsound3 12
+#define footstepsound4 13
+#define jumpsound 14
+#define landsound 15
+#define whooshsound 16
+#define hawksound 17
+#define landsound1 18
+#define landsound2 19
+#define breaksound 20
+#define lowwhooshsound 21
+#define heavyimpactsound 22
+#define firestartsound 23
+#define fireendsound 24
+#define breaksound2 25
+#define knifedrawsound 26
+#define knifesheathesound 27
+#define knifeswishsound 28
+#define knifeslicesound 29
+#define skidsound 30
+#define snowskidsound 31
+#define bushrustle 32
+#define midwhooshsound 33
+#define highwhooshsound 34
+#define movewhooshsound 35
+#define thudsound 36
+#define whooshhitsound 37
+#define clank1sound 38
+#define clank2sound 39
+#define clank3sound 40
+#define clank4sound 41
+#define consolefailsound 42
+#define consolesuccesssound 43
+#define swordslicesound 44
+#define metalhitsound 45
+#define clawslicesound 46
+#define splattersound 47
+#define growlsound 48
+#define growl2sound 49
+#define barksound 50
+#define snarlsound 51
+#define snarl2sound 52
+#define barkgrowlsound 53
+#define bark2sound 54
+#define bark3sound 55
+#define rabbitattacksound 56
+#define rabbitattack2sound 57
+#define rabbitattack3sound 58
+#define rabbitattack4sound 59
+#define rabbitpainsound 60
+#define rabbitpain1sound 61
+#define rabbitpain2sound 62
+#define rabbitchitter 63
+#define rabbitchitter2 64
+#define fleshstabsound 65
+#define fleshstabremovesound 66
+#define swordstaffsound 67
+#define staffbodysound 68
+#define staffheadsound 69
+#define alarmsound 70
+#define staffbreaksound 71
+
+#define normalmode 0
+#define motionblurmode 1
+#define radialzoommode 2
+#define realmotionblurmode 3
+#define doublevisionmode 4
+#define glowmode 5
+
+#define maxplayers 10
+#endif
\ No newline at end of file
diff --git a/Source/DRIVER.CC b/Source/DRIVER.CC
new file mode 100644 (file)
index 0000000..df96e35
--- /dev/null
@@ -0,0 +1,202 @@
+// DRIVER.CC - test driver for the C++/object oriented translation and 
+//             modification of MD5.
+
+// Translation and modification (c) 1995 by Mordechai T. Abzug 
+
+// This translation/ modification is provided "as is," without express or 
+// implied warranty of any kind.
+
+// The translator/ modifier does not claim (1) that MD5 will do what you think 
+// it does; (2) that this translation/ modification is accurate; or (3) that 
+// this software is "merchantible."  (Language for this disclaimer partially 
+// copied from the disclaimer below).
+
+/* based on:
+
+   MDDRIVER.C - test driver for MD2, MD4 and MD5
+
+  Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+rights reserved.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+
+#include "md5.h"
+
+
+// Length of test block, number of test blocks.
+
+#define TEST_BLOCK_LEN 1000
+#define TEST_BLOCK_COUNT 1000
+
+static void  MD5_timeTrial (void);
+static void  MD5_testSuite (void);
+static void  MD5_file (char *);
+static void  MD5_filter (void);
+static void  MD5_string (unsigned char *string);
+static char *MD5_usage (void);
+
+// Main driver.
+/*
+int main (int argc, char *argv[]){
+
+  int i;
+
+  MD5_testSuite();
+
+  if (argc > 1)
+    for (i = 1; i < argc; i++)
+      if (argv[i][0] == '-' && argv[i][1] == 's')
+       MD5_string ( (unsigned char *) argv[i] + 2);
+      else if (strcmp (argv[i], "-t") == 0)
+       MD5_timeTrial ();
+      else if (strcmp (argv[i], "-x") == 0)
+       MD5_testSuite ();
+      else if (strcmp (argv[i], "-h") == 0)
+       cout << MD5_usage()<< flush;
+      else if (strcmp (argv[i], "-help")==0)
+       cout << MD5_usage()<< flush;
+      else if (argv[i][0] == '-'){
+       cerr << argv[i] << " is an unknown option.\n" << MD5_usage()<< flush;
+       exit (1);
+      }
+      else
+       MD5_file (argv[i]);
+  else
+    MD5_filter ();
+
+  return (0);
+}
+*/
+
+// Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks.
+
+static void MD5_timeTrial ()
+{
+  MD5 context;
+  time_t endTime, startTime;
+  unsigned char block[TEST_BLOCK_LEN];
+  unsigned int i;
+
+
+  cout << "MD5 time trial. Digesting "<< TEST_BLOCK_LEN << " ";
+  cout << TEST_BLOCK_COUNT << "-byte blocks ...";
+
+  // Initialize block
+  for (i = 0; i < TEST_BLOCK_LEN; i++)
+    block[i] = (unsigned char)(i & 0xff);
+
+  // Start timer
+  time (&startTime);
+
+  // Digest blocks
+  for (i = 0; i < TEST_BLOCK_COUNT; i++)
+    context.update (block, TEST_BLOCK_LEN);
+
+  context.finalize();
+
+  // Stop timer
+  time (&endTime);
+
+  cout << " done" << endl;
+
+  cout << "Digest = " << context << endl;
+
+  cout << "Time = "<< (long)(endTime-startTime) << " seconds" << endl;
+
+  cout << "Speed = ";
+  cout << (long)TEST_BLOCK_LEN * (long)TEST_BLOCK_COUNT/(endTime-startTime);
+  cout << "bytes/second" <<endl;
+
+}
+
+// Digests a reference suite of strings and prints the results.
+/*
+static void MD5_testSuite ()
+{
+  cout << "MD5 test suite:" << endl;
+
+  MD5_string ( (unsigned char*) "");
+  MD5_string ( (unsigned char*) "a");
+  MD5_string ( (unsigned char*) "abc");
+  MD5_string ( (unsigned char*) "message digest");
+  MD5_string ( (unsigned char*) "abcdefghijklmnopqrstuvwxyz");
+  MD5_string
+ ( (unsigned char*) "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+  MD5_string
+ ( (unsigned char*) "1234567890123456789012345678901234567890\
+1234567890123456789012345678901234567890");
+}
+*/
+
+// Digests a file and prints the result.
+
+static void MD5_file (char *filename){
+
+  ifstream file(filename);
+
+  if (!file)
+    cerr << filename <<" can't be opened" << endl;
+  else {
+    MD5 context(file);
+    cout <<  "MD5 ("  << filename <<  ") = "  <<  context << endl;
+  }
+}
+
+// Digests the standard input and prints the result.
+
+static void MD5_filter ()
+{
+
+  MD5 context(cin);  // ie. run istream version of MD5 on cin.
+                     // Could also run file version of MD5 on stdin.
+
+  cout << context << endl;
+}
+
+
+
+// Digests a string and prints the result.
+/*
+void MD5_string (unsigned char *string){
+
+  MD5 context;
+  unsigned int len = strlen ( (char *)string);
+
+  context.update   (string, len);
+  context.finalize ();
+
+  cout << "MD5 (\"" << (char *)string << "\") = " << context <<endl;
+}*/
+
+
+
+static char *MD5_usage(){
+
+  return "\n\
+  MD5\n\n\
+USAGE:\n\n\
+  MD5 [-sstring] [-t] [-x] [-h] [-help] [filename]\n\n\
+Arguments (may be any combination):\n\
+  -sstring - digests string\n\
+  -t       - runs time trial\n\
+  -x       - runs test script\n\
+  -h       - displays this message\n\
+  -help    - displays this message\n\
+  filename - digests file\n\
+  (none)   - digests standard input\n\n";
+}
+
+
+
diff --git a/Source/Frustum.cpp b/Source/Frustum.cpp
new file mode 100644 (file)
index 0000000..2641bc3
--- /dev/null
@@ -0,0 +1,155 @@
+#include "frustum.h"
+#include <math.h>
+
+#include "gl.h"
+
+
+void FRUSTUM::
+       GetFrustum() {
+       static float projmatrix[16];
+       static float mvmatrix[16];
+       static float clip[16];
+       static float t;
+       
+       glGetFloatv(GL_PROJECTION_MATRIX, projmatrix);
+       glGetFloatv(GL_MODELVIEW_MATRIX, mvmatrix);
+       
+       // Combine the matrices
+       clip[0] = mvmatrix[0] * projmatrix[0] + mvmatrix[1] * projmatrix[4] + mvmatrix[2] * projmatrix[8] + mvmatrix[3] * projmatrix[12];
+       clip[1] = mvmatrix[0] * projmatrix[1] + mvmatrix[1] * projmatrix[5] + mvmatrix[2] * projmatrix[9] + mvmatrix[3] * projmatrix[13];
+       clip[2] = mvmatrix[0] * projmatrix[2] + mvmatrix[1] * projmatrix[6] + mvmatrix[2] * projmatrix[10] + mvmatrix[3] * projmatrix[14];
+       clip[3] = mvmatrix[0] * projmatrix[3] + mvmatrix[1] * projmatrix[7] + mvmatrix[2] * projmatrix[11] + mvmatrix[3] * projmatrix[15];
+       
+       clip[4] = mvmatrix[4] * projmatrix[0] + mvmatrix[5] * projmatrix[4] + mvmatrix[6] * projmatrix[8] + mvmatrix[7] * projmatrix[12];
+       clip[5] = mvmatrix[4] * projmatrix[1] + mvmatrix[5] * projmatrix[5] + mvmatrix[6] * projmatrix[9] + mvmatrix[7] * projmatrix[13];
+       clip[6] = mvmatrix[4] * projmatrix[2] + mvmatrix[5] * projmatrix[6] + mvmatrix[6] * projmatrix[10] + mvmatrix[7] * projmatrix[14];
+       clip[7] = mvmatrix[4] * projmatrix[3] + mvmatrix[5] * projmatrix[7] + mvmatrix[6] * projmatrix[11] + mvmatrix[7] * projmatrix[15];
+       
+       clip[8] = mvmatrix[8] * projmatrix[0] + mvmatrix[9] * projmatrix[4] + mvmatrix[10] * projmatrix[8] + mvmatrix[11] * projmatrix[12];
+       clip[9] = mvmatrix[8] * projmatrix[1] + mvmatrix[9] * projmatrix[5] + mvmatrix[10] * projmatrix[9] + mvmatrix[11] * projmatrix[13];
+       clip[10] = mvmatrix[8] * projmatrix[2] + mvmatrix[9] * projmatrix[6] + mvmatrix[10] * projmatrix[10] + mvmatrix[11] * projmatrix[14];
+       clip[11] = mvmatrix[8] * projmatrix[3] + mvmatrix[9] * projmatrix[7] + mvmatrix[10] * projmatrix[11] + mvmatrix[11] * projmatrix[15];
+       
+       clip[12] = mvmatrix[12] * projmatrix[0] + mvmatrix[13] * projmatrix[4] + mvmatrix[14] * projmatrix[8] + mvmatrix[15] * projmatrix[12];
+       clip[13] = mvmatrix[12] * projmatrix[1] + mvmatrix[13] * projmatrix[5] + mvmatrix[14] * projmatrix[9] + mvmatrix[15] * projmatrix[13];
+       clip[14] = mvmatrix[12] * projmatrix[2] + mvmatrix[13] * projmatrix[6] + mvmatrix[14] * projmatrix[10] + mvmatrix[15] * projmatrix[14];
+       clip[15] = mvmatrix[12] * projmatrix[3] + mvmatrix[13] * projmatrix[7] + mvmatrix[14] * projmatrix[11] + mvmatrix[15] * projmatrix[15];
+       
+       // Right plane
+       frustum[0][0] = clip[3] - clip[0];
+       frustum[0][1] = clip[7] - clip[4];
+       frustum[0][2] = clip[11] - clip[8];
+       frustum[0][3] = clip[15] - clip[12];
+       
+       // Left plane
+       frustum[1][0] = clip[3] + clip[0];
+       frustum[1][1] = clip[7] + clip[4];
+       frustum[1][2] = clip[11] + clip[8];
+       frustum[1][3] = clip[15] + clip[12];
+       
+       // Bottom plane
+       frustum[2][0] = clip[3] + clip[1];
+       frustum[2][1] = clip[7] + clip[5];
+       frustum[2][2] = clip[11] + clip[9];
+       frustum[2][3] = clip[15] + clip[13];
+       
+       // Top plane
+       frustum[3][0] = clip[3] - clip[1];
+       frustum[3][1] = clip[7] - clip[5];
+       frustum[3][2] = clip[11] - clip[9];
+       frustum[3][3] = clip[15] - clip[13];
+       
+       // Far plane
+       frustum[4][0] = clip[3] - clip[2];
+       frustum[4][1] = clip[7] - clip[6];
+       frustum[4][2] = clip[11] - clip[10];
+       frustum[4][3] = clip[15] - clip[14];
+       
+       // Near plane
+       frustum[5][0] = clip[3] + clip[2];
+       frustum[5][1] = clip[7] + clip[6];
+       frustum[5][2] = clip[11] + clip[10];
+       frustum[5][3] = clip[15] + clip[14];
+}
+
+int FRUSTUM::
+       CubeInFrustum(float x, float y, float z, float size) {
+       static int c, c2;
+       
+       for(int i=0; i<6; i++) {
+               c=0;
+               if(frustum[i][0] * (x-size) + frustum[i][1] * (y-size) + frustum[i][2] * (z-size) + frustum[i][3] > 0)
+                       c++;
+               if(frustum[i][0] * (x+size) + frustum[i][1] * (y-size) + frustum[i][2] * (z-size) + frustum[i][3] > 0)
+                       c++;
+               if(frustum[i][0] * (x-size) + frustum[i][1] * (y+size) + frustum[i][2] * (z-size) + frustum[i][3] > 0)
+                       c++;
+               if(frustum[i][0] * (x+size) + frustum[i][1] * (y+size) + frustum[i][2] * (z-size) + frustum[i][3] > 0)
+                       c++;
+               if(frustum[i][0] * (x-size) + frustum[i][1] * (y-size) + frustum[i][2] * (z+size) + frustum[i][3] > 0)
+                       c++;
+               if(frustum[i][0] * (x+size) + frustum[i][1] * (y-size) + frustum[i][2] * (z+size) + frustum[i][3] > 0)
+                       c++;
+               if(frustum[i][0] * (x-size) + frustum[i][1] * (y+size) + frustum[i][2] * (z+size) + frustum[i][3] > 0)
+                       c++;
+               if(frustum[i][0] * (x+size) + frustum[i][1] * (y+size) + frustum[i][2] * (z+size) + frustum[i][3] > 0)
+                       c++;
+               if(c==0)
+                       return 0;
+               if(c==8)
+                       c2++;
+       }
+       if(c2>=6)
+               return 2;
+       else
+               return 1;
+}
+
+int FRUSTUM::
+       CubeInFrustum(float x, float y, float z, float size, float height) {
+       static int c, c2;
+       
+       for(int i=0; i<6; i++) {
+               c=0;
+               if(frustum[i][0] * (x-size) + frustum[i][1] * (y-height) + frustum[i][2] * (z-size) + frustum[i][3] > 0)
+                       c++;
+               if(frustum[i][0] * (x+size) + frustum[i][1] * (y-height) + frustum[i][2] * (z-size) + frustum[i][3] > 0)
+                       c++;
+               if(frustum[i][0] * (x-size) + frustum[i][1] * (y+height) + frustum[i][2] * (z-size) + frustum[i][3] > 0)
+                       c++;
+               if(frustum[i][0] * (x+size) + frustum[i][1] * (y+height) + frustum[i][2] * (z-size) + frustum[i][3] > 0)
+                       c++;
+               if(frustum[i][0] * (x-size) + frustum[i][1] * (y-height) + frustum[i][2] * (z+size) + frustum[i][3] > 0)
+                       c++;
+               if(frustum[i][0] * (x+size) + frustum[i][1] * (y-height) + frustum[i][2] * (z+size) + frustum[i][3] > 0)
+                       c++;
+               if(frustum[i][0] * (x-size) + frustum[i][1] * (y+height) + frustum[i][2] * (z+size) + frustum[i][3] > 0)
+                       c++;
+               if(frustum[i][0] * (x+size) + frustum[i][1] * (y+height) + frustum[i][2] * (z+size) + frustum[i][3] > 0)
+                       c++;
+               if(c==0)
+                       return 0;
+               if(c==8)
+                       c2++;
+       }
+       if(c2>=6)
+               return 2;
+       else
+               return 1;
+}
+
+int FRUSTUM::
+       SphereInFrustum(float x, float y, float z, float radius) {
+       static int  c2;
+       
+       for(int i=0; i<6; i++) {
+               if(frustum[i][0] * x + frustum[i][1] * y + frustum[i][2] * z + frustum[i][3] > -1*radius)
+                       c2++;
+               else
+                       return 0;
+       }
+       if(c2>=6)
+               return 2;
+       else
+               return 1;
+}
\ No newline at end of file
diff --git a/Source/Frustum.h b/Source/Frustum.h
new file mode 100644 (file)
index 0000000..d748af5
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef FRUSTUM_H
+#define FRUSTUM_H
+
+class FRUSTUM {
+public:
+       float frustum[6][4];
+       void GetFrustum();
+       int CubeInFrustum(float, float, float, float);
+       int CubeInFrustum(float, float, float, float, float);
+       int SphereInFrustum(float, float, float, float);
+};
+
+#endif
\ No newline at end of file
diff --git a/Source/Game.h b/Source/Game.h
new file mode 100644 (file)
index 0000000..65cbaf1
--- /dev/null
@@ -0,0 +1,270 @@
+#ifndef _GAME_H_
+#define _GAME_H_
+
+#ifndef WIN32
+#include <Carbon.h>
+#include "Quicktime.h"
+#endif
+//Jordan included glut.h
+//#include <glut.h>
+
+#include "TGALoader.h"
+#ifdef WIN32
+#include "WinInput.h"
+#else
+#include "Macinput.h"
+#endif
+#include "Terrain.h"
+#include "Skybox.h"
+#include "Skeleton.h"
+#include "Models.h"   
+#include "Lights.h"
+#include "Person.h"
+#include "Constants.h"
+#include "fmod.h"
+#include "Sprites.h"
+//#include <agl.h>
+#include "Text.h"
+#include "Objects.h"
+//#include <DrawSprocket.h>
+#include "Weapons.h"
+#include "binio.h"
+#include <fstream>
+#include "gl.h"
+
+extern GLuint rabbittexture;
+
+
+class Game             
+{
+public:
+
+       typedef std::map<std::string, GLuint> TextureList;
+       typedef std::map<GLuint, std::string> GLTextureList;
+       typedef TextureList::iterator TexIter;
+       static TextureList textures;
+
+       GLuint terraintexture;
+       GLuint terraintexture2;
+       GLuint terraintexture3;
+       GLuint screentexture;
+       GLuint screentexture2;
+       GLuint logotexture;
+       GLuint loadscreentexture;
+       GLuint Maparrowtexture;
+       GLuint Mapboxtexture;
+       GLuint Mapcircletexture;
+       GLuint cursortexture;
+       GLuint Mainmenuitems[10];
+
+       int nummenuitems;
+       int startx[100];
+       int starty[100];
+       int endx[100];
+       int endy[100];
+       float selectedlong[100];
+       float offsetx[100];
+       float offsety[100];
+       float movex[100];
+       float movey[100];
+       float transition;
+       int anim;
+       int selected;
+       int loaddistrib;
+       int keyselect;
+       int indemo;
+       int registered;
+
+       bool won;
+
+       bool entername;
+
+       char menustring[100][256];
+       char registrationname[256];
+       float registrationnumber;
+
+       int newdetail;
+       int newscreenwidth;
+       int newscreenheight;
+
+       bool gameon;
+       float deltah,deltav;
+       int mousecoordh,mousecoordv;
+       int oldmousecoordh,oldmousecoordv;
+       float rotation,rotation2;
+       SkyBox skybox;
+       bool cameramode;
+       bool cameratogglekeydown;
+       bool chattogglekeydown;
+       int olddrawmode;
+       int drawmode;
+       bool drawmodetogglekeydown;
+       bool explodetogglekeydown;
+       bool detailtogglekeydown;
+       bool firstload;
+       bool oldbutton;
+
+       float leveltime;
+       float loadtime;
+
+       Model hawk;
+       XYZ hawkcoords;
+       XYZ realhawkcoords;
+       GLuint hawktexture;
+       float hawkrotation;
+       float hawkcalldelay;
+
+       Model eye;
+       Model iris;
+       Model cornea;
+
+       bool stealthloading;
+
+       int campaignnumlevels;
+       char campaignmapname[50][256];
+       char campaigndescription[50][256];
+       int campaignchoosenext[50];
+       int campaignnumnext[50];
+       int campaignnextlevel[50][10];
+       int campaignchoicesmade;
+       int campaignchoices[5000];
+       int campaignlocationx[50];
+       int campaignlocationy[50];
+       int campaignchoicenum;
+       int campaignchoicewhich[10];
+       int whichchoice;
+
+       int numlevelspassed;
+       int levelorder[5000];
+       int levelvisible[50];
+       int levelhighlight[50];
+
+       bool minimap;
+
+       int musictype,oldmusictype,oldoldmusictype;
+       bool realthreat;
+
+       Model rabbit;
+       XYZ rabbitcoords;
+
+       XYZ mapcenter;
+       float mapradius;
+
+       Text text;
+       float fps;
+
+       XYZ cameraloc;
+       float cameradist;
+
+       bool envtogglekeydown;
+       bool slomotogglekeydown;
+       bool texturesizetogglekeydown;
+       bool freezetogglekeydown;
+       int drawtoggle;
+
+       bool editorenabled;
+       int editortype;
+       float editorsize;
+       float editorrotation;
+       float editorrotation2;
+
+       float brightness;
+
+       int quit;
+       int tryquit;
+
+       XYZ pathpoint[30];
+       int numpathpoints;
+       int numpathpointconnect[30];
+       int pathpointconnect[30][30];
+       int pathpointselected;
+
+       int endgame;
+       bool scoreadded;
+       int numchallengelevels;
+
+       bool console;
+       int archiveselected;
+       char consoletext[15][256];
+       int consolechars[15];
+       bool chatting;
+       char displaytext[15][256];
+       int displaychars[15];
+       float displaytime[15];
+       float displayblinkdelay;
+       bool displayblink;
+       int displayselected;
+       bool consolekeydown;
+       bool consoletogglekeydown;
+       float consoleblinkdelay;
+       bool consoleblink;
+       int consoleselected;
+       int togglekey[140];
+       float togglekeydelay[140];
+       bool registernow;
+       bool autocam;
+
+       unsigned short crouchkey,jumpkey,forwardkey,chatkey,backkey,leftkey,rightkey,drawkey,throwkey,attackkey;
+       bool oldattackkey;
+
+       long long MD5_string (char *string);
+       static void LoadTexture(char *fileName, GLuint *textureid,int mipmap, bool hasalpha);
+       static void LoadTextureSave(char *fileName, GLuint *textureid,int mipmap,GLubyte *array, int *skinsize);
+       void LoadSave(char *fileName, GLuint *textureid,bool mipmap,GLubyte *array, int *skinsize);
+       bool AddClothes(char *fileName, GLuint *textureid,bool mipmap,GLubyte *array, int *skinsize);
+       void InitGame();
+       void LoadStuff();
+       void LoadingScreen();
+       void FadeLoadingScreen(float howmuch);
+       void Dispose();
+       int DrawGLScene(GLvoid);
+       void Tick();
+       void TickOnce();
+       void TickOnceAfter();
+       void SetUpLighting();
+       void Loadlevel(int which);
+       void Loadlevel(char *name);
+       void LoadSounds();
+       void Setenvironment(int which);
+       GLvoid ReSizeGLScene(float fov, float near);
+       int findPathDist(int start,int end);
+       int checkcollide(XYZ startpoint, XYZ endpoint);
+       int checkcollide(XYZ startpoint, XYZ endpoint, int what);
+       int loading;
+       float talkdelay;
+
+       int numboundaries;
+       XYZ boundary[360];
+
+       int whichlevel;
+       int oldenvironment;
+       int targetlevel;
+       float changedelay;
+
+       float musicvolume[4];
+       float oldmusicvolume[4];
+       int musicselected;
+       int change;
+       Game();
+       ~Game() {               
+               for(int i=0;i<10;i++){
+                       if(Mainmenuitems[i])glDeleteTextures( 1, (const unsigned long *)&Mainmenuitems[i] );
+               }
+               glDeleteTextures( 1, (const unsigned long *)&cursortexture );
+               glDeleteTextures( 1, (const unsigned long *)&Maparrowtexture );
+               glDeleteTextures( 1, (const unsigned long *)&Mapboxtexture );
+               glDeleteTextures( 1, (const unsigned long *)&Mapcircletexture );
+               glDeleteTextures( 1, (const unsigned long *)&terraintexture );
+               glDeleteTextures( 1, (const unsigned long *)&terraintexture2 );
+               if(screentexture>0)glDeleteTextures( 1, (const unsigned long *)&screentexture );
+               if(screentexture2>0)glDeleteTextures( 1, (const unsigned long *)&screentexture2 );
+               glDeleteTextures( 1, (const unsigned long *)&hawktexture );
+               glDeleteTextures( 1, (const unsigned long *)&logotexture );
+               glDeleteTextures( 1, (const unsigned long *)&loadscreentexture );
+
+               Dispose();
+       }
+
+};
+
+#endif
\ No newline at end of file
diff --git a/Source/GameDraw.cpp b/Source/GameDraw.cpp
new file mode 100644 (file)
index 0000000..e3cd41b
--- /dev/null
@@ -0,0 +1,3970 @@
+#include "Game.h"      
+
+using namespace std;
+
+extern XYZ viewer;
+extern int environment;
+extern float texscale;
+extern Light light;
+extern Terrain terrain;
+extern Sprites sprites;
+extern float multiplier;
+extern float sps;
+extern float viewdistance;
+extern float fadestart;
+extern float screenwidth,screenheight;
+#ifdef WIN32
+extern HDC hDC;
+#else
+extern AGLContext gaglContext;
+#endif
+extern int kTextureSize;
+extern FRUSTUM frustum;
+extern Light light;
+extern Objects objects;
+extern int detail;
+extern float usermousesensitivity;
+extern bool osx;
+extern float camerashake;
+extern Weapons weapons;
+extern Person player[maxplayers];
+extern int slomo;
+extern float slomodelay;
+extern bool ismotionblur;
+extern float woozy;
+extern float blackout;
+extern bool damageeffects;
+extern float volume;
+extern int numplayers;
+extern bool texttoggle;
+extern float blurness;
+extern float targetblurness;
+extern float playerdist;
+extern bool cellophane;
+extern bool freeze;
+extern float flashamount,flashr,flashg,flashb;
+extern int flashdelay;
+extern int netstate;
+extern float motionbluramount;
+extern bool isclient;
+extern bool alwaysblur;
+extern int test;
+extern bool tilt2weird;
+extern bool tiltweird;
+extern bool midweird;
+extern bool proportionweird;
+extern bool vertexweird[6];
+extern bool velocityblur;
+extern bool buttons[3];
+extern bool debugmode;
+extern int mainmenu;
+extern int oldmainmenu;
+extern int bloodtoggle;
+extern int difficulty;
+extern bool decals;
+// MODIFIED GWC
+//extern int texdetail;
+extern float texdetail;
+extern bool musictoggle;
+extern int bonus;
+extern float bonusvalue;
+extern float bonustotal;
+extern float bonustime;
+extern int oldbonus;
+extern float startbonustotal;
+extern float bonusnum[100];
+extern int tutoriallevel;
+extern float smoketex;
+extern float tutorialstagetime;
+extern float tutorialmaxtime;
+extern int tutorialstage;
+extern bool againbonus;
+extern float damagedealt;
+extern float damagetaken;
+extern bool invertmouse;
+
+extern int numhotspots;
+extern int winhotspot;
+extern int killhotspot;
+extern XYZ hotspot[40];
+extern int hotspottype[40];
+extern float hotspotsize[40];
+extern char hotspottext[40][256];
+extern int currenthotspot;
+
+extern int numaccounts;
+extern int accountactive;
+extern int accountdifficulty[10];
+extern int accountprogress[10];
+extern float accountpoints[10];
+extern float accounthighscore[10][50];
+extern float accountfasttime[10][50];
+extern bool accountunlocked[10][60];
+extern char accountname[10][256];
+
+extern int numfalls;
+extern int numflipfail;
+extern int numseen;
+extern int numstaffattack;
+extern int numswordattack;
+extern int numknifeattack;
+extern int numunarmedattack;
+extern int numescaped;
+extern int numflipped;
+extern int numwallflipped;
+extern int numthrowkill;
+extern int numafterkill;
+extern int numreversals;
+extern int numattacks;
+extern int maxalarmed;
+extern int numresponded;
+
+extern bool campaign;
+extern bool winfreeze;
+
+extern float menupulse;
+
+extern bool gamestart;
+
+extern int numdialogues;
+extern int numdialogueboxes[max_dialogues];
+extern int dialoguetype[max_dialogues];
+extern int dialogueboxlocation[max_dialogues][max_dialoguelength];
+extern float dialogueboxcolor[max_dialogues][max_dialoguelength][3];
+extern int dialogueboxsound[max_dialogues][max_dialoguelength];
+extern char dialoguetext[max_dialogues][max_dialoguelength][128];
+extern char dialoguename[max_dialogues][max_dialoguelength][64];
+extern XYZ dialoguecamera[max_dialogues][max_dialoguelength];
+extern XYZ participantlocation[max_dialogues][10];
+extern int participantfocus[max_dialogues][max_dialoguelength];
+extern int participantaction[max_dialogues][max_dialoguelength];
+extern float participantrotation[max_dialogues][10];
+extern XYZ participantfacing[max_dialogues][max_dialoguelength][10];
+extern float dialoguecamerarotation[max_dialogues][max_dialoguelength];
+extern float dialoguecamerarotation2[max_dialogues][max_dialoguelength];
+extern int indialogue;
+extern int whichdialogue;
+extern int directing;
+extern float dialoguetime;
+extern int dialoguegonethrough[20];
+
+extern int accountcampaignchoicesmade[10];
+extern int accountcampaignchoices[10][5000];
+
+extern float accountcampaignhighscore[10];
+extern float accountcampaignfasttime[10];
+extern float accountcampaignscore[10];
+extern float accountcampaigntime[10];
+
+extern bool gamestarted;
+
+extern FSOUND_SAMPLE   *samp[100];
+extern int channels[100];
+extern "C"     void PlaySoundEx(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused);
+
+/*********************> DrawGLScene() <*****/
+long long Game::MD5_string (char *string){
+       char temp[256]="";
+       char temp2[256]="";
+       long long num=90814;
+
+       sprintf (temp, "%s",string);
+
+       int i=0;
+       while (i<256&&temp[i]!='\0'){
+               if(temp[i]%3==0)num+=temp[i]*124;
+               else if(temp[i]%3==1)num-=temp[i]*temp[i];
+               else num*=temp[i];
+               i++;
+       }
+
+       num=abs(num);
+       if(num==0)num+=1452;
+
+       while(num<5000000000000000){
+               num*=1.85421521;
+       }
+
+       while(num>9900000000000000){
+               num/=1.235421521;
+       }
+
+       return num;
+
+       //return 1111111111111111;
+}
+
+int Game::DrawGLScene(GLvoid)                                                                  
+{      
+       static float texcoordwidth,texcoordheight;
+       static float texviewwidth, texviewheight;
+       static int i,j,k,l;
+       static GLubyte color;
+       static float newbrightness;
+       static float changespeed;
+       static XYZ checkpoint;
+       static float tempmult;
+       float tutorialopac;
+       static char string[256]="";
+       static char string2[256]="";
+       static char string3[256]="";
+
+       static float lastcheck;
+
+       lastcheck+=multiplier;
+
+       glColorMask( 1.0, 1.0, 1.0, 1.0 );
+       if(!registered)debugmode=0;
+
+
+       if(freeze||winfreeze||(mainmenu&&gameon)||(!gameon&&gamestarted)){
+               tempmult=multiplier;
+               multiplier=0;
+       }
+
+       if(!mainmenu){
+               if(editorenabled){
+                       numboundaries=mapradius*2;
+                       if(numboundaries>360)numboundaries=360;
+                       for(i=0;i<numboundaries;i++){
+                               boundary[i]=0;
+                               boundary[i].z=1;
+                               boundary[i]=mapcenter+DoRotation(boundary[i]*mapradius,0,i*(360/((float)(numboundaries))),0);
+                       }
+               }
+
+               SetUpLighting();
+
+               static int changed;
+               changed=0;
+
+               olddrawmode=drawmode;
+               if(ismotionblur&&!loading){
+                       if((findLengthfast(&player[0].velocity)>200)&&velocityblur&&!cameramode){
+                               drawmode=motionblurmode;
+                               motionbluramount=200/(findLengthfast(&player[0].velocity));
+                               changed=1;
+                       }
+                       if(player[0].damage-player[0].superpermanentdamage>(player[0].damagetolerance-player[0].superpermanentdamage)*1/2&&damageeffects&&!cameramode){
+                               drawmode=doublevisionmode;
+                               changed=1;
+                       }
+               }
+
+               if(slomo&&!loading){
+                       if(ismotionblur)
+                               drawmode=motionblurmode;
+                       motionbluramount=.2;
+                       slomodelay-=multiplier;
+                       if(slomodelay<0)slomo=0;
+                       camerashake=0;
+                       changed=1;
+               }
+               if((!changed&&!slomo)||loading){
+                       drawmode=normalmode;
+                       if(ismotionblur&&(/*fps>100||*/alwaysblur)){
+                               if(olddrawmode!=realmotionblurmode)change=1;
+                               else change=0;
+                               drawmode=realmotionblurmode;
+                       }
+                       else if(olddrawmode==realmotionblurmode)change=2;
+                       else change=0;
+               }
+
+               if(freeze||winfreeze||(mainmenu&&gameon)||(!gameon&&gamestarted))drawmode=normalmode;
+               if((freeze||winfreeze)&&ismotionblur&&!mainmenu)drawmode=radialzoommode;
+
+               if(winfreeze||mainmenu)drawmode=normalmode;
+
+               //drawmode=glowmode;
+               if(drawmode==glowmode){
+                       RGBColor color2;
+                       color2.red=0;
+                       color2.green=0;
+                       color2.blue=0;
+#ifndef WIN32
+                       DSpContext_FadeGamma(NULL,200,&color2);
+#endif
+               }
+
+               if(drawtoggle!=2)drawtoggle=1-drawtoggle;
+
+               if(!texcoordwidth){
+
+                       texviewwidth=kTextureSize;
+                       if(texviewwidth>screenwidth)texviewwidth=screenwidth;
+                       texviewheight=kTextureSize;
+                       if(texviewheight>screenheight)texviewheight=screenheight;
+
+                       texcoordwidth=screenwidth/kTextureSize;
+                       texcoordheight=screenheight/kTextureSize;
+                       if(texcoordwidth>1)texcoordwidth=1;
+                       if(texcoordheight>1)texcoordheight=1;
+               }
+
+               glDrawBuffer(GL_BACK);
+               glReadBuffer(GL_BACK);
+
+               /*if(environment==desertenvironment)glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, (float)(abs(Random()%100))/50 );
+               else glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0);
+               */
+               if(abs(blurness-targetblurness)<multiplier*10||abs(blurness-targetblurness)>2){
+                       blurness=targetblurness;
+                       targetblurness=(float)(abs(Random()%100))/40;
+               }
+               if(blurness<targetblurness)blurness+=multiplier*5;
+               if(blurness>targetblurness)blurness-=multiplier*5;
+
+               //glFinish();
+               static XYZ terrainlight;
+               static float distance;
+               //if(drawmode==normalmode)ReSizeGLScene(90,.1);
+               if(drawmode==normalmode)ReSizeGLScene(90,.1f);
+               if(drawmode!=normalmode)glViewport(0,0,texviewwidth,texviewheight);     
+               glDepthFunc(GL_LEQUAL);
+               glDepthMask(1);
+               glAlphaFunc(GL_GREATER, 0.0001f);
+               glEnable(GL_ALPHA_TEST);
+               glClearColor(0.25f, 0.25f, 0.25f, 1.0f);
+               glClear(GL_DEPTH_BUFFER_BIT);
+
+               glMatrixMode (GL_MODELVIEW);
+               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+               glLoadIdentity ();
+               if(!cameramode&&!freeze&&!winfreeze){
+                       glRotatef(float(Random()%100)/10*camerashake/*+(woozy*woozy)/10*/,0,0,1);
+                       glRotatef(rotation2+sin(woozy/2)*(player[0].damage/player[0].damagetolerance)*5,1,0,0);
+                       glRotatef(rotation+sin(woozy)*(player[0].damage/player[0].damagetolerance)*5,0,1,0);
+               }
+               if(cameramode||freeze||winfreeze){
+                       //glRotatef(float(Random()%100)/10*camerashake/*+(woozy*woozy)/10*/,0,0,1);
+                       glRotatef(rotation2,1,0,0);
+                       glRotatef(rotation,0,1,0);
+               }
+
+               if(environment==desertenvironment){
+                       glRotatef((float)(abs(Random()%100))/3000-1,1,0,0);
+                       glRotatef((float)(abs(Random()%100))/3000-1,0,1,0);
+                       //glRotatef(blurness/40-1,1,0,0);
+                       //glRotatef(blurness/40-1,0,1,0);
+               }
+               SetUpLight(&light,0);
+               glPushMatrix();
+               if(environment==desertenvironment&&detail==2)glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, blurness+.4 );
+               if(environment==desertenvironment){
+                       glRotatef((float)(abs(Random()%100))/1000,1,0,0);
+                       glRotatef((float)(abs(Random()%100))/1000,0,1,0);
+               }       
+               skybox.draw();
+               glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0);
+               glPopMatrix();
+               glTranslatef(-viewer.x,-viewer.y,-viewer.z);
+               frustum.GetFrustum();
+
+               //Make Shadow
+               static XYZ point;
+               static float size,opacity,rotation;
+               rotation=0;
+               for(k=0;k<numplayers;k++){
+                       if(!player[k].skeleton.free&&player[k].playerdetail&&player[k].howactive<typesleeping)
+                               if(frustum.SphereInFrustum(player[k].coords.x,player[k].coords.y+player[k].scale*3,player[k].coords.z,player[k].scale*7)&&player[k].occluded<25)
+                                       for(i=0;i<player[k].skeleton.num_joints;i++){
+                                               if(player[k].skeleton.joints[i].label==leftknee||player[k].skeleton.joints[i].label==rightknee||player[k].skeleton.joints[i].label==groin){
+                                                       point=DoRotation(player[k].skeleton.joints[i].position,0,player[k].rotation,0)*player[k].scale+player[k].coords;
+                                                       size=.4f;
+                                                       opacity=.4-player[k].skeleton.joints[i].position.y*player[k].scale/5-(player[k].coords.y-terrain.getHeight(player[k].coords.x,player[k].coords.z))/10;
+                                                       if(k!=0&&tutoriallevel==1){
+                                                               opacity=.2+.2*sin(smoketex*6+i)-player[k].skeleton.joints[i].position.y*player[k].scale/5-(player[k].coords.y-terrain.getHeight(player[k].coords.x,player[k].coords.z))/10;
+                                                       }
+                                                       terrain.MakeDecal(shadowdecal,point,size,opacity,rotation);
+                                                       if(terrain.patchobjectnum[player[k].whichpatchx][player[k].whichpatchz])
+                                                               for(l=0;l<terrain.patchobjectnum[player[k].whichpatchx][player[k].whichpatchz];l++){
+                                                                       j=terrain.patchobjects[player[k].whichpatchx][player[k].whichpatchz][l];
+                                                                       if(objects.position[j].y<player[k].coords.y||objects.type[j]==tunneltype||objects.type[j]==weirdtype){
+                                                                               point=DoRotation(DoRotation(player[k].skeleton.joints[i].position,0,player[k].rotation,0)*player[k].scale+player[k].coords-objects.position[j],0,-objects.rotation[j],0);
+                                                                               size=.4f;
+                                                                               opacity=.4f;
+                                                                               if(k!=0&&tutoriallevel==1){
+                                                                                       opacity=.2+.2*sin(smoketex*6+i);
+                                                                               }
+                                                                               objects.model[j].MakeDecal(shadowdecal,&point,&size,&opacity,&rotation);
+                                                                       }
+                                                               }
+                                               }
+                                       }
+                                       if((player[k].skeleton.free||player[k].howactive>=typesleeping)&&player[k].playerdetail)
+                                               if(frustum.SphereInFrustum(player[k].coords.x,player[k].coords.y,player[k].coords.z,player[k].scale*5)&&player[k].occluded<25)
+                                                       for(i=0;i<player[k].skeleton.num_joints;i++){
+                                                               if(player[k].skeleton.joints[i].label==leftknee||player[k].skeleton.joints[i].label==rightknee||player[k].skeleton.joints[i].label==groin||player[k].skeleton.joints[i].label==leftelbow||player[k].skeleton.joints[i].label==rightelbow||player[k].skeleton.joints[i].label==neck){
+                                                                       if(player[k].skeleton.free)point=player[k].skeleton.joints[i].position*player[k].scale+player[k].coords;
+                                                                       else point=DoRotation(player[k].skeleton.joints[i].position,0,player[k].rotation,0)*player[k].scale+player[k].coords;
+                                                                       size=.4f;
+                                                                       opacity=.4-player[k].skeleton.joints[i].position.y*player[k].scale/5-(player[k].coords.y-terrain.getHeight(player[k].coords.x,player[k].coords.z))/5;
+                                                                       if(k!=0&&tutoriallevel==1){
+                                                                               opacity=.2+.2*sin(smoketex*6+i)-player[k].skeleton.joints[i].position.y*player[k].scale/5-(player[k].coords.y-terrain.getHeight(player[k].coords.x,player[k].coords.z))/10;
+                                                                       }
+                                                                       terrain.MakeDecal(shadowdecal,point,size,opacity*.7,rotation);
+                                                                       if(terrain.patchobjectnum[player[k].whichpatchx][player[k].whichpatchz])
+                                                                               for(l=0;l<terrain.patchobjectnum[player[k].whichpatchx][player[k].whichpatchz];l++){
+                                                                                       j=terrain.patchobjects[player[k].whichpatchx][player[k].whichpatchz][l];
+                                                                                       if(objects.position[j].y<player[k].coords.y||objects.type[j]==tunneltype||objects.type[j]==weirdtype){
+                                                                                               if(player[k].skeleton.free)point=DoRotation(player[k].skeleton.joints[i].position*player[k].scale+player[k].coords-objects.position[j],0,-objects.rotation[j],0);
+                                                                                               else point=DoRotation(DoRotation(player[k].skeleton.joints[i].position,0,player[k].rotation,0)*player[k].scale+player[k].coords-objects.position[j],0,-objects.rotation[j],0);
+                                                                                               size=.4f;
+                                                                                               opacity=.4f;
+                                                                                               if(k!=0&&tutoriallevel==1){
+                                                                                                       opacity=.2+.2*sin(smoketex*6+i);
+                                                                                               }
+                                                                                               objects.model[j].MakeDecal(shadowdecal,&point,&size,&opacity,&rotation);
+                                                                                       }
+                                                                               }
+                                                               }
+                                                       }
+
+                                                       if(!player[k].playerdetail)
+                                                               if(frustum.SphereInFrustum(player[k].coords.x,player[k].coords.y,player[k].coords.z,player[k].scale*5))
+                                                               {
+                                                                       point=player[k].coords;
+                                                                       size=.7;
+                                                                       opacity=.4-(player[k].coords.y-terrain.getHeight(player[k].coords.x,player[k].coords.z))/5;
+                                                                       terrain.MakeDecal(shadowdecal,point,size,opacity*.7,rotation);
+                                                                       if(terrain.patchobjectnum[player[k].whichpatchx][player[k].whichpatchz])
+                                                                               for(l=0;l<terrain.patchobjectnum[player[k].whichpatchx][player[k].whichpatchz];l++){
+                                                                                       j=terrain.patchobjects[player[k].whichpatchx][player[k].whichpatchz][l];
+                                                                                       point=DoRotation(player[k].coords-objects.position[j],0,-objects.rotation[j],0);
+                                                                                       size=.7;
+                                                                                       opacity=.4f;
+                                                                                       objects.model[j].MakeDecal(shadowdecal,&point,&size,&opacity,&rotation);
+                                                                               }
+                                                               }
+               }
+
+               //Terrain
+               glEnable(GL_TEXTURE_2D);
+               glDepthMask(1);
+               glEnable(GL_DEPTH_TEST);
+               glEnable(GL_CULL_FACE);
+               glDisable(GL_BLEND);
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
+               glBindTexture( GL_TEXTURE_2D, terraintexture);
+               terrain.draw(0);
+               glBindTexture( GL_TEXTURE_2D, terraintexture2);
+               terrain.draw(1);
+               //glBindTexture( GL_TEXTURE_2D, terraintexture3);
+               //glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+               //terrain.draw(2);
+
+               terrain.drawdecals();
+
+               //Model
+               glEnable(GL_CULL_FACE);
+               glEnable(GL_LIGHTING);
+               glDisable(GL_BLEND);
+               glEnable(GL_TEXTURE_2D);
+               glDepthMask(1);
+
+               glEnable(GL_COLOR_MATERIAL);
+
+               test=2;
+               tilt2weird=0;
+               tiltweird=0;
+               midweird=0;
+               proportionweird=0;
+               vertexweird[0]=0;
+               vertexweird[1]=0;
+               vertexweird[2]=0;
+               vertexweird[3]=0;
+               vertexweird[4]=0;
+               vertexweird[5]=0;
+
+               if(!cellophane){
+                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       glEnable(GL_CULL_FACE);
+                       glCullFace(GL_FRONT);
+                       glDepthMask(1);
+                       for(k=0;k<numplayers;k++){
+                               if(k==0||tutoriallevel!=1){
+                                       glEnable(GL_BLEND);
+                                       glEnable(GL_LIGHTING);
+                                       terrainlight=terrain.getLighting(player[k].coords.x,player[k].coords.z);
+                                       distance=findDistancefast(&viewer,&player[k].coords);
+                                       distance=(viewdistance*viewdistance-(distance-(viewdistance*viewdistance*fadestart))*(1/(1-fadestart)))/viewdistance/viewdistance;
+                                       glColor4f(terrainlight.x,terrainlight.y,terrainlight.z,distance);
+                                       if(distance>=1)glDisable(GL_BLEND);
+                                       if(distance>=.5){
+                                               checkpoint=DoRotation(player[k].skeleton.joints[abs(Random()%player[k].skeleton.num_joints)].position,0,player[k].rotation,0)*player[k].scale+player[k].coords;
+                                               checkpoint.y+=1;
+                                               if(!player[k].occluded==0)i=checkcollide(viewer,checkpoint,player[k].lastoccluded);
+                                               if(i==-1||player[k].occluded==0)i=checkcollide(viewer,checkpoint);
+                                               if(i!=-1){
+                                                       player[k].occluded+=1;
+                                                       player[k].lastoccluded=i;
+                                               }
+                                               else player[k].occluded=0;
+                                               if(player[k].occluded<25)player[k].DrawSkeleton();
+                                       }
+                               }
+                       }
+               }
+
+               if(!cameramode&&musictype==stream_music2)playerdist=findDistancefastflat(&player[0].coords,&viewer);
+               else playerdist=-100;
+               glPushMatrix();
+               glCullFace(GL_BACK);
+               glEnable(GL_TEXTURE_2D);
+               objects.Draw();
+               glPopMatrix();
+
+               glPushMatrix();
+               if(frustum.SphereInFrustum(realhawkcoords.x+hawk.boundingspherecenter.x,realhawkcoords.y+hawk.boundingspherecenter.y,realhawkcoords.z+hawk.boundingspherecenter.z,2)){   
+                       glAlphaFunc(GL_GREATER, 0.0001f);
+                       glDepthMask(1);
+                       glDisable(GL_CULL_FACE);
+                       glDisable(GL_LIGHTING);
+                       glEnable(GL_BLEND);
+                       glTranslatef(hawkcoords.x,hawkcoords.y,hawkcoords.z);
+                       glRotatef(hawkrotation,0,1,0);
+                       glTranslatef(25,0,0);
+                       distance=findDistancefast(&viewer,&realhawkcoords)*1.2;
+                       glColor4f(light.color[0],light.color[1],light.color[2],(viewdistance*viewdistance-(distance-(viewdistance*viewdistance*fadestart))*(1/(1-fadestart)))/viewdistance/viewdistance);
+                       if((viewdistance*viewdistance-(distance-(viewdistance*viewdistance*fadestart))*(1/(1-fadestart)))/viewdistance/viewdistance>1)glColor4f(light.color[0],light.color[1],light.color[2],1);
+                       if((viewdistance*viewdistance-(distance-(viewdistance*viewdistance*fadestart))*(1/(1-fadestart)))/viewdistance/viewdistance>0)
+                               hawk.drawdifftex(hawktexture);
+               }
+               glPopMatrix();
+
+               //if(cellophane){
+               /*glEnable(GL_CULL_FACE);
+               glCullFace(GL_FRONT);
+               glDepthMask(1);
+               for(k=0;k<numplayers;k++){
+               glEnable(GL_BLEND);
+               glEnable(GL_LIGHTING);
+               terrainlight=terrain.getLighting(player[k].coords.x,player[k].coords.z);
+               distance=findDistancefast(&viewer,&player[k].coords);
+               distance=(viewdistance*viewdistance-(distance-(viewdistance*viewdistance*fadestart))*(1/(1-fadestart)))/viewdistance/viewdistance;
+               glColor4f(terrainlight.x,terrainlight.y,terrainlight.z,distance);
+               if(distance>=1)glDisable(GL_BLEND);
+               if(distance>0){
+               checkpoint=DoRotation(player[k].skeleton.joints[abs(Random()%player[k].skeleton.num_joints)].position,0,player[k].rotation,0)*player[k].scale+player[k].coords;
+               checkpoint.y+=1;
+               if(checkcollide(viewer,checkpoint)){
+               player[k].occluded+=1;
+               }
+               else player[k].occluded=0;
+               if(player[k].occluded<25)player[k].DrawSkeleton();
+               }
+               }*/
+
+               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+               glEnable(GL_CULL_FACE);
+               glCullFace(GL_FRONT);
+               glDepthMask(1);
+               for(k=0;k<numplayers;k++){
+                       if(!(k==0||tutoriallevel!=1)){
+                               glEnable(GL_BLEND);
+                               glEnable(GL_LIGHTING);
+                               terrainlight=terrain.getLighting(player[k].coords.x,player[k].coords.z);
+                               distance=findDistancefast(&viewer,&player[k].coords);
+                               distance=(viewdistance*viewdistance-(distance-(viewdistance*viewdistance*fadestart))*(1/(1-fadestart)))/viewdistance/viewdistance;
+                               glColor4f(terrainlight.x,terrainlight.y,terrainlight.z,distance);
+                               if(distance>=1)glDisable(GL_BLEND);
+                               if(distance>=.5){
+                                       checkpoint=DoRotation(player[k].skeleton.joints[abs(Random()%player[k].skeleton.num_joints)].position,0,player[k].rotation,0)*player[k].scale+player[k].coords;
+                                       checkpoint.y+=1;
+                                       if(!player[k].occluded==0)i=checkcollide(viewer,checkpoint,player[k].lastoccluded);
+                                       if(i==-1||player[k].occluded==0)i=checkcollide(viewer,checkpoint);
+                                       if(i!=-1){
+                                               player[k].occluded+=1;
+                                               player[k].lastoccluded=i;
+                                       }
+                                       else player[k].occluded=0;
+                                       if(player[k].occluded<25)player[k].DrawSkeleton();
+                               }
+                       }
+               }
+               //}
+
+               glPushMatrix();
+               glEnable(GL_TEXTURE_2D);
+               weapons.Draw();
+               glPopMatrix();
+               glCullFace(GL_BACK);
+
+               glDisable(GL_COLOR_MATERIAL);
+
+               glDisable(GL_LIGHTING);
+               glDisable(GL_TEXTURE_2D);
+
+               glDepthMask(0);
+
+               sprites.Draw();
+
+               if(editorenabled){
+                       glEnable(GL_BLEND);
+                       glDisable(GL_LIGHTING);
+                       glDisable(GL_TEXTURE_2D);
+                       glDisable(GL_COLOR_MATERIAL);
+                       glColor4f(1,1,0,1);
+
+                       for(k=0;k<numplayers;k++){
+                               if(player[k].numwaypoints>1){
+                                       glBegin(GL_LINE_LOOP);
+                                       for(i=0;i<player[k].numwaypoints;i++){
+                                               glVertex3f(player[k].waypoints[i].x,player[k].waypoints[i].y+.5,player[k].waypoints[i].z);
+                                       }
+                                       glEnd();
+                               }
+                       }
+
+
+                       if(numpathpoints>1){
+                               glColor4f(0,1,0,1);
+                               for(k=0;k<numpathpoints;k++){
+                                       if(numpathpointconnect[k]){
+                                               for(i=0;i<numpathpointconnect[k];i++){
+                                                       glBegin(GL_LINE_LOOP);
+                                                       glVertex3f(pathpoint[k].x,pathpoint[k].y+.5,pathpoint[k].z);
+                                                       glVertex3f(pathpoint[pathpointconnect[k][i]].x,pathpoint[pathpointconnect[k][i]].y+.5,pathpoint[pathpointconnect[k][i]].z);                                     
+                                                       glEnd();
+                                               }
+                                       }
+                               }
+                               glColor4f(1,1,1,1);
+                               glPointSize(4);
+                               glBegin(GL_POINTS);
+                               glVertex3f(pathpoint[pathpointselected].x,pathpoint[pathpointselected].y+.5,pathpoint[pathpointselected].z);
+                               glEnd();
+                       }
+               }
+
+               //Text
+
+               glEnable(GL_TEXTURE_2D);
+               glColor4f(.5,.5,.5,1);
+               if(!console){
+                       sprintf (string, " ",(int)(fps));
+                       text.glPrint(10,30,string,0,.8,screenwidth,screenheight);
+
+                       if(!tutoriallevel)
+                               if(bonus>0&&bonustime<1&&!winfreeze&&indialogue==-1/*bonustime<4*/){
+                                       if(bonus==tracheotomy)sprintf (string, "Tracheotomy!");
+                                       else if(bonus==backstab)sprintf (string, "Backstabber!");
+                                       else if(bonus==spinecrusher)sprintf (string, "Spinecrusher!");
+                                       else if(bonus==ninja)sprintf (string, "Ninja Bonus!");
+                                       else if(bonus==style)sprintf (string, "Style Bonus!");
+                                       else if(bonus==cannon)sprintf (string, "Leg Cannon!");
+                                       else if(bonus==aimbonus)sprintf (string, "Nice Aim!");
+                                       else if(bonus==deepimpact)sprintf (string, "Heavy Impact!");
+                                       else if(bonus==touchofdeath)sprintf (string, "Touch of Death!");
+                                       else if(bonus==swordreversebonus)sprintf (string, "Sword Disarm!");
+                                       else if(bonus==staffreversebonus)sprintf (string, "Staff Disarm!");
+                                       else if(bonus==reverseko)sprintf (string, "Reversal KO!");
+                                       else if(bonus==solidhit)sprintf (string, "Solid Hit!");
+                                       else if(bonus==twoxcombo)sprintf (string, "2X Combo!");
+                                       else if(bonus==threexcombo)sprintf (string, "3X Combo!");
+                                       else if(bonus==fourxcombo)sprintf (string, "4X COMBO!");
+                                       else if(bonus==megacombo)sprintf (string, "MEGA COMBO!");
+                                       else if(bonus==Reversal)sprintf (string, "Reversal!");
+                                       else if(bonus==Stabbonus)sprintf (string, "Punctured!");
+                                       else if(bonus==Slicebonus)sprintf (string, "Sliced!");
+                                       else if(bonus==Bullseyebonus)sprintf (string, "Bullseye!");
+                                       else if(bonus==Slashbonus)sprintf (string, "Slashed!");
+                                       else if(bonus==Wolfbonus)sprintf (string, "WOLF SLAYER!");
+                                       else if(bonus==FinishedBonus)sprintf (string, "SLAIN!");
+                                       else if(bonus==TackleBonus)sprintf (string, "Tackle!");
+                                       else if(bonus==AboveBonus)sprintf (string, "Death from Above!");
+                                       else sprintf (string, "Excellent!");
+
+                                       glColor4f(0,0,0,1-bonustime);
+                                       text.glPrintOutline(1024/2-10*strlen(string)-4,768/16-4+768*4/5,string,1,2.5,1024,768);
+                                       glColor4f(1,0,0,1-bonustime);
+                                       text.glPrint(1024/2-10*strlen(string),768/16+768*4/5,string,1,2,1024,768);
+
+                                       sprintf (string, "%d",(int)bonusvalue);
+                                       glColor4f(0,0,0,1-bonustime);
+                                       text.glPrintOutline(1024/2-10*strlen(string)-4,768/16-4-20+768*4/5,string,1,2.5*.8,1024,768);
+                                       glColor4f(1,0,0,1-bonustime);
+                                       text.glPrint(1024/2-10*strlen(string),768/16-20+768*4/5,string,1,2*.8,1024,768);
+                                       glColor4f(.5,.5,.5,1);
+                               }
+
+                               if(tutoriallevel==1){
+                                       tutorialopac=tutorialmaxtime-tutorialstagetime;
+                                       if(tutorialopac>1)tutorialopac=1;
+                                       if(tutorialopac<0)tutorialopac=0;
+
+                                       sprintf (string, " ");
+                                       sprintf (string2, " ");
+                                       sprintf (string3, " ");
+                                       if(tutorialstage==0){
+                                               sprintf (string, " ");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==1){
+                                               sprintf (string, "Welcome to the Lugaru training level!");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==2){
+                                               sprintf (string, "BASIC MOVEMENT:");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==3){
+                                               sprintf (string, "You can move the mouse to rotate the camera.");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==4){
+                                               sprintf (string, "Try using the %s, %s, %s and %s keys to move around.",KeyToChar(forwardkey),KeyToChar(leftkey),KeyToChar(backkey),KeyToChar(rightkey));
+                                               sprintf (string2, "All movement is relative to the camera.");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==5){
+                                               sprintf (string, "Please press %s to jump.",KeyToChar(jumpkey));
+                                               sprintf (string2, "You can hold it longer to jump higher.");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==6){
+                                               sprintf (string, "You can press %s to crouch.",KeyToChar(crouchkey));
+                                               sprintf (string2, "You can jump higher from a crouching position.");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==7){
+                                               sprintf (string, "While running, you can press %s to roll.",KeyToChar(crouchkey));
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==8){
+                                               sprintf (string, "While crouching, you can sneak around silently");
+                                               sprintf (string2, "using the movement keys.");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==9){
+                                               sprintf (string, "Release the crouch key while sneaking and hold the movement keys");
+                                               sprintf (string2, "to run animal-style.");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==10){
+                                               sprintf (string, "ADVANCED MOVEMENT:");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==11){
+                                               sprintf (string, "When you jump at a wall, you can hold %s again",KeyToChar(jumpkey));
+                                               sprintf (string2, "during impact to perform a walljump.");
+                                               sprintf (string3, "Be sure to use the movement keys to press against the wall");
+                                       }
+                                       if(tutorialstage==12){
+                                               sprintf (string, "While in the air, you can press crouch to flip.",KeyToChar(jumpkey));
+                                               sprintf (string2, "Walljumps and flips confuse enemies and give you more control.");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==13){
+                                               sprintf (string, "BASIC COMBAT:");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==14){
+                                               sprintf (string, "There is now an imaginary enemy");
+                                               sprintf (string2, "in the middle of the training area.");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==15){
+                                               if(attackkey==MAC_MOUSEBUTTON1)sprintf (string, "Click to attack when you are near an enemy.");
+                                               else sprintf (string, "Press %s to attack when you are near an enemy.",KeyToChar(attackkey));
+                                               sprintf (string2, "You can punch by standing still near an enemy and attacking.");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==16){
+                                               sprintf (string, "If you are close, you will perform a weak punch.");
+                                               sprintf (string2, "The weak punch is excellent for starting attack combinations.");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==17){
+                                               sprintf (string, "Attacking while running results in a spin kick.");
+                                               sprintf (string2, "This is one of your most powerful ground attacks.");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==18){
+                                               sprintf (string, "Sweep the enemy's legs out by attacking while crouched.");
+                                               sprintf (string2, "This is a very fast attack, and easy to follow up.");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==19){
+                                               sprintf (string, "When an enemy is on the ground, you can deal some extra");
+                                               sprintf (string2, "damage by running up and drop-kicking him.");
+                                               sprintf (string3, "(Try knocking them down with a sweep first)");
+                                       }
+                                       if(tutorialstage==20){
+                                               sprintf (string, "Your most powerful individual attack is the rabbit kick.");
+                                               if(attackkey==MAC_MOUSEBUTTON1)sprintf (string2, "Run at the enemy while holding the mouse button, and press");
+                                               else sprintf (string2, "Run at the enemy while holding %s, and press", KeyToChar(attackkey));
+                                               sprintf (string3, "the jump key (%s) to attack.",KeyToChar(jumpkey));
+                                       }
+                                       if(tutorialstage==21){
+                                               sprintf (string, "This attack is devastating if timed correctly.");
+                                               sprintf (string2, "Even if timed incorrectly, it will knock the enemy over.");
+                                               if(againbonus)sprintf (string3, "Try rabbit-kicking the imaginary enemy again.");
+                                               else sprintf (string3, "Try rabbit-kicking the imaginary enemy.");
+                                       }
+                                       if(tutorialstage==22){
+                                               sprintf (string, "If you sneak behind an enemy unnoticed, you can kill");
+                                               sprintf (string2, "him instantly. Move close behind this enemy");
+                                               sprintf (string3, "and attack.");
+                                       }
+                                       if(tutorialstage==23){
+                                               sprintf (string, "Another important attack is the wall kick. When an enemy");
+                                               sprintf (string2, "is near a wall, perform a walljump nearby and hold");
+                                               sprintf (string3, "the attack key during impact with the wall.");
+                                       }
+                                       if(tutorialstage==24){
+                                               sprintf (string, "You can tackle enemies by running at them animal-style");
+                                               if(attackkey==MAC_MOUSEBUTTON1)sprintf (string2, "and pressing jump (%s) or attack(mouse button).",KeyToChar(jumpkey));
+                                               else sprintf (string2, "and pressing jump (%s) or attack(%s).",KeyToChar(jumpkey),KeyToChar(attackkey));
+                                               sprintf (string3, "This is especially useful when they are running away.");
+                                       }
+                                       if(tutorialstage==25){
+                                               sprintf (string, "Dodge by pressing back and attack. Dodging is essential");
+                                               sprintf (string2, "against enemies with swords or other long weapons.");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==26){
+                                               sprintf (string, "REVERSALS AND COUNTER-REVERSALS");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==27){
+                                               sprintf (string, "The enemy can now reverse your attacks.");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==28){
+                                               sprintf (string, "If you attack, you will notice that the enemy now sometimes");
+                                               sprintf (string2, "catches your attack and uses it against you. Hold");
+                                               sprintf (string3, "crouch (%s) after attacking to escape from reversals.",KeyToChar(crouchkey));
+                                       }
+                                       if(tutorialstage==29){
+                                               sprintf (string, "Try escaping from two more reversals in a row.");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==30){
+                                               sprintf (string, "Good!");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==31){
+                                               sprintf (string, "To reverse an attack, you must tap crouch (%s) during the",KeyToChar(crouchkey));
+                                               sprintf (string2, "enemy's attack. You must also be close to the enemy;");
+                                               sprintf (string3, "this is especially important against armed opponents.");
+                                       }
+                                       if(tutorialstage==32){
+                                               sprintf (string, "The enemy can attack in %d seconds.", (int)(tutorialmaxtime-tutorialstagetime));
+                                               sprintf (string2, "This imaginary opponents attacks will be highlighted");
+                                               sprintf (string3, "to make this easier.");
+                                       }
+                                       if(tutorialstage==33){
+                                               sprintf (string, "Reverse three enemy attacks!");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==34){
+                                               sprintf (string, "Reverse two more enemy attacks!");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==35){
+                                               sprintf (string, "Reverse one more enemy attack!");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==36){
+                                               sprintf (string, "Excellent!");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==37){
+                                               sprintf (string, "Now spar with the enemy for %d more seconds.", (int)(tutorialmaxtime-tutorialstagetime));
+                                               sprintf (string2, "Damage dealt: %d",(int)damagedealt);
+                                               sprintf (string3, "Damage taken: %d.",(int)damagetaken);
+                                       }
+                                       if(tutorialstage==38){
+                                               sprintf (string, "WEAPONS:");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==39){
+                                               sprintf (string, "There is now an imaginary knife");
+                                               sprintf (string2, "in the center of the training area.");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==40){
+                                               sprintf (string, "Stand, roll or handspring over the knife");
+                                               sprintf (string2, "while pressing %s to pick it up.",KeyToChar(throwkey));
+                                               sprintf (string3, "You can crouch and press the same key to drop it again.");
+                                       }
+                                       if(tutorialstage==41){
+                                               sprintf (string, "You can equip and unequip weapons using the %s key.",KeyToChar(drawkey));
+                                               sprintf (string2, "Sometimes it is best to keep them unequipped to");
+                                               sprintf (string3, "prevent enemies from taking them. ");
+                                       }
+                                       if(tutorialstage==42){
+                                               sprintf (string, "The knife is the smallest weapon and the least encumbering.");
+                                               sprintf (string2, "You can equip or unequip it while standing, crouching,");
+                                               sprintf (string3, "running or flipping.");
+                                       }
+                                       if(tutorialstage==43){
+                                               sprintf (string, "You perform weapon attacks the same way as unarmed attacks,");
+                                               sprintf (string2, "but sharp weapons cause permanent damage, instead of the");
+                                               sprintf (string3, "temporary trauma from blunt weapons, fists and feet.");
+                                       }
+                                       if(tutorialstage==44){
+                                               sprintf (string, "The enemy now has your knife!");
+                                               sprintf (string2, "Please reverse two of his knife attacks.");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==45){
+                                               sprintf (string, "Please reverse one more of his knife attacks.");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==46){
+                                               sprintf (string, "Now he has a sword!");
+                                               sprintf (string2, "The sword has longer reach than your arms, so you");
+                                               sprintf (string3, "must move close to reverse the sword slash.");
+                                       }
+                                       if(tutorialstage==47){
+                                               sprintf (string, "Long weapons like the sword and staff are also useful for defense;");
+                                               sprintf (string2, "you can parry enemy weapon attacks by pressing the attack key");
+                                               sprintf (string3, "at the right time. Please try parrying the enemy's attacks!");
+                                       }
+                                       if(tutorialstage==48){
+                                               sprintf (string, "The staff is like the sword, but has two main attacks.");
+                                               sprintf (string2, "The standing smash is fast and effective, and the running");
+                                               sprintf (string3, "spin smash is slower and more powerful.");
+                                       }
+                                       if(tutorialstage==49){
+                                               sprintf (string, "When facing an enemy, you can throw the knife with %s.",KeyToChar(throwkey));
+                                               sprintf (string2, "It is possible to throw the knife while flipping,");
+                                               sprintf (string3, "but it is very inaccurate.");
+                                       }
+                                       if(tutorialstage==50){
+                                               sprintf (string, "You now know everything you can learn from training.");
+                                               sprintf (string2, "Everything else you must learn from experience!");
+                                               sprintf (string3, " ");
+                                       }
+                                       if(tutorialstage==51){
+                                               sprintf (string, "Walk out of the training area to return to the main menu.");
+                                               sprintf (string2, " ");
+                                               sprintf (string3, " ");
+                                       }
+
+                                       glColor4f(0,0,0,tutorialopac);
+                                       text.glPrintOutline(screenwidth/2-7.6*strlen(string)*screenwidth/1024-4,screenheight/16-4+screenheight*4/5,string,1,1.5*1.25*screenwidth/1024,screenwidth,screenheight);
+                                       text.glPrintOutline(screenwidth/2-7.6*strlen(string2)*screenwidth/1024-4,screenheight/16-4+screenheight*4/5-20*screenwidth/1024,string2,1,1.5*1.25*screenwidth/1024,screenwidth,screenheight);
+                                       text.glPrintOutline(screenwidth/2-7.6*strlen(string3)*screenwidth/1024-4,screenheight/16-4+screenheight*4/5-40*screenwidth/1024,string3,1,1.5*1.25*screenwidth/1024,screenwidth,screenheight);
+                                       glColor4f(1,1,1,tutorialopac);
+                                       text.glPrint(screenwidth/2-7.6*strlen(string)*screenwidth/1024,screenheight/16+screenheight*4/5,string,1,1.5*screenwidth/1024,screenwidth,screenheight);
+                                       text.glPrint(screenwidth/2-7.6*strlen(string2)*screenwidth/1024,screenheight/16+screenheight*4/5-20*screenwidth/1024,string2,1,1.5*screenwidth/1024,screenwidth,screenheight);
+                                       text.glPrint(screenwidth/2-7.6*strlen(string3)*screenwidth/1024,screenheight/16+screenheight*4/5-40*screenwidth/1024,string3,1,1.5*screenwidth/1024,screenwidth,screenheight);
+
+                                       sprintf (string, "Press 'tab' to skip to the next item.",KeyToChar(jumpkey));
+                                       sprintf (string2, "Press escape at any time to");
+                                       sprintf (string3, "pause or exit the tutorial.");
+
+                                       glColor4f(0,0,0,1);
+                                       text.glPrintOutline(screenwidth/2-7.6*strlen(string)*screenwidth/1024*.8-4,0-4+screenheight*1/10,string,1,1.5*1.25*screenwidth/1024*.8,screenwidth,screenheight);
+                                       text.glPrintOutline(screenwidth/2-7.6*strlen(string2)*screenwidth/1024*.8-4,0-4+screenheight*1/10-20*.8*screenwidth/1024,string2,1,1.5*1.25*screenwidth/1024*.8,screenwidth,screenheight);
+                                       text.glPrintOutline(screenwidth/2-7.6*strlen(string3)*screenwidth/1024*.8-4,0-4+screenheight*1/10-40*.8*screenwidth/1024,string3,1,1.5*1.25*screenwidth/1024*.8,screenwidth,screenheight);
+                                       glColor4f(0.5,0.5,0.5,1);
+                                       text.glPrint(screenwidth/2-7.6*strlen(string)*screenwidth/1024*.8,0+screenheight*1/10,string,1,1.5*screenwidth/1024*.8,screenwidth,screenheight);
+                                       text.glPrint(screenwidth/2-7.6*strlen(string2)*screenwidth/1024*.8,0+screenheight*1/10-20*.8*screenwidth/1024,string2,1,1.5*screenwidth/1024*.8,screenwidth,screenheight);
+                                       text.glPrint(screenwidth/2-7.6*strlen(string3)*screenwidth/1024*.8,0+screenheight*1/10-40*.8*screenwidth/1024,string3,1,1.5*screenwidth/1024*.8,screenwidth,screenheight);
+                               }
+                               //Hot spots     
+
+                               if(numhotspots&&(bonustime>=1||bonus<=0||bonustime<0)&&!tutoriallevel){
+                                       int closest=-1;
+                                       float closestdist=-1;
+                                       float distance=0;
+                                       closest=currenthotspot;
+                                       for(i=0;i<numhotspots;i++){
+                                               distance=findDistancefast(&player[0].coords,&hotspot[i]);
+                                               if(closestdist==-1||distance<closestdist){
+                                                       if(findDistancefast(&player[0].coords,&hotspot[i])<hotspotsize[i]&&((hotspottype[i]<=10&&hotspottype[i]>=0)||(hotspottype[i]<=40&&hotspottype[i]>=20))){
+                                                               closestdist=distance;
+                                                               closest=i;
+                                                       }
+                                               }
+                                       }
+                                       if(closest!=-1)
+                                               currenthotspot=closest;
+                                       if(currenthotspot!=-1){
+                                               if(hotspottype[closest]<=10){
+                                                       if(findDistancefast(&player[0].coords,&hotspot[closest])<hotspotsize[closest])
+                                                               tutorialstagetime=0;
+                                                       tutorialmaxtime=1;
+                                                       tutorialopac=tutorialmaxtime-tutorialstagetime;
+                                                       if(tutorialopac>1)tutorialopac=1;
+                                                       if(tutorialopac<0)tutorialopac=0;
+
+                                                       sprintf (string, "%s", hotspottext[closest]);
+
+                                                       int lastline;
+                                                       int line=0;
+                                                       bool done=0;
+                                                       lastline=0;
+                                                       i=0;
+                                                       while(!done){
+                                                               if(string[i]=='\n'||string[i]>'z'||string[i]<' '||string[i]=='\0'){
+                                                                       glColor4f(0,0,0,tutorialopac);
+                                                                       text.glPrintOutline(screenwidth/2-7.6*(i-lastline)*screenwidth/1024-4,screenheight/16-4+screenheight*4/5-20*screenwidth/1024*line,string,1,1.5*1.25*screenwidth/1024,screenwidth,screenheight,lastline,i);
+                                                                       glColor4f(1,1,1,tutorialopac);
+                                                                       text.glPrint(screenwidth/2-7.6*(i-lastline)*screenwidth/1024,screenheight/16+screenheight*4/5-20*screenwidth/1024*line,string,1,1.5*screenwidth/1024,screenwidth,screenheight,lastline,i);
+                                                                       lastline=i+1;
+                                                                       line++;
+                                                                       if(string[i]=='\0')done=1;
+                                                               }
+                                                               if(i>=255)done=1;
+                                                               i++;
+                                                       }
+                                               }
+                                               else if (hotspottype[closest]>=20&&dialoguegonethrough[hotspottype[closest]-20]==0){
+                                                       whichdialogue=hotspottype[closest]-20;
+                                                       for(j=0;j<numdialogueboxes[whichdialogue];j++){
+                                                               player[participantfocus[whichdialogue][j]].coords=participantlocation[whichdialogue][participantfocus[whichdialogue][j]];
+                                                               player[participantfocus[whichdialogue][j]].rotation=participantrotation[whichdialogue][participantfocus[whichdialogue][j]];
+                                                               player[participantfocus[whichdialogue][j]].targetrotation=participantrotation[whichdialogue][participantfocus[whichdialogue][j]];
+                                                               player[participantfocus[whichdialogue][j]].velocity=0;
+                                                               player[participantfocus[whichdialogue][j]].targetanimation=player[participantfocus[whichdialogue][j]].getIdle();
+                                                               player[participantfocus[whichdialogue][j]].targetframe=0;
+                                                       }
+                                                       directing=0;
+                                                       indialogue=0;
+                                                       dialoguegonethrough[whichdialogue]++;
+                                                       if(dialogueboxsound[whichdialogue][indialogue]!=0){
+                                                               static float gLoc[3];
+                                                               static float vel[3];
+                                                               gLoc[0]=player[participantfocus[whichdialogue][indialogue]].coords.x;
+                                                               gLoc[1]=player[participantfocus[whichdialogue][indialogue]].coords.y;
+                                                               gLoc[2]=player[participantfocus[whichdialogue][indialogue]].coords.z;
+                                                               vel[0]=0;
+                                                               vel[1]=0;
+                                                               vel[2]=0;
+                                                               int whichsoundplay;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==1)whichsoundplay=rabbitchitter;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==2)whichsoundplay=rabbitchitter2;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==3)whichsoundplay=rabbitpainsound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==4)whichsoundplay=rabbitpain1sound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==5)whichsoundplay=rabbitattacksound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==6)whichsoundplay=rabbitattack2sound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==7)whichsoundplay=rabbitattack3sound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==8)whichsoundplay=rabbitattack4sound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==9)whichsoundplay=growlsound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==10)whichsoundplay=growl2sound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==11)whichsoundplay=snarlsound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==12)whichsoundplay=snarl2sound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==13)whichsoundplay=barksound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==14)whichsoundplay=bark2sound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==15)whichsoundplay=bark3sound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==16)whichsoundplay=barkgrowlsound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==-1)whichsoundplay=fireendsound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==-2)whichsoundplay=firestartsound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==-3)whichsoundplay=consolesuccesssound;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]==-4)whichsoundplay=consolefailsound;
+                                                               PlaySoundEx( whichsoundplay, samp[whichsoundplay], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[whichsoundplay], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[whichsoundplay], 256);
+                                                               FSOUND_SetPaused(channels[whichsoundplay], FALSE);
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               if(indialogue!=-1&&!mainmenu){
+                                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                                       glDisable(GL_CULL_FACE);
+                                       glDisable(GL_LIGHTING);
+                                       glDisable(GL_TEXTURE_2D);
+                                       glDepthMask(0);
+                                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                       glPushMatrix();                                                                         // Store The Projection Matrix
+                                       glLoadIdentity();                                                                       // Reset The Projection Matrix
+                                       glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                       glPushMatrix();                                                                         // Store The Modelview Matrix
+                                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                                       if(dialogueboxlocation[whichdialogue][indialogue]==1)glTranslatef(0,screenheight*3/4,0);
+                                       glScalef(screenwidth,screenheight/4,1);
+                                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                                       glEnable(GL_BLEND);
+
+                                       glColor4f(dialogueboxcolor[whichdialogue][indialogue][0],dialogueboxcolor[whichdialogue][indialogue][1],dialogueboxcolor[whichdialogue][indialogue][2],0.7);
+                                       glBegin(GL_QUADS);
+                                       glVertex3f(0,           0,       0.0f);
+                                       glVertex3f(1,   0,       0.0f);
+                                       glVertex3f(1,   1, 0.0f);
+                                       glVertex3f(0,   1, 0.0f);
+                                       glEnd();
+                                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                                       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+                                       glEnable(GL_CULL_FACE);
+                                       glDisable(GL_BLEND);
+                                       glDepthMask(1);
+                                       glEnable(GL_TEXTURE_2D);
+
+                                       tutorialopac=1;
+
+                                       float startx;
+                                       float starty;
+
+                                       startx=screenwidth*1/5;
+                                       if(dialogueboxlocation[whichdialogue][indialogue]==1)starty=screenheight/16+screenheight*4/5;
+                                       if(dialogueboxlocation[whichdialogue][indialogue]==2)starty=screenheight*1/5-screenheight/16;
+
+//                                     char tempname[64];
+                                       char tempname[264];
+                                       bool goodchar;
+                                       int tempnum=0;
+//                                     for(i=0;i<64;i++){
+                                       for(i=0;i<264;i++){
+                                               tempname[i]='\0';
+                                       }
+
+                                       for(i=0;i<(int)strlen(dialoguename[whichdialogue][indialogue]);i++){
+                                               tempname[tempnum]=dialoguename[whichdialogue][indialogue][i];
+                                               goodchar=1;
+                                               if(dialoguename[whichdialogue][indialogue][i]=='#'||dialoguename[whichdialogue][indialogue][i]=='\0')goodchar=0;
+                                               //if(tempnum>2)if(tempname[tempnum-2]=='e'&&tempname[tempnum-1]=='r')goodchar=0;
+                                               //if(tempnum>2)if(tempname[tempnum]=='r'&&tempname[0]=='a')goodchar=0;
+                                               if(goodchar)tempnum++;
+                                               else tempname[tempnum]='\0';
+                                       }
+
+                                       sprintf (string, "%s: ", tempname);
+
+                                       if(dialogueboxcolor[whichdialogue][indialogue][0]+dialogueboxcolor[whichdialogue][indialogue][1]+dialogueboxcolor[whichdialogue][indialogue][2]<1.5){
+                                               glColor4f(0,0,0,tutorialopac);
+                                               text.glPrintOutline(startx-2*7.6*strlen(string)*screenwidth/1024-4,starty-4,string,1,1.5*1.25*screenwidth/1024,screenwidth,screenheight);
+                                               glColor4f(0.7,0.7,0.7,tutorialopac);
+                                               text.glPrint(startx-2*7.6*strlen(string)*screenwidth/1024,starty,string,1,1.5*screenwidth/1024,screenwidth,screenheight);
+                                       }
+                                       else
+                                       {
+                                               glColor4f(0,0,0,tutorialopac);
+                                               text.glPrintOutline(startx-2*7.6*strlen(string)*screenwidth/1024-4,starty-4,string,1,1.5*1.25*screenwidth/1024,screenwidth,screenheight);
+
+                                       }
+
+                                       tempnum=0;
+                                       for(i=0;i<(int)strlen(dialoguetext[whichdialogue][indialogue])+1;i++){
+                                               tempname[tempnum]=dialoguetext[whichdialogue][indialogue][i];
+                                               if(dialoguetext[whichdialogue][indialogue][i]!='#')tempnum++;
+                                       }
+
+
+                                       sprintf (string, "%s", tempname);
+
+
+                                       int lastline;
+                                       int line=0;
+                                       bool done=0;
+                                       lastline=0;
+                                       i=0;
+                                       while(!done){
+                                               if(string[i]=='\n'||string[i]>'z'||string[i]<' '||string[i]=='\0'){
+                                                       if(dialogueboxcolor[whichdialogue][indialogue][0]+dialogueboxcolor[whichdialogue][indialogue][1]+dialogueboxcolor[whichdialogue][indialogue][2]<1.5){
+                                                               glColor4f(0,0,0,tutorialopac);
+                                                               text.glPrintOutline(startx/*-7.6*(i-lastline)*screenwidth/1024*/-4,starty-4-20*screenwidth/1024*line,string,1,1.5*1.25*screenwidth/1024,screenwidth,screenheight,lastline,i);
+                                                               glColor4f(1,1,1,tutorialopac);
+                                                               text.glPrint(startx/*-7.6*(i-lastline)*screenwidth/1024*/,starty-20*screenwidth/1024*line,string,1,1.5*screenwidth/1024,screenwidth,screenheight,lastline,i);
+                                                       }
+                                                       else
+                                                       {
+                                                               glColor4f(0,0,0,tutorialopac);
+                                                               text.glPrint(startx/*-7.6*(i-lastline)*screenwidth/1024*/,starty-20*screenwidth/1024*line,string,1,1.5*screenwidth/1024,screenwidth,screenheight,lastline,i);
+                                                       }
+                                                       lastline=i+1;
+                                                       line++;
+                                                       if(string[i]=='\0')done=1;
+                                               }
+                                               if(i>=255)done=1;
+                                               i++;
+                                       }
+                               }       
+
+                               if(!tutoriallevel&&!winfreeze&&indialogue==-1&&!mainmenu){
+                                       if(campaign){
+                                               if(!scoreadded)sprintf (string, "Score: %d", (int)accountcampaignscore[accountactive]+(int)bonustotal);//(int)bonustotal);
+                                               if(scoreadded)sprintf (string, "Score: %d", (int)accountcampaignscore[accountactive]);//(int)bonustotal);
+                                       }
+                                       if(!campaign)sprintf (string, "Score: %d", (int)bonustotal);
+                                       glColor4f(0,0,0,1);
+                                       text.glPrintOutline(1024/40-4,768/16-4+768*14/16,string,1,1.5*1.25,1024,768);
+                                       glColor4f(1,0,0,1);
+                                       text.glPrint(1024/40,768/16+768*14/16,string,1,1.5,1024,768);
+                               }
+
+                               glColor4f(.5,.5,.5,1);
+
+
+                               if((texttoggle||editorenabled)&&debugmode&&!mainmenu){
+                                       sprintf (string, "The framespersecond is %d.",(int)(fps));
+                                       text.glPrint(10,30,string,0,.8,1024,768);
+
+                                       sprintf (string, "Name: %s", registrationname);
+                                       text.glPrint(10,260,string,0,.8,1024,768);
+
+
+                                       if(editorenabled)sprintf (string, "Map editor enabled.");
+                                       if(!editorenabled)sprintf (string, "Map editor Disabled.");
+                                       text.glPrint(10,60,string,0,.8,1024,768);
+                                       if(editorenabled){
+                                               sprintf (string, "Object size: %f",editorsize);
+                                               text.glPrint(10,75,string,0,.8,1024,768);
+                                               if(editorrotation>=0)sprintf (string, "Object rotation: %f",editorrotation);
+                                               else sprintf (string, "Object rotation: Random");
+                                               text.glPrint(10,90,string,0,.8,1024,768);
+                                               if(editorrotation2>=0)sprintf (string, "Object rotation2: %f",editorrotation2);
+                                               else sprintf (string, "Object rotation2: Random");
+                                               text.glPrint(10,105,string,0,.8,1024,768);
+                                               sprintf (string, "Object type: %d",editortype);
+                                               text.glPrint(10,120,string,0,.8,1024,768);
+                                               if(editortype==boxtype)sprintf (string, "(box)");
+                                               if(editortype==treetrunktype)sprintf (string, "(tree)");
+                                               if(editortype==walltype)sprintf (string, "(wall)");
+                                               if(editortype==weirdtype)sprintf (string, "(weird)");
+                                               if(editortype==spiketype)sprintf (string, "(spike)");
+                                               if(editortype==rocktype)sprintf (string, "(rock)");
+                                               if(editortype==bushtype)sprintf (string, "(bush)");
+                                               if(editortype==tunneltype)sprintf (string, "(tunnel)");
+                                               if(editortype==chimneytype)sprintf (string, "(chimney)");
+                                               if(editortype==platformtype)sprintf (string, "(platform)");
+                                               if(editortype==cooltype)sprintf (string, "(cool)");
+                                               if(editortype==firetype)sprintf (string, "(fire)");
+                                               text.glPrint(130,120,string,0,.8,1024,768);
+
+                                               sprintf (string, "Numplayers: %d",numplayers);
+                                               text.glPrint(10,155,string,0,.8,1024,768);
+                                               sprintf (string, "Player %d: numwaypoints: %d",numplayers,player[numplayers-1].numwaypoints);
+                                               text.glPrint(10,140,string,0,.8,1024,768);
+                                       }
+                                       /*sprintf (string, "Coords are: %f %f %f",player[0].coords.x,player[0].coords.y,player[0].coords.z);
+                                       text.glPrint(10,200,string,0,.8,1024,768);*/
+                                       sprintf (string, "Difficulty: %d",difficulty);
+                                       text.glPrint(10,240,string,0,.8,1024,768);
+                                       /*
+                                       sprintf (string, "lasthotspot: %d",hotspottype[numhotspots-1]);
+                                       text.glPrint(10,240,string,0,.8,1024,768);
+                                       sprintf (string, "killhotspot: %d",killhotspot);
+                                       text.glPrint(10,220,string,0,.8,1024,768);
+                                       sprintf (string, "winhotspot: %d",winhotspot);
+                                       text.glPrint(10,200,string,0,.8,1024,768);*/
+
+                               }
+               }
+
+               if(drawmode==glowmode){
+                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                       glDisable(GL_CULL_FACE);
+                       glDisable(GL_LIGHTING);
+                       glDisable(GL_TEXTURE_2D);
+                       glDepthMask(0);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPushMatrix();                                                                         // Store The Projection Matrix
+                       glLoadIdentity();                                                                       // Reset The Projection Matrix
+                       glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPushMatrix();                                                                         // Store The Modelview Matrix
+                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                       glScalef(screenwidth,screenheight,1);
+                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       glEnable(GL_BLEND);
+                       glColor4f(0,0,0,.5);
+                       glBegin(GL_QUADS);
+                       glVertex3f(0,           0,       0.0f);
+                       glVertex3f(256, 0,       0.0f);
+                       glVertex3f(256, 256, 0.0f);
+                       glVertex3f(0,   256, 0.0f);
+                       glEnd();
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+                       glEnable(GL_CULL_FACE);
+                       glDisable(GL_BLEND);
+                       glDepthMask(1);
+               }
+
+               if((((blackout&&damageeffects)||(player[0].bloodloss>0&&damageeffects&&player[0].blooddimamount>0)||player[0].dead)&&!cameramode)||console){
+                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                       glDisable(GL_CULL_FACE);
+                       glDisable(GL_LIGHTING);
+                       glDisable(GL_TEXTURE_2D);
+                       glDepthMask(0);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPushMatrix();                                                                         // Store The Projection Matrix
+                       glLoadIdentity();                                                                       // Reset The Projection Matrix
+                       glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPushMatrix();                                                                         // Store The Modelview Matrix
+                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                       glScalef(screenwidth,screenheight,1);
+                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       glEnable(GL_BLEND);
+                       if(player[0].dead)blackout+=multiplier*3;
+                       if(player[0].dead==1)blackout=.4f;
+                       if(player[0].dead==2&&blackout>.6)blackout=.6;
+                       glColor4f(0,0,0,blackout);
+                       if(!player[0].dead){
+                               if((player[0].bloodloss/player[0].damagetolerance*(sin(woozy)/4+.5))*.3<.3){
+                                       glColor4f(0,0,0,player[0].blooddimamount*player[0].bloodloss/player[0].damagetolerance*(sin(woozy)/4+.5)*.3);
+                                       blackout=player[0].blooddimamount*player[0].bloodloss/player[0].damagetolerance*(sin(woozy)/4+.5)*.3;
+                               }
+                               else {
+                                       glColor4f(0,0,0,player[0].blooddimamount*.3);
+                                       blackout=player[0].blooddimamount*.3;
+                               }
+                       }
+                       if(console)glColor4f(.7,0,0,.2);
+                       glBegin(GL_QUADS);
+                       glVertex3f(0,           0,       0.0f);
+                       glVertex3f(256, 0,       0.0f);
+                       glVertex3f(256, 256, 0.0f);
+                       glVertex3f(0,   256, 0.0f);
+                       glEnd();
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+                       glEnable(GL_CULL_FACE);
+                       glDisable(GL_BLEND);
+                       glDepthMask(1);
+               }
+
+               if(flashamount>0&&damageeffects){
+                       if(flashamount>1)flashamount=1;
+                       if(flashdelay<=0)flashamount-=multiplier;
+                       flashdelay--;
+                       if(flashamount<0)flashamount=0;
+                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                       glDisable(GL_CULL_FACE);
+                       glDisable(GL_LIGHTING);
+                       glDepthMask(0);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPushMatrix();                                                                         // Store The Projection Matrix
+                       glLoadIdentity();                                                                       // Reset The Projection Matrix
+                       glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPushMatrix();                                                                         // Store The Modelview Matrix
+                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                       glScalef(screenwidth,screenheight,1);
+                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       glEnable(GL_BLEND);
+                       glColor4f(flashr,flashg,flashb,flashamount);
+                       glBegin(GL_QUADS);
+                       glVertex3f(0,           0,       0.0f);
+                       glVertex3f(256, 0,       0.0f);
+                       glVertex3f(256, 256, 0.0f);
+                       glVertex3f(0,   256, 0.0f);
+                       glEnd();
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+                       glEnable(GL_CULL_FACE);
+                       glDisable(GL_BLEND);
+                       glDepthMask(1);
+               }       
+
+               if(!console){
+                       displaytime[0]=0;
+                       glEnable(GL_TEXTURE_2D);
+                       glColor4f(1,1,1,1);
+                       if(chatting){
+                               sprintf (string, " ]");
+                               text.glPrint(10,30+screenheight-330,string,0,1,screenwidth,screenheight);
+                               if(displayblink){
+                                       sprintf (string, "_");
+                                       text.glPrint(30+(float)(displayselected)*10,30+(screenheight-330),string,0,1,screenwidth,screenheight);
+                               }
+                       }
+                       for(i=0;i<15;i++){
+                               if((i!=0||chatting)&&displaytime[i]<4)
+                                       for(j=0;j<displaychars[i];j++){
+                                               glColor4f(1,1,1,4-displaytime[i]);
+                                               if(j<displaychars[i]){
+                                                       sprintf (string, "%c",displaytext[i][j]);
+                                                       text.glPrint(30+j*10,30+i*20+(screenheight-330),string,0,1,screenwidth,screenheight);
+                                               }
+                                       }
+                       }
+               }
+
+               if(minimap&&indialogue==-1){
+                       float mapviewdist;
+                       mapviewdist=20000;
+
+                       glDisable(GL_DEPTH_TEST);
+                       glColor3f (1.0, 1.0, 1.0); // no coloring
+
+                       glEnable(GL_TEXTURE_2D);
+                       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+                       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                       glDisable(GL_CULL_FACE);
+                       glDisable(GL_LIGHTING);
+                       glDepthMask(0);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPushMatrix();                                                                         // Store The Projection Matrix
+                       glLoadIdentity();                                                                       // Reset The Projection Matrix
+                       glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPushMatrix();                                                                         // Store The Modelview Matrix
+                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                       glScalef((float)screenwidth/2,(float)screenwidth/2,1);
+                       glTranslatef(1.75,.25,0);
+                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       glEnable(GL_BLEND);
+                       glColor4f(1,1,1,1);
+                       glPushMatrix();
+                       float opac;
+                       opac=.7;
+                       XYZ center;
+                       float radius;
+                       float distcheck;
+                       center=0;
+                       int numliveplayers=0;
+                       for(i=0;i<numplayers;i++){
+                               if(!player[i].dead)numliveplayers++;
+                       }
+
+                       int numadd;
+                       numadd=0;
+
+                       for(i=0;i<objects.numobjects;i++){
+                               if(objects.type[i]==treetrunktype||objects.type[i]==boxtype){
+                                       center+=objects.position[i];    
+                                       numadd++;
+                               }
+                       }
+                       for(i=0;i<numplayers;i++){
+                               if(!player[i].dead)center+=player[i].coords;    
+                       }
+                       center/=numadd+numliveplayers;
+
+                       center=player[0].coords;
+
+                       float maxdistance=0;
+                       float tempdist;
+                       int whichclosest;
+                       for(i=0;i<objects.numobjects;i++){
+                               tempdist=findDistancefast(&center,&objects.position[i]);
+                               if(tempdist>maxdistance){
+                                       whichclosest=i;
+                                       maxdistance=tempdist;
+                               }
+                       }
+                       for(i=0;i<numplayers;i++){
+                               if(!player[i].dead){
+                                       tempdist=findDistancefast(&center,&player[i].coords);
+                                       if(tempdist>maxdistance){
+                                               whichclosest=i;
+                                               maxdistance=tempdist;
+                                       }
+                               }
+                       }
+                       radius=fast_sqrt(maxdistance);
+
+                       radius=110;
+
+                       glScalef(.25/radius*256*terrain.scale*.4,.25/radius*256*terrain.scale*.4,1);
+                       glPushMatrix();
+                       glScalef(1/(1/radius*256*terrain.scale*.4),1/(1/radius*256*terrain.scale*.4),1);
+                       /*float startx,starty,endx,endy;
+                       glBegin(GL_QUADS);
+                       glTexCoord2f(1-(center.x-radius)/terrain.scale/256,(center.z-radius)/terrain.scale/256);
+                       glVertex3f(-1,          -1,      0.0f);
+                       glTexCoord2f(1-(center.x+radius)/terrain.scale/256,(center.z-radius)/terrain.scale/256);
+                       glVertex3f(1,   -1,      0.0f);
+                       glTexCoord2f(1-(center.x+radius)/terrain.scale/256,(center.z+radius)/terrain.scale/256);
+                       glVertex3f(1,   1, 0.0f);
+                       glTexCoord2f(1-(center.x-radius)/terrain.scale/256,(center.z+radius)/terrain.scale/256);
+                       glVertex3f(-1,  1, 0.0f);
+                       glEnd();*/
+                       glPopMatrix();
+                       glRotatef(player[0].lookrotation*-1+180,0,0,1);
+                       glTranslatef(-(center.x/terrain.scale/256*-2+1),(center.z/terrain.scale/256*-2+1),0);
+                       for(i=0;i<objects.numobjects;i++){
+                               if(objects.type[i]==treetrunktype){
+                                       distcheck=findDistancefast(&player[0].coords,&objects.position[i]);
+                                       if(distcheck<mapviewdist){
+                                               glBindTexture( GL_TEXTURE_2D, Mapcircletexture);
+                                               glColor4f(0,.3,0,opac*(1-distcheck/mapviewdist));
+                                               glPushMatrix();
+                                               glTranslatef(objects.position[i].x/terrain.scale/256*-2+1,objects.position[i].z/terrain.scale/256*2-1,0);
+                                               glRotatef(objects.rotation[i],0,0,1);
+                                               glScalef(.003,.003,.003);
+                                               glBegin(GL_QUADS);
+                                               glTexCoord2f(0,0);
+                                               glVertex3f(-1,          -1,      0.0f);
+                                               glTexCoord2f(1,0);
+                                               glVertex3f(1,   -1,      0.0f);
+                                               glTexCoord2f(1,1);
+                                               glVertex3f(1,   1, 0.0f);
+                                               glTexCoord2f(0,1);
+                                               glVertex3f(-1,  1, 0.0f);
+                                               glEnd();
+                                               glPopMatrix();
+                                       }
+                               }
+                               if(objects.type[i]==boxtype){
+                                       distcheck=findDistancefast(&player[0].coords,&objects.position[i]);
+                                       if(distcheck<mapviewdist){
+                                               glBindTexture( GL_TEXTURE_2D, Mapboxtexture);
+                                               glColor4f(.4,.4,.4,opac*(1-distcheck/mapviewdist));
+                                               glPushMatrix();
+                                               glTranslatef(objects.position[i].x/terrain.scale/256*-2+1,objects.position[i].z/terrain.scale/256*2-1,0);
+                                               glRotatef(objects.rotation[i],0,0,1);
+                                               glScalef(.01*objects.scale[i],.01*objects.scale[i],.01*objects.scale[i]);
+                                               glBegin(GL_QUADS);
+                                               glTexCoord2f(0,0);
+                                               glVertex3f(-1,          -1,      0.0f);
+                                               glTexCoord2f(1,0);
+                                               glVertex3f(1,   -1,      0.0f);
+                                               glTexCoord2f(1,1);
+                                               glVertex3f(1,   1, 0.0f);
+                                               glTexCoord2f(0,1);
+                                               glVertex3f(-1,  1, 0.0f);
+                                               glEnd();
+                                               glPopMatrix();
+                                       }
+                               }
+                       }
+                       if(editorenabled){
+                               glBindTexture( GL_TEXTURE_2D, Mapcircletexture);
+                               for(i=0;i<numboundaries;i++){
+                                       glColor4f(0,0,0,opac/3);
+                                       glPushMatrix();
+                                       glTranslatef(boundary[i].x/terrain.scale/256*-2+1,boundary[i].z/terrain.scale/256*2-1,0);
+                                       glScalef(.002,.002,.002);
+                                       glBegin(GL_QUADS);
+                                       glTexCoord2f(0,0);
+                                       glVertex3f(-1,          -1,      0.0f);
+                                       glTexCoord2f(1,0);
+                                       glVertex3f(1,   -1,      0.0f);
+                                       glTexCoord2f(1,1);
+                                       glVertex3f(1,   1, 0.0f);
+                                       glTexCoord2f(0,1);
+                                       glVertex3f(-1,  1, 0.0f);
+                                       glEnd();
+                                       glPopMatrix();
+                               }
+                       }
+                       for(i=0;i<numplayers;i++){
+                               distcheck=findDistancefast(&player[0].coords,&player[i].coords);
+                               if(distcheck<mapviewdist){
+                                       glPushMatrix();
+                                       glBindTexture( GL_TEXTURE_2D, Maparrowtexture);
+                                       if(i==0)glColor4f(1,1,1,opac);
+                                       else if(player[i].dead==2||player[i].howactive>typesleeping)glColor4f(0,0,0,opac*(1-distcheck/mapviewdist));
+                                       else if(player[i].dead)glColor4f(.3,.3,.3,opac*(1-distcheck/mapviewdist));
+                                       else if(player[i].aitype==attacktypecutoff)glColor4f(1,0,0,opac*(1-distcheck/mapviewdist));
+                                       else if(player[i].aitype==passivetype)glColor4f(0,1,0,opac*(1-distcheck/mapviewdist));
+                                       else glColor4f(1,1,0,1);
+                                       glTranslatef(player[i].coords.x/terrain.scale/256*-2+1,player[i].coords.z/terrain.scale/256*2-1,0);
+                                       glRotatef(player[i].rotation+180,0,0,1);
+                                       glScalef(.005,.005,.005);
+                                       glBegin(GL_QUADS);
+                                       glTexCoord2f(0,0);
+                                       glVertex3f(-1,          -1,      0.0f);
+                                       glTexCoord2f(1,0);
+                                       glVertex3f(1,   -1,      0.0f);
+                                       glTexCoord2f(1,1);
+                                       glVertex3f(1,   1, 0.0f);
+                                       glTexCoord2f(0,1);
+                                       glVertex3f(-1,  1, 0.0f);
+                                       glEnd();
+                                       /*glBegin(GL_TRIANGLES);
+                                       glTexCoord2f(0,0);
+                                       glVertex3f(-1,          -1,      0.0f);
+                                       glTexCoord2f(1,0);
+                                       glVertex3f(1,   -1,      0.0f);
+                                       glTexCoord2f(1,1);
+                                       glVertex3f(0,   1, 0.0f);
+                                       glEnd();*/
+                                       glPopMatrix();
+                               }
+                       }
+                       /*glBegin(GL_QUADS);
+                       glTexCoord2f(0,0);
+                       glVertex3f(-1,          -1,      0.0f);
+                       glTexCoord2f(1,0);
+                       glVertex3f(1,   -1,      0.0f);
+                       glTexCoord2f(1,1);
+                       glVertex3f(1,   1, 0.0f);
+                       glTexCoord2f(0,1);
+                       glVertex3f(-1,  1, 0.0f);
+                       glEnd();*/
+                       glPopMatrix();
+                       glDisable(GL_TEXTURE_2D);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+                       glEnable(GL_CULL_FACE);
+                       glDisable(GL_BLEND);
+                       glDepthMask(1);
+               }
+
+               /*if(loading){
+               loading=2;
+               drawmode=normalmode;
+               }*/
+
+
+               if(loading&&!stealthloading&&(!campaign||player[0].dead)){
+                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                       glDisable(GL_CULL_FACE);
+                       glDisable(GL_LIGHTING);
+                       glDisable(GL_TEXTURE_2D);
+                       glDepthMask(0);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPushMatrix();                                                                         // Store The Projection Matrix
+                       glLoadIdentity();                                                                       // Reset The Projection Matrix
+                       glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPushMatrix();                                                                         // Store The Modelview Matrix
+                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                       glScalef(screenwidth,screenheight,1);
+                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       glEnable(GL_BLEND);
+                       glColor4f(0,0,0,.7);
+                       glBegin(GL_QUADS);
+                       glVertex3f(0,           0,       0.0f);
+                       glVertex3f(256, 0,       0.0f);
+                       glVertex3f(256, 256, 0.0f);
+                       glVertex3f(0,   256, 0.0f);
+                       glEnd();
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+                       glEnable(GL_CULL_FACE);
+                       glDisable(GL_BLEND);
+                       glDepthMask(1);
+
+                       //logo
+                       glDisable(GL_DEPTH_TEST);
+                       glColor3f (1.0, 1.0, 1.0); // no coloring
+
+                       glEnable(GL_TEXTURE_2D);
+                       /*glBindTexture( GL_TEXTURE_2D, logotexture);
+                       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+                       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                       glDisable(GL_CULL_FACE);
+                       glDisable(GL_LIGHTING);
+                       glDepthMask(0);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPushMatrix();                                                                         // Store The Projection Matrix
+                       glLoadIdentity();                                                                       // Reset The Projection Matrix
+                       glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPushMatrix();                                                                         // Store The Modelview Matrix
+                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                       glScalef((float)screenwidth/2,(float)screenwidth/2,1);
+                       glTranslatef(1.8,1.25,0);
+                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       glEnable(GL_BLEND);
+                       glColor4f(1,1,1,1);
+                       glPushMatrix();
+                       glScalef(.25,.25,.25);
+                       glBegin(GL_QUADS);
+                       glTexCoord2f(0,0);
+                       glVertex3f(-1,          -1,      0.0f);
+                       glTexCoord2f(1,0);
+                       glVertex3f(1,   -1,      0.0f);
+                       glTexCoord2f(1,1);
+                       glVertex3f(1,   1, 0.0f);
+                       glTexCoord2f(0,1);
+                       glVertex3f(-1,  1, 0.0f);
+                       glEnd();
+                       glPopMatrix();
+                       glDisable(GL_TEXTURE_2D);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+                       glEnable(GL_CULL_FACE);
+                       glDisable(GL_BLEND);
+                       glDepthMask(1);*/
+
+                       //Minimap
+
+                       if(loading!=4){                         
+                               glEnable(GL_TEXTURE_2D);
+                               glColor4f(1,1,1,1);
+                               sprintf (string, "Loading...");
+                               text.glPrint(1024/2-90,768/2,string,1,2,1024,768);
+                       }
+                       loading=2;
+                       //if(ismotionblur)drawmode=motionblurmode;
+                       drawmode=normalmode;
+               }
+
+               if(winfreeze&&!campaign){
+                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                       glDisable(GL_CULL_FACE);
+                       glDisable(GL_LIGHTING);
+                       glDisable(GL_TEXTURE_2D);
+                       glDepthMask(0);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPushMatrix();                                                                         // Store The Projection Matrix
+                       glLoadIdentity();                                                                       // Reset The Projection Matrix
+                       glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPushMatrix();                                                                         // Store The Modelview Matrix
+                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                       glScalef(screenwidth,screenheight,1);
+                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       glEnable(GL_BLEND);
+                       glColor4f(0,0,0,.4);
+                       glBegin(GL_QUADS);
+                       glVertex3f(0,           0,       0.0f);
+                       glVertex3f(256, 0,       0.0f);
+                       glVertex3f(256, 256, 0.0f);
+                       glVertex3f(0,   256, 0.0f);
+                       glEnd();
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+                       glEnable(GL_CULL_FACE);
+                       glDisable(GL_BLEND);
+                       glDepthMask(1);
+
+                       //logo
+                       glDisable(GL_DEPTH_TEST);
+                       glColor3f (1.0, 1.0, 1.0); // no coloring
+
+                       glEnable(GL_TEXTURE_2D);
+                       /*glBindTexture( GL_TEXTURE_2D, logotexture);
+                       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+                       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                       glDisable(GL_CULL_FACE);
+                       glDisable(GL_LIGHTING);
+                       glDepthMask(0);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPushMatrix();                                                                         // Store The Projection Matrix
+                       glLoadIdentity();                                                                       // Reset The Projection Matrix
+                       glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPushMatrix();                                                                         // Store The Modelview Matrix
+                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                       glScalef((float)screenwidth/2,(float)screenwidth/2,1);
+                       glTranslatef(1.8,1.25,0);
+                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       glEnable(GL_BLEND);
+                       glColor4f(1,1,1,1);
+                       glPushMatrix();
+                       glScalef(.25,.25,.25);
+                       glBegin(GL_QUADS);
+                       glTexCoord2f(0,0);
+                       glVertex3f(-1,          -1,      0.0f);
+                       glTexCoord2f(1,0);
+                       glVertex3f(1,   -1,      0.0f);
+                       glTexCoord2f(1,1);
+                       glVertex3f(1,   1, 0.0f);
+                       glTexCoord2f(0,1);
+                       glVertex3f(-1,  1, 0.0f);
+                       glEnd();
+                       glPopMatrix();
+                       glDisable(GL_TEXTURE_2D);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+                       glEnable(GL_CULL_FACE);
+                       glDisable(GL_BLEND);
+                       glDepthMask(1);*/
+
+                       //Awards
+                       int numawards;
+                       int awards[30];
+                       numawards=0;
+
+                       if(damagetaken==0&&player[0].bloodloss==0){
+                               awards[numawards]=awardflawless;
+                               numawards++;
+                       }
+                       bool alldead;
+                       alldead=1;
+                       if(numplayers>1)
+                               for(i=1;i<numplayers;i++){              
+                                       if(player[i].dead!=2)alldead=0;
+                               }
+                               if(alldead){
+                                       awards[numawards]=awardalldead;
+                                       numawards++;
+                               }
+                               alldead=1;
+                               if(numplayers>1)
+                                       for(i=1;i<numplayers;i++){              
+                                               if(player[i].dead!=1)alldead=0;
+                                       }
+                                       if(alldead){
+                                               awards[numawards]=awardnodead;
+                                               numawards++;
+                                       }
+                                       if(numresponded==0&&!numthrowkill){
+                                               awards[numawards]=awardstealth;
+                                               numawards++;
+                                       }
+                                       if(numattacks==numstaffattack&&numattacks>0){
+                                               awards[numawards]=awardbojutsu;
+                                               numawards++;
+                                       }
+                                       if(numattacks==numswordattack&&numattacks>0){
+                                               awards[numawards]=awardswordsman;
+                                               numawards++;
+                                       }
+                                       if(numattacks==numknifeattack&&numattacks>0){
+                                               awards[numawards]=awardknifefighter;
+                                               numawards++;
+                                       }
+                                       if(numattacks==numunarmedattack&&numthrowkill==0&&weapons.numweapons>0){
+                                               awards[numawards]=awardkungfu;
+                                               numawards++;
+                                       }
+                                       if(numescaped>0){
+                                               awards[numawards]=awardevasion;
+                                               numawards++;
+                                       }
+                                       if(numflipfail==0&&numflipped+numwallflipped*2>20){
+                                               awards[numawards]=awardacrobat;
+                                               numawards++;
+                                       }
+                                       if(numthrowkill==numplayers-1){
+                                               awards[numawards]=awardlongrange;
+                                               numawards++;
+                                       }
+                                       alldead=1;
+                                       if(numplayers>1)
+                                               for(i=1;i<numplayers;i++){              
+                                                       if(player[i].dead!=2)alldead=0;
+                                               }
+                                               if(numafterkill>0&&alldead){
+                                                       awards[numawards]=awardbrutal;
+                                                       numawards++;
+                                               }
+                                               if(numreversals>((float)numattacks)*.8&&numreversals>3){
+                                                       awards[numawards]=awardaikido;
+                                                       numawards++;
+                                               }
+                                               if(maxalarmed==1&&numplayers>2){
+                                                       awards[numawards]=awardstrategy;
+                                                       numawards++;
+                                               }
+                                               if(numflipfail>3){
+                                                       awards[numawards]=awardklutz;
+                                                       numawards++;
+                                               }
+
+
+                                               //Win Screen Won Victory
+
+                                               glEnable(GL_TEXTURE_2D);
+                                               glColor4f(1,1,1,1);
+                                               sprintf (string, "Level Cleared!");
+                                               text.glPrintOutlined(1024/2-strlen(string)*10,768*7/8,string,1,2,1024,768);
+
+                                               sprintf (string, "Score:     %d",(int)(bonustotal-startbonustotal));
+                                               text.glPrintOutlined(1024/30,768*6/8,string,1,2,1024,768);
+
+                                               if(!campaign)sprintf (string, "Press Escape to return to menu or Space to continue");
+                                               if(campaign)sprintf (string, "Press Escape or Space to continue");
+                                               text.glPrintOutlined(640/2-strlen(string)*5,480*1/16,string,1,1,640,480);
+
+                                               char temp[255];
+
+                                               for(i=0;i<255;i++)string[i]='\0';
+                                               sprintf (temp, "Time:      %d:",(int)(((int)leveltime-(int)(leveltime)%60)/60));
+                                               strcat(string,temp);
+                                               if((int)(leveltime)%60<10)strcat(string,"0");
+                                               sprintf (temp, "%d",(int)(leveltime)%60);
+                                               strcat(string,temp);
+                                               text.glPrintOutlined(1024/30,768*6/8-40,string,1,2,1024,768);
+
+                                               for(i=0;i<numawards;i++){
+                                                       if(i<6){
+                                                               if(awards[i]==awardklutz)sprintf (string, "Suicidal");
+                                                               if(awards[i]==awardflawless)sprintf (string, "Flawless!");
+                                                               if(awards[i]==awardalldead)sprintf (string, "Take no prisoners");
+                                                               if(awards[i]==awardnodead)sprintf (string, "Merciful");
+                                                               if(awards[i]==awardstealth)sprintf (string, "One with the shadows!");
+                                                               if(awards[i]==awardswordsman)sprintf (string, "Swordsman");
+                                                               if(awards[i]==awardkungfu)sprintf (string, "Unarmed!");
+                                                               if(awards[i]==awardknifefighter)sprintf (string, "Knife fighter");
+                                                               if(awards[i]==awardcoward)sprintf (string, "Coward");
+                                                               if(awards[i]==awardevasion)sprintf (string, "Escape artist");
+                                                               if(awards[i]==awardacrobat)sprintf (string, "Gymnast");
+                                                               if(awards[i]==awardlongrange)sprintf (string, "Blade slinger");
+                                                               if(awards[i]==awardbrutal)sprintf (string, "Brutal");
+                                                               if(awards[i]==awardhyper)sprintf (string, "Hyper");
+                                                               if(awards[i]==awardaikido)sprintf (string, "Aikido master!");
+                                                               if(awards[i]==awardrambo)sprintf (string, "Rambo");
+                                                               if(awards[i]==awardfast)sprintf (string, "Fast");
+                                                               if(awards[i]==awardrealfast)sprintf (string, "Real fast");
+                                                               if(awards[i]==awarddamnfast)sprintf (string, "Damn fast");
+                                                               if(awards[i]==awardstrategy)sprintf (string, "Divide and conquer");
+                                                               if(awards[i]==awardbojutsu)sprintf (string, "Bojutsu");
+                                                               text.glPrintOutlined(1024/30,768*6/8-90-40*i,string,1,2,1024,768);
+                                                       }
+                                               }
+
+                                               //drawmode=normalmode;
+               }
+
+               if(drawmode!=normalmode){
+                       glEnable(GL_TEXTURE_2D);
+                       //glFinish();
+                       if(!drawtoggle||drawmode!=realmotionblurmode||(drawtoggle==2||change==1)){
+                               if(screentexture){
+
+                                       glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
+                                       GLfloat subtractColor[4] = { 0.5, 0.5, 0.5, 0.0 };
+                                       glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, subtractColor);
+                                       //glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_SUBTRACT);
+                                       glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
+                                       glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_CONSTANT_EXT);
+                                       glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 2.0f);
+
+                                       glBindTexture( GL_TEXTURE_2D, screentexture);
+                                       glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texviewwidth, texviewheight);         
+                               }
+                       }
+                       if((drawtoggle||change==1)&&drawmode==realmotionblurmode){
+                               if(screentexture2){
+                                       glBindTexture( GL_TEXTURE_2D, screentexture2);
+                                       glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, texviewwidth, texviewheight);         
+                               }
+                               if(!screentexture2){
+                                       glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+                                       glGenTextures( 1, &screentexture2 );
+                                       glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+                                       glEnable(GL_TEXTURE_2D);
+                                       glBindTexture( GL_TEXTURE_2D, screentexture2);
+                                       glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+                                       glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+
+                                       glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, kTextureSize, kTextureSize, 0);                
+                               }
+                       }
+                       //glFlush();
+               }
+
+               glClear(GL_DEPTH_BUFFER_BIT);
+               ReSizeGLScene(90,.1f);
+               glViewport(0,0,screenwidth,screenheight);       
+
+               if(drawmode!=normalmode){
+                       glDisable(GL_DEPTH_TEST);
+                       if(drawmode==motionblurmode){
+                               glDrawBuffer(GL_FRONT);
+                               glReadBuffer(GL_BACK);
+                               //myassert(glGetError() == GL_NO_ERROR);
+                               //glFlush();
+                       }
+                       glColor3f (1.0, 1.0, 1.0); // no coloring
+
+                       glEnable(GL_TEXTURE_2D);
+                       glBindTexture( GL_TEXTURE_2D, screentexture);
+                       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+                       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                       glDisable(GL_CULL_FACE);
+                       glDisable(GL_LIGHTING);
+                       glDepthMask(0);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPushMatrix();                                                                         // Store The Projection Matrix
+                       glLoadIdentity();                                                                       // Reset The Projection Matrix
+                       glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPushMatrix();                                                                         // Store The Modelview Matrix
+                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                       glScalef((float)screenwidth/2,(float)screenheight/2,1);
+                       glTranslatef(1,1,0);
+                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       glEnable(GL_BLEND);
+                       if(drawmode==motionblurmode){
+                               if(motionbluramount<.2)motionbluramount=.2;
+                               //glColor4f(1,1,1,fast_sqrt(multiplier)*2.9*motionbluramount);
+                               glColor4f(1,1,1,motionbluramount);
+                               glPushMatrix();
+                               glBegin(GL_QUADS);
+                               glTexCoord2f(0,0);
+                               glVertex3f(-1,          -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,0);
+                               glVertex3f(1,   -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,texcoordheight);
+                               glVertex3f(1,   1, 0.0f);
+                               glTexCoord2f(0,texcoordheight);
+                               glVertex3f(-1,  1, 0.0f);
+                               glEnd();
+                               glPopMatrix();
+                       }
+                       if(drawmode==realmotionblurmode){
+                               glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+                               glClear(GL_COLOR_BUFFER_BIT);
+                               glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+                               glBindTexture( GL_TEXTURE_2D, screentexture);
+                               glColor4f(1,1,1,.5);
+                               glPushMatrix();
+                               glBegin(GL_QUADS);
+                               glTexCoord2f(0,0);
+                               glVertex3f(-1,          -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,0);
+                               glVertex3f(1,   -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,texcoordheight);
+                               glVertex3f(1,   1, 0.0f);
+                               glTexCoord2f(0,texcoordheight);
+                               glVertex3f(-1,  1, 0.0f);
+                               glEnd();
+                               glPopMatrix();
+                               glBindTexture( GL_TEXTURE_2D, screentexture2);
+                               glColor4f(1,1,1,.5);
+                               glPushMatrix();
+                               glBegin(GL_QUADS);
+                               glTexCoord2f(0,0);
+                               glVertex3f(-1,          -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,0);
+                               glVertex3f(1,   -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,texcoordheight);
+                               glVertex3f(1,   1, 0.0f);
+                               glTexCoord2f(0,texcoordheight);
+                               glVertex3f(-1,  1, 0.0f);
+                               glEnd();
+                               glPopMatrix();
+                               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       }
+                       if(drawmode==doublevisionmode){
+                               static float crosseyedness;
+                               crosseyedness=abs(player[0].damage-player[0].superpermanentdamage-(player[0].damagetolerance-player[0].superpermanentdamage)*1/2)/30;
+                               if(crosseyedness>1)crosseyedness=1;
+                               if(crosseyedness<0)crosseyedness=0;
+                               glColor4f(1,1,1,1);
+                               glDisable(GL_BLEND);
+                               glPushMatrix();
+                               glScalef(1,1,1);
+                               glBegin(GL_QUADS);
+                               glTexCoord2f(0,0);
+                               glVertex3f(-1,          -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,0);
+                               glVertex3f(1,   -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,texcoordheight);
+                               glVertex3f(1,   1, 0.0f);
+                               glTexCoord2f(0,texcoordheight);
+                               glVertex3f(-1,  1, 0.0f);
+                               glEnd();
+                               glPopMatrix();
+                               if(crosseyedness){
+                                       glColor4f(1,1,1,.5);
+                                       glEnable(GL_BLEND);
+                                       glPushMatrix();
+                                       glTranslatef(.015*crosseyedness,0,0);
+                                       glScalef(1,1,1);
+                                       glBegin(GL_QUADS);
+                                       glTexCoord2f(0,0);
+                                       glVertex3f(-1,          -1,      0.0f);
+                                       glTexCoord2f(texcoordwidth,0);
+                                       glVertex3f(1,   -1,      0.0f);
+                                       glTexCoord2f(texcoordwidth,texcoordheight);
+                                       glVertex3f(1,   1, 0.0f);
+                                       glTexCoord2f(0,texcoordheight);
+                                       glVertex3f(-1,  1, 0.0f);
+                                       glEnd();
+                                       glPopMatrix();
+                               }
+                       }
+                       if(drawmode==glowmode){
+                               glColor4f(.5,.5,.5,.5);
+                               glEnable(GL_BLEND);
+                               glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+                               glPushMatrix();
+                               glTranslatef(.01,0,0);
+                               glBegin(GL_QUADS);
+                               glTexCoord2f(0,0);
+                               glVertex3f(-1,          -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,0);
+                               glVertex3f(1,   -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,texcoordheight);
+                               glVertex3f(1,   1, 0.0f);
+                               glTexCoord2f(0,texcoordheight);
+                               glVertex3f(-1,  1, 0.0f);
+                               glEnd();
+                               glPopMatrix();
+                               glPushMatrix();
+                               glTranslatef(-.01,0,0);
+                               glBegin(GL_QUADS);
+                               glTexCoord2f(0,0);
+                               glVertex3f(-1,          -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,0);
+                               glVertex3f(1,   -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,texcoordheight);
+                               glVertex3f(1,   1, 0.0f);
+                               glTexCoord2f(0,texcoordheight);
+                               glVertex3f(-1,  1, 0.0f);
+                               glEnd();
+                               glPopMatrix();
+                               glPushMatrix();
+                               glTranslatef(.0,.01,0);
+                               glBegin(GL_QUADS);
+                               glTexCoord2f(0,0);
+                               glVertex3f(-1,          -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,0);
+                               glVertex3f(1,   -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,texcoordheight);
+                               glVertex3f(1,   1, 0.0f);
+                               glTexCoord2f(0,texcoordheight);
+                               glVertex3f(-1,  1, 0.0f);
+                               glEnd();
+                               glPopMatrix();
+                               glPushMatrix();
+                               glTranslatef(0,-.01,0);
+                               glBegin(GL_QUADS);
+                               glTexCoord2f(0,0);
+                               glVertex3f(-1,          -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,0);
+                               glVertex3f(1,   -1,      0.0f);
+                               glTexCoord2f(texcoordwidth,texcoordheight);
+                               glVertex3f(1,   1, 0.0f);
+                               glTexCoord2f(0,texcoordheight);
+                               glVertex3f(-1,  1, 0.0f);
+                               glEnd();
+                               glPopMatrix();
+                       }
+                       if(drawmode==radialzoommode){
+                               for(i=0;i<3;i++){
+                                       //glRotatef((float)i*.1,0,0,1);
+                                       glColor4f(1,1,1,1/((float)i+1));
+                                       glPushMatrix();
+                                       glScalef(1+(float)i*.01,1+(float)i*.01,1);
+                                       glBegin(GL_QUADS);
+                                       glTexCoord2f(0,0);
+                                       glVertex3f(-1,          -1,      0.0f);
+                                       glTexCoord2f(texcoordwidth,0);
+                                       glVertex3f(1,   -1,      0.0f);
+                                       glTexCoord2f(texcoordwidth,texcoordheight);
+                                       glVertex3f(1,   1, 0.0f);
+                                       glTexCoord2f(0,texcoordheight);
+                                       glVertex3f(-1,  1, 0.0f);
+                                       glEnd();
+                                       glPopMatrix();
+                               }
+                       }
+                       glDisable(GL_TEXTURE_2D);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+                       glEnable(GL_CULL_FACE);
+                       glDisable(GL_BLEND);
+                       glDepthMask(1);
+               }
+
+               if(console){
+                       glEnable(GL_TEXTURE_2D);
+                       glColor4f(1,1,1,1);
+                       if(console){
+                               int offset;
+                               offset=0;
+                               if(consoleselected>=60)offset=consoleselected-60;
+                               sprintf (string, " ]");
+                               text.glPrint(10,30,string,0,1,1024,768);
+                               if(consoleblink){
+                                       sprintf (string, "_");
+                                       text.glPrint(30+(float)(consoleselected)*10-offset*10,30,string,0,1,1024,768);
+                               }
+                               for(i=0;i<15;i++){
+                                       for(j=0;j<consolechars[i];j++){
+                                               glColor4f(1,1,1,1-(float)(i)/16);
+                                               if(j<consolechars[i]){
+                                                       sprintf (string, "%c",consoletext[i][j]);
+                                                       text.glPrint(30+j*10-offset*10,30+i*20,string,0,1,1024,768);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if(freeze||winfreeze||(mainmenu&&gameon)||(!gameon&&gamestarted)||(mainmenu&&gameon)||(!gameon&&gamestarted)||(!gameon&&gamestarted)){
+               multiplier=tempmult;
+       }
+
+       if(mainmenu){
+               glDrawBuffer(GL_BACK);
+               glReadBuffer(GL_BACK);
+               glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+               ReSizeGLScene(90,.1f);
+
+               int temptexdetail;
+               temptexdetail=texdetail;
+               if(texdetail>2)texdetail=2;
+               if(mainmenu!=oldmainmenu&&oldmainmenu!=0){
+                       if(mainmenu==1){
+                               LoadTexture(":Data:Textures:Newgame.png",&Mainmenuitems[1],0,0);
+                               LoadTexture(":Data:Textures:Quit.png",&Mainmenuitems[3],0,0);
+                               /*if(oldmainmenu==1||oldmainmenu==0){
+                               LoadTexture(":Data:Textures:World.png",&Mainmenuitems[7],0,0);
+                               LoadTexture(":Data:Textures:Options.png",&Mainmenuitems[2],0,0);
+                               LoadTexture(":Data:Textures:Lugaru.png",&Mainmenuitems[0],0,0);
+                               loaddistrib=0;
+                               }*/
+                       }
+                       if(mainmenu==2){
+                               LoadTexture(":Data:Textures:Resume.png",&Mainmenuitems[1],0,0);
+                               LoadTexture(":Data:Textures:Endgame.png",&Mainmenuitems[3],0,0);
+                               /*if(oldmainmenu==2||oldmainmenu==0){
+                               LoadTexture(":Data:Textures:World.png",&Mainmenuitems[7],0,0);
+                               LoadTexture(":Data:Textures:Options.png",&Mainmenuitems[2],0,0);
+                               LoadTexture(":Data:Textures:Lugaru.png",&Mainmenuitems[0],0,0);
+                               loaddistrib=0;
+                               }*/
+                       }
+               }
+               if(lastcheck>.5||oldmainmenu!=mainmenu){
+                       if(mainmenu==5){
+                               //                              ifstream ipstream(":Data:Campaigns:main.txt");  
+                               ifstream ipstream("./Data/Campaigns/main.txt"); 
+                               //campaignnumlevels=0;
+                               //accountcampaignchoicesmade[accountactive]=0;
+                               ipstream.ignore(256,':');
+                               ipstream >> campaignnumlevels;
+                               for(i=0;i<campaignnumlevels;i++){
+                                       ipstream.ignore(256,':');
+                                       ipstream.ignore(256,':');
+                                       ipstream.ignore(256,' ');
+                                       ipstream >> campaignmapname[i];
+                                       ipstream.ignore(256,':');
+                                       ipstream >> campaigndescription[i];
+                                       for(j=0;j<256;j++){
+                                               if(campaigndescription[i][j]=='_')campaigndescription[i][j]=' ';
+                                       }
+                                       ipstream.ignore(256,':');
+                                       ipstream >> campaignchoosenext[i];
+                                       ipstream.ignore(256,':');
+                                       ipstream >> campaignnumnext[i];
+                                       if(campaignnumnext[i])
+                                               for(j=0;j<campaignnumnext[i];j++){
+                                                       ipstream.ignore(256,':');
+                                                       ipstream >> campaignnextlevel[i][j];
+                                                       campaignnextlevel[i][j]-=1;
+                                               }
+                                               ipstream.ignore(256,':');
+                                               ipstream >> campaignlocationx[i];
+                                               //campaignlocationx[i]-=30;
+                                               ipstream.ignore(256,':');
+                                               ipstream >> campaignlocationy[i];
+                                               //campaignlocationy[i]+=30;
+                               }
+                               ipstream.close();
+
+                               for(i=0;i<campaignnumlevels;i++){
+                                       levelvisible[i]=0;
+                                       levelhighlight[i]=0;
+                               }
+
+                               levelorder[0]=0;
+                               levelvisible[0]=1;
+                               if(accountcampaignchoicesmade[accountactive])
+                                       for(i=0;i<accountcampaignchoicesmade[accountactive];i++){
+                                               levelorder[i+1]=campaignnextlevel[levelorder[i]][accountcampaignchoices[accountactive][i]];
+                                               levelvisible[levelorder[i+1]]=1;
+                                       }
+                                       int whichlevelstart;
+                                       whichlevelstart=accountcampaignchoicesmade[accountactive]-1;
+                                       if(whichlevelstart<0){
+                                               accountcampaignscore[accountactive]=0;
+                                               accountcampaignfasttime[accountactive]=0;
+                                               campaignchoicenum=1;
+                                               campaignchoicewhich[0]=0;
+                                       }
+                                       else
+                                       {
+                                               campaignchoicenum=campaignnumnext[levelorder[whichlevelstart]];
+                                               if(campaignchoicenum==0){
+                                                       if(accountcampaignscore[accountactive]>accountcampaignhighscore[accountactive])accountcampaignhighscore[accountactive]=accountcampaignscore[accountactive];
+                                                       if(accountcampaignfasttime[accountactive]==0||accountcampaigntime[accountactive]<accountcampaignfasttime[accountactive])accountcampaignfasttime[accountactive]=accountcampaigntime[accountactive];              
+                                               }
+                                               if(campaignchoicenum)
+                                                       for(i=0;i<campaignchoicenum;i++){
+                                                               campaignchoicewhich[i]=campaignnextlevel[levelorder[whichlevelstart]][i];
+                                                               levelvisible[campaignnextlevel[levelorder[whichlevelstart]][i]]=1;
+                                                               levelhighlight[campaignnextlevel[levelorder[whichlevelstart]][i]]=1;
+                                                       }
+                                       }
+                                       /*levelorder[0]=0;
+                                       levelorder[1]=1;
+                                       levelorder[2]=2;
+                                       levelorder[3]=3;*/
+                       }
+               }
+               if(mainmenu==5){
+                       lastcheck=0;
+               }
+
+               texdetail=temptexdetail;
+
+               /*if(mainmenu!=0)*/oldmainmenu=mainmenu;
+
+               if(mainmenu==3||mainmenu==4||mainmenu==5||mainmenu==6||mainmenu==7||mainmenu==8||mainmenu==9||mainmenu==10||mainmenu==119||mainmenu==12||mainmenu==13||mainmenu==14||mainmenu==15||mainmenu==16||mainmenu==17){
+                       glClear(GL_DEPTH_BUFFER_BIT);
+                       glEnable(GL_ALPHA_TEST);
+                       glAlphaFunc(GL_GREATER, 0.001f);
+                       glEnable(GL_TEXTURE_2D);
+                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                       glDisable(GL_CULL_FACE);
+                       glDisable(GL_LIGHTING);
+                       glDepthMask(0);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPushMatrix();                                                                         // Store The Projection Matrix
+                               glLoadIdentity();                                                                       // Reset The Projection Matrix
+                               glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                       glPushMatrix();                                                                         // Store The Modelview Matrix
+                                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                                       glTranslatef(screenwidth/2,screenheight/2,0);
+                                       glPushMatrix();
+                                               glScalef((float)screenwidth/2,(float)screenheight/2,1);
+                                               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                                               glDisable(GL_BLEND);
+                                               glColor4f(0,0,0,1.0);
+                                               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
+                                               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
+                                               glDisable(GL_TEXTURE_2D);
+                                               glPushMatrix();
+                                                       //glScalef(.25,.25,.25);
+                                                       glBegin(GL_QUADS);
+                                                       glTexCoord2f(0,0);
+                                                       glVertex3f(-1,          -1,      0.0f);
+                                                       glTexCoord2f(1,0);
+                                                       glVertex3f(1,   -1,      0.0f);
+                                                       glTexCoord2f(1,1);
+                                                       glVertex3f(1,   1, 0.0f);
+                                                       glTexCoord2f(0,1);
+                                                       glVertex3f(-1,  1, 0.0f);
+                                                       glEnd();
+                                               glPopMatrix();
+                                               glEnable(GL_BLEND);
+                                               glColor4f(0.4,0.4,0.4,1.0);
+                                               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
+                                               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
+                                               glEnable(GL_TEXTURE_2D);
+                                               glBindTexture( GL_TEXTURE_2D, Mainmenuitems[4]);
+                                               glPushMatrix();
+                                                       //glScalef(.25,.25,.25);
+                                                       glBegin(GL_QUADS);
+                                                       glTexCoord2f(0,0);
+                                                       glVertex3f(-1,          -1,      0.0f);
+                                                       glTexCoord2f(1,0);
+                                                       glVertex3f(1,   -1,      0.0f);
+                                                       glTexCoord2f(1,1);
+                                                       glVertex3f(1,   1, 0.0f);
+                                                       glTexCoord2f(0,1);
+                                                       glVertex3f(-1,  1, 0.0f);
+                                                       glEnd();
+                                               glPopMatrix();
+                                       glPopMatrix();
+                               glPopMatrix();
+                               glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPopMatrix();
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+
+                       if(mainmenu==3){                        
+                               nummenuitems=12;
+                               if((float)newscreenwidth>(float)newscreenheight*1.61||(float)newscreenwidth<(float)newscreenheight*1.59)sprintf (menustring[0], "Resolution: %d*%d",(int)newscreenwidth,(int)newscreenheight);
+                               else sprintf (menustring[0], "Resolution: %d*%d (widescreen)",(int)newscreenwidth,(int)newscreenheight);
+                               startx[0]=10+20;
+                               starty[0]=440;
+                               endx[0]=startx[0]+strlen(menustring[0])*10;
+                               endy[0]=starty[0]+20;
+                               movex[0]=0;
+                               movey[0]=0;
+
+                               if(newdetail==2)sprintf (menustring[1], "Detail: High");
+                               else if(newdetail==1)sprintf (menustring[1], "Detail: Medium");
+                               else sprintf (menustring[1], "Detail: Low");
+                               startx[1]=10+60;
+                               starty[1]=405;
+                               endx[1]=startx[1]+strlen(menustring[1])*10;
+                               endy[1]=starty[1]+20;
+                               movex[1]=0;
+                               movey[1]=0;
+
+                               if(bloodtoggle==2)sprintf (menustring[2], "Blood: On, high detail (slower)");
+                               if(bloodtoggle==1)sprintf (menustring[2], "Blood: On, low detail");
+                               if(bloodtoggle==0)sprintf (menustring[2], "Blood: Off");
+                               startx[2]=10+70;
+                               starty[2]=370;
+                               endx[2]=startx[2]+strlen(menustring[2])*10;
+                               endy[2]=starty[2]+20;
+                               movex[2]=0;
+                               movey[2]=0;
+
+                               if(difficulty==2)sprintf (menustring[3], "Difficulty: Insane");
+                               if(difficulty==1)sprintf (menustring[3], "Difficulty: Difficult");
+                               if(difficulty==0)sprintf (menustring[3], "Difficulty: Easier");
+                               startx[3]=10+20-1000;
+                               starty[3]=335-1000;
+                               endx[3]=startx[3]+strlen(menustring[3])*10;
+                               endy[3]=starty[3]+20;
+                               movex[3]=0;
+                               movey[3]=0;
+
+                               if(ismotionblur==1)sprintf (menustring[4], "Blur Effects: Enabled (less compatible)");
+                               if(ismotionblur==0)sprintf (menustring[4], "Blur Effects: Disabled (more compatible)");
+                               startx[4]=10;
+                               starty[4]=335;
+                               endx[4]=startx[4]+strlen(menustring[4])*10;
+                               endy[4]=starty[4]+20;
+                               movex[4]=0;
+                               movey[4]=0;
+
+                               if(decals==1)sprintf (menustring[5], "Decals: Enabled (slower)");
+                               if(decals==0)sprintf (menustring[5], "Decals: Disabled");
+                               startx[5]=10+60;
+                               starty[5]=300;
+                               endx[5]=startx[5]+strlen(menustring[5])*10;
+                               endy[5]=starty[5]+20;
+                               movex[5]=0;
+                               movey[5]=0;
+
+                               if(musictoggle==1)sprintf (menustring[6], "Music: Enabled");
+                               if(musictoggle==0)sprintf (menustring[6], "Music: Disabled");
+                               startx[6]=10+70;
+                               starty[6]=265;
+                               endx[6]=startx[6]+strlen(menustring[6])*10;
+                               endy[6]=starty[6]+20;
+                               movex[6]=0;
+                               movey[6]=0;
+
+                               if(invertmouse==1)sprintf (menustring[9], "Invert mouse: Yes");
+                               if(invertmouse==0)sprintf (menustring[9], "Invert mouse: No");
+                               startx[9]=10;
+                               starty[9]=230;
+                               endx[9]=startx[9]+strlen(menustring[9])*10;
+                               endy[9]=starty[9]+20;
+                               movex[9]=0;
+                               movey[9]=0;
+
+                               sprintf (menustring[10], "Mouse Speed: %d", (int)(usermousesensitivity*5));
+                               startx[10]=20;
+                               starty[10]=195;
+                               endx[10]=startx[10]+strlen(menustring[10])*10;
+                               endy[10]=starty[10]+20;
+                               movex[10]=0;
+                               movey[10]=0;
+                               
+                               sprintf (menustring[11], "Volume: %d%", (int)(volume*100));
+                               startx[11]=10+60;
+                               starty[11]=155;
+                               endx[11]=startx[11]+strlen(menustring[11])*10;
+                               endy[11]=starty[11]+20;
+                               movex[11]=0;
+                               movey[11]=0;
+                               
+                               sprintf (menustring[7], "-Configure Controls-");
+                               startx[7]=10+15;
+                               starty[7]=100;
+                               endx[7]=startx[7]+strlen(menustring[7])*10;
+                               endy[7]=starty[7]+20;
+                               movex[7]=0;
+                               movey[7]=0;
+
+                               if(newdetail==detail&&newscreenheight==(int)screenheight&&newscreenwidth==(int)screenwidth)sprintf (menustring[8], "Back");
+                               else sprintf (menustring[8], "Back (some changes take effect next time Lugaru is opened)");
+                               startx[8]=10;
+                               endx[8]=startx[8]+strlen(menustring[8])*10;
+                               starty[8]=10;
+                               endy[8]=starty[8]+20;
+                               movex[8]=0;
+                               movey[8]=0;
+                       }
+
+                       if(mainmenu==4){                        
+                               nummenuitems=10;
+                               if(keyselect!=0)sprintf (menustring[0], "Forwards: %s",KeyToChar(forwardkey));
+                               else sprintf (menustring[0], "Forwards: _");
+                               startx[0]=10;
+                               starty[0]=400;
+                               endx[0]=startx[0]+strlen(menustring[0])*10;
+                               endy[0]=starty[0]+20;
+                               movex[0]=0;
+                               movey[0]=0;
+
+                               if(keyselect!=1)sprintf (menustring[1], "Back: %s",KeyToChar(backkey));
+                               else sprintf (menustring[1], "Back: _");
+                               startx[1]=10+40;
+                               starty[1]=360;
+                               endx[1]=startx[1]+strlen(menustring[1])*10;
+                               endy[1]=starty[1]+20;
+                               movex[1]=0;
+                               movey[1]=0;
+
+                               if(keyselect!=2)sprintf (menustring[2], "Left: %s",KeyToChar(leftkey));
+                               else sprintf (menustring[2], "Left: _");
+                               startx[2]=10+40;
+                               starty[2]=320;
+                               endx[2]=startx[2]+strlen(menustring[2])*10;
+                               endy[2]=starty[2]+20;
+                               movex[2]=0;
+                               movey[2]=0;
+
+                               if(keyselect!=3)sprintf (menustring[3], "Right: %s",KeyToChar(rightkey));
+                               else sprintf (menustring[3], "Right: _");
+                               startx[3]=10+30;
+                               starty[3]=280;
+                               endx[3]=startx[3]+strlen(menustring[3])*10;
+                               endy[3]=starty[3]+20;
+                               movex[3]=0;
+                               movey[3]=0;
+
+                               if(keyselect!=4)sprintf (menustring[4], "Crouch: %s",KeyToChar(crouchkey));
+                               else sprintf (menustring[4], "Crouch: _");
+                               startx[4]=10+20;
+                               starty[4]=240;
+                               endx[4]=startx[4]+strlen(menustring[4])*10;
+                               endy[4]=starty[4]+20;
+                               movex[4]=0;
+                               movey[4]=0;
+
+                               if(keyselect!=5)sprintf (menustring[5], "Jump: %s",KeyToChar(jumpkey));
+                               else sprintf (menustring[5], "Jump: _");
+                               startx[5]=10+40;
+                               starty[5]=200;
+                               endx[5]=startx[5]+strlen(menustring[5])*10;
+                               endy[5]=starty[5]+20;
+                               movex[5]=0;
+                               movey[5]=0;
+
+                               if(keyselect!=6)sprintf (menustring[6], "Draw: %s",KeyToChar(drawkey));
+                               else sprintf (menustring[6], "Draw: _");
+                               startx[6]=10+40;
+                               starty[6]=160;
+                               endx[6]=startx[6]+strlen(menustring[6])*10;
+                               endy[6]=starty[6]+20;
+                               movex[6]=0;
+                               movey[6]=0;
+
+                               if(keyselect!=7)sprintf (menustring[7], "Throw: %s",KeyToChar(throwkey));
+                               else sprintf (menustring[7], "Throw: _");
+                               startx[7]=10+30;
+                               starty[7]=120;
+                               endx[7]=startx[7]+strlen(menustring[7])*10;
+                               endy[7]=starty[7]+20;
+                               movex[7]=0;
+                               movey[7]=0;
+
+                               if(keyselect!=8)sprintf (menustring[8], "Attack: %s",KeyToChar(attackkey));
+                               else sprintf (menustring[8], "Attack: _");
+                               startx[8]=10+20;
+                               starty[8]=80;
+                               endx[8]=startx[8]+strlen(menustring[8])*10;
+                               endy[8]=starty[8]+20;
+                               movex[8]=0;
+                               movey[8]=0;
+
+
+
+                               sprintf (menustring[9], "Back");
+                               startx[9]=10;
+                               endx[9]=startx[9]+strlen(menustring[9])*10;
+                               starty[9]=10;
+                               endy[9]=starty[9]+20;
+                               movex[9]=0;
+                               movey[9]=0;
+                       }
+                       if(mainmenu==5){                        
+                               nummenuitems=7+accountcampaignchoicesmade[accountactive]+campaignchoicenum;
+
+                               sprintf (menustring[0], "%s",accountname[accountactive]);
+                               startx[0]=5;
+                               starty[0]=400;
+                               endx[0]=startx[0]+strlen(menustring[0])*10;
+                               endy[0]=starty[0]+20;
+                               movex[0]=0;
+                               movey[0]=0;
+
+                               sprintf (menustring[1], "Tutorial");
+                               startx[1]=5;
+                               starty[1]=300;
+                               endx[1]=startx[1]+strlen(menustring[1])*10;
+                               endy[1]=starty[1]+20;
+                               movex[1]=0;
+                               movey[1]=0;
+
+                               sprintf (menustring[2], "Challenge");
+                               startx[2]=5;
+                               starty[2]=240;
+                               endx[2]=startx[2]+strlen(menustring[2])*10;
+                               endy[2]=starty[2]+20;
+                               movex[2]=0;
+                               movey[2]=0;
+
+                               sprintf (menustring[3], "Delete User");
+                               startx[3]=400;
+                               starty[3]=10;
+                               endx[3]=startx[3]+strlen(menustring[3])*10;
+                               endy[3]=starty[3]+20;
+                               movex[3]=0;
+                               movey[3]=0;
+
+                               sprintf (menustring[4], "Main Menu");
+                               startx[4]=5;
+                               starty[4]=10;
+                               endx[4]=startx[4]+strlen(menustring[4])*10;
+                               endy[4]=starty[4]+20;
+                               movex[4]=0;
+                               movey[4]=0;
+
+                               sprintf (menustring[5], "Change User");
+                               startx[5]=5;
+                               endx[5]=startx[5]+strlen(menustring[5])*10;
+                               starty[5]=180;
+                               endy[5]=starty[5]+20;
+                               movex[5]=0;
+                               movey[5]=0;
+
+                               //World
+
+                               sprintf (menustring[6], "World");
+                               startx[6]=30+120;
+                               starty[6]=30+480-400-50;
+                               endx[6]=startx[6]+400;
+                               endy[6]=30+480-50;
+                               movex[6]=0;
+                               movey[6]=0;
+
+                               if(accountcampaignchoicesmade[accountactive])
+                                       for(i=0;i<accountcampaignchoicesmade[accountactive];i++){
+                                               sprintf (menustring[7+i], campaigndescription[levelorder[i]]);
+                                               startx[7+i]=30+120+campaignlocationx[levelorder[i]]*400/512;
+                                               starty[7+i]=30+30+(512-campaignlocationy[levelorder[i]])*400/512;
+                                               endx[7+i]=startx[7+i]+10;
+                                               endy[7+i]=starty[7+i]+10;
+                                               movex[7+i]=0;
+                                               movey[7+i]=0;
+                                       }
+
+                                       if(campaignchoicenum>0)
+                                               for(i=accountcampaignchoicesmade[accountactive];i<accountcampaignchoicesmade[accountactive]+campaignchoicenum;i++){
+                                                       sprintf (menustring[7+i], campaigndescription[levelorder[i]]);
+                                                       startx[7+i]=30+120+campaignlocationx[campaignchoicewhich[i-(accountcampaignchoicesmade[accountactive])]]*400/512;
+                                                       starty[7+i]=30+30+(512-campaignlocationy[campaignchoicewhich[i-(accountcampaignchoicesmade[accountactive])]])*400/512;
+                                                       endx[7+i]=startx[7+i]+10;
+                                                       endy[7+i]=starty[7+i]+10;
+                                                       movex[7+i]=0;
+                                                       movey[7+i]=0;
+                                               }
+
+                                               /*sprintf (menustring[7], "Dot");
+                                               startx[7]=120+260*400/512;
+                                               starty[7]=30+(512-184)*400/512;
+                                               endx[7]=startx[7]+10;
+                                               endy[7]=starty[7]+10;
+                                               movex[7]=0;
+                                               movey[7]=0;
+
+                                               sprintf (menustring[8], "Dot");
+                                               startx[8]=120+129*400/512;
+                                               starty[8]=30+(512-284)*400/512;
+                                               endx[8]=startx[8]+10;
+                                               endy[8]=starty[8]+10;
+                                               movex[8]=0;
+                                               movey[8]=0;
+
+                                               sprintf (menustring[9], "Dot");
+                                               startx[9]=120+358*400/512;
+                                               starty[9]=30+(512-235)*400/512;
+                                               endx[9]=startx[9]+10;
+                                               endy[9]=starty[9]+10;
+                                               movex[9]=0;
+                                               movey[9]=0;
+
+                                               sprintf (menustring[10], "Dot");
+                                               startx[10]=120+359*400/512;
+                                               starty[10]=30+(512-308)*400/512;
+                                               endx[10]=startx[10]+10;
+                                               endy[10]=starty[10]+10;
+                                               movex[10]=0;
+                                               movey[10]=0;
+
+                                               sprintf (menustring[11], "Dot");
+                                               startx[11]=120+288*400/512;
+                                               starty[11]=30+(512-277)*400/512;
+                                               endx[11]=startx[11]+10;
+                                               endy[11]=starty[11]+10;
+                                               movex[11]=0;
+                                               movey[11]=0;*/
+                       }
+
+                       if(mainmenu==6){                        
+                               nummenuitems=3;
+
+                               sprintf (menustring[0], "Are you sure you want to delete this user?");
+                               startx[0]=10;
+                               starty[0]=400;
+                               endx[0]=startx[0]+strlen(menustring[0])*10;
+                               endy[0]=starty[0]+20;
+                               movex[0]=0;
+                               movey[0]=0;
+
+                               sprintf (menustring[1], "Yes");
+                               startx[1]=10;
+                               starty[1]=360;
+                               endx[1]=startx[1]+strlen(menustring[1])*10;
+                               endy[1]=starty[1]+20;
+                               movex[1]=0;
+                               movey[1]=0;
+
+                               sprintf (menustring[2], "No");
+                               startx[2]=10;
+                               starty[2]=320;
+                               endx[2]=startx[2]+strlen(menustring[2])*10;
+                               endy[2]=starty[2]+20;
+                               movex[2]=0;
+                               movey[2]=0;
+
+                               sprintf (menustring[3], "Extra 4");
+                               startx[3]=10;
+                               starty[3]=280;
+                               endx[3]=startx[3]+strlen(menustring[3])*10;
+                               endy[3]=starty[3]+20;
+                               movex[3]=0;
+                               movey[3]=0;
+
+                               sprintf (menustring[4], "Extra 5");
+                               startx[4]=10;
+                               starty[4]=240;
+                               endx[4]=startx[4]+strlen(menustring[4])*10;
+                               endy[4]=starty[4]+20;
+                               movex[4]=0;
+                               movey[4]=0;
+
+                               sprintf (menustring[5], "Back");
+                               startx[5]=10;
+                               endx[5]=startx[5]+strlen(menustring[5])*10;
+                               starty[5]=10;
+                               endy[5]=starty[5]+20;
+                               movex[5]=0;
+                               movey[5]=0;
+                       }
+
+                       if(mainmenu==7){                        
+                               nummenuitems=numaccounts+2;
+
+                               int num;
+
+                               if(numaccounts<8)
+                                       sprintf (menustring[0], "New User");
+                               else
+                                       sprintf (menustring[0], "No More Users");
+                               startx[0]=10;
+                               starty[0]=400;
+                               endx[0]=startx[0]+strlen(menustring[0])*10;
+                               endy[0]=starty[0]+20;
+                               movex[0]=0;
+                               movey[0]=0;
+
+                               if(entername)startx[0]+=10;
+
+
+                               num=1;
+                               if(numaccounts)
+                                       for(i=0;i<numaccounts;i++){
+                                               sprintf (menustring[num], "%s",accountname[i]);
+                                               startx[num]=10;
+                                               starty[num]=360-20-20*num;
+                                               endx[num]=startx[num]+strlen(menustring[num])*10;
+                                               endy[num]=starty[num]+20;
+                                               movex[num]=0;
+                                               movey[num]=0;
+
+                                               num++;
+                                       }
+
+                                       sprintf (menustring[num], "Back");
+                                       startx[num]=10;
+                                       endx[num]=startx[num]+strlen(menustring[num])*10;
+                                       starty[num]=10;
+                                       endy[num]=starty[num]+20;
+                                       movex[num]=0;
+                                       movey[num]=0;
+                       }
+                       if(mainmenu==8){                        
+                               nummenuitems=3;
+
+                               sprintf (menustring[0], "Easier");
+                               startx[0]=10;
+                               starty[0]=400;
+                               endx[0]=startx[0]+strlen(menustring[0])*10;
+                               endy[0]=starty[0]+20;
+                               movex[0]=0;
+                               movey[0]=0;
+
+                               sprintf (menustring[1], "Difficult");
+                               startx[1]=10;
+                               starty[1]=360;
+                               endx[1]=startx[1]+strlen(menustring[1])*10;
+                               endy[1]=starty[1]+20;
+                               movex[1]=0;
+                               movey[1]=0;
+
+                               sprintf (menustring[2], "Insane");
+                               startx[2]=10;
+                               starty[2]=320;
+                               endx[2]=startx[2]+strlen(menustring[2])*10;
+                               endy[2]=starty[2]+20;
+                               movex[2]=0;
+                               movey[2]=0;
+                       }
+                       if(mainmenu==9){                        
+                               int tempncl;
+                               //tempncl=numchallengelevels;
+                               //numchallengelevels=9;
+                               nummenuitems=2+numchallengelevels;
+                               char temp[255];
+
+                               for(j=0;j<numchallengelevels;j++){
+                                       for(i=0;i<255;i++)menustring[j][i]='\0';
+                                       sprintf (temp, "Level %d",j+1);
+                                       strcpy(menustring[j],temp);
+                                       for(i=0;i<17;i++)if(menustring[j][i]=='\0')menustring[j][i]=' ';
+                                       menustring[j][17]='\0';
+                                       sprintf (temp, "%d",(int)accounthighscore[accountactive][j]);
+                                       strcat(menustring[j],temp);
+                                       for(i=18;i<32;i++)if(menustring[j][i]=='\0')menustring[j][i]=' ';
+                                       menustring[j][32]='\0';
+                                       sprintf (temp, "%d:",(int)(((int)accountfasttime[accountactive][j]-(int)(accountfasttime[accountactive][j])%60)/60));
+                                       strcat(menustring[j],temp);
+                                       if((int)(accountfasttime[accountactive][j])%60<10)strcat(menustring[j],"0");
+                                       sprintf (temp, "%d",(int)(accountfasttime[accountactive][j])%60);
+                                       strcat(menustring[j],temp);
+
+                                       startx[j]=10;
+                                       starty[j]=400-j*25;
+                                       endx[j]=startx[j]+strlen(menustring[j])*10;
+                                       endy[j]=starty[j]+20;
+                                       movex[j]=0;
+                                       movey[j]=0;
+                               }
+
+                               sprintf (menustring[numchallengelevels], "Back");
+                               startx[numchallengelevels]=10;
+                               endx[numchallengelevels]=startx[numchallengelevels]+strlen(menustring[numchallengelevels])*10;
+                               starty[numchallengelevels]=10;
+                               endy[numchallengelevels]=starty[numchallengelevels]+20;
+                               movex[numchallengelevels]=0;
+                               movey[numchallengelevels]=0;
+
+                               sprintf (menustring[numchallengelevels+1], "             High Score      Best Time");
+                               startx[numchallengelevels+1]=10;
+                               starty[numchallengelevels+1]=440;
+                               endx[numchallengelevels+1]=startx[numchallengelevels+1]+strlen(menustring[numchallengelevels+1])*10;
+                               endy[numchallengelevels+1]=starty[numchallengelevels+1]+20;
+                               movex[numchallengelevels+1]=0;
+                               movey[numchallengelevels+1]=0;
+
+                               //numchallengelevels=tempncl;
+
+                       }
+                       if(mainmenu==11){                       
+                               nummenuitems=2+numchallengelevels;
+                               char temp[255];
+
+                               for(j=0;j<numchallengelevels;j++){
+                                       for(i=0;i<255;i++)menustring[j][i]='\0';
+                                       sprintf (temp, "Level %d",j+1);
+                                       strcpy(menustring[j],temp);
+                                       for(i=0;i<17;i++)if(menustring[j][i]=='\0')menustring[j][i]=' ';
+                                       menustring[j][17]='\0';
+                                       sprintf (temp, "%d",(int)accounthighscore[accountactive][j]);
+                                       strcat(menustring[j],temp);
+                                       for(i=18;i<32;i++)if(menustring[j][i]=='\0')menustring[j][i]=' ';
+                                       menustring[j][32]='\0';
+                                       sprintf (temp, "%d:",(int)(((int)accountfasttime[accountactive][j]-(int)(accountfasttime[accountactive][j])%60)/60));
+                                       strcat(menustring[j],temp);
+                                       if((int)(accountfasttime[accountactive][j])%60<10)strcat(menustring[j],"0");
+                                       sprintf (temp, "%d",(int)(accountfasttime[accountactive][j])%60);
+                                       strcat(menustring[j],temp);
+
+                                       startx[j]=10;
+                                       starty[j]=360-j*40;
+                                       endx[j]=startx[j]+strlen(menustring[j])*10;
+                                       endy[j]=starty[j]+20;
+                                       movex[j]=0;
+                                       movey[j]=0;
+                               }
+
+                               sprintf (menustring[numchallengelevels], "Back");
+                               startx[numchallengelevels]=10;
+                               endx[numchallengelevels]=startx[numchallengelevels]+strlen(menustring[numchallengelevels])*10;
+                               starty[numchallengelevels]=10;
+                               endy[numchallengelevels]=starty[numchallengelevels]+20;
+                               movex[numchallengelevels]=0;
+                               movey[numchallengelevels]=0;
+
+                               sprintf (menustring[numchallengelevels+1], "             High Score      Best Time");
+                               startx[numchallengelevels+1]=10;
+                               starty[numchallengelevels+1]=400;
+                               endx[numchallengelevels+1]=startx[numchallengelevels+1]+strlen(menustring[numchallengelevels+1])*10;
+                               endy[numchallengelevels+1]=starty[numchallengelevels+1]+20;
+                               movex[numchallengelevels+1]=0;
+                               movey[numchallengelevels+1]=0;
+
+                       }
+                       if(mainmenu==10){                       
+                               nummenuitems=6;
+                               char temp[255];
+
+                               sprintf (menustring[0], "Congratulations!");
+                               startx[0]=220;
+                               starty[0]=330;
+                               endx[0]=startx[0]+strlen(menustring[0])*10;
+                               endy[0]=starty[0]+20;
+                               movex[0]=0;
+                               movey[0]=0;
+
+                               sprintf (menustring[1], "You have avenged your family and");
+                               startx[1]=140;
+                               starty[1]=300;
+                               endx[1]=startx[1]+strlen(menustring[1])*10;
+                               endy[1]=starty[1]+20;
+                               movex[1]=0;
+                               movey[1]=0;
+
+                               sprintf (menustring[2], "restored peace to the island of Lugaru.");
+                               startx[2]=110;
+                               starty[2]=270;
+                               endx[2]=startx[2]+strlen(menustring[2])*10;
+                               endy[2]=starty[2]+20;
+                               movex[2]=0;
+                               movey[2]=0;
+
+                               sprintf (menustring[3], "Back");
+                               startx[3]=10;
+                               endx[3]=startx[3]+strlen(menustring[3])*10;
+                               starty[3]=10;
+                               endy[3]=starty[3]+20;
+                               movex[3]=0;
+                               movey[3]=0;
+
+                               for(i=0;i<255;i++)menustring[4][i]='\0';
+                               sprintf (temp, "Your score:");
+                               strcpy(menustring[4],temp);
+                               for(i=0;i<20;i++)if(menustring[4][i]=='\0')menustring[4][i]=' ';
+                               menustring[4][20]='\0';
+                               sprintf (temp, "%d",(int)accountcampaignscore[accountactive]);
+                               strcat(menustring[4],temp);
+                               startx[4]=190;
+                               endx[4]=startx[4]+strlen(menustring[4])*10;
+                               starty[4]=200;
+                               endy[4]=starty[4]+20;
+                               movex[4]=0;
+                               movey[4]=0;
+                               /*
+                               for(i=0;i<255;i++)menustring[5][i]='\0';
+                               sprintf (temp, "Your time:");
+                               strcpy(menustring[5],temp);
+                               for(i=0;i<20;i++)if(menustring[5][i]=='\0')menustring[5][i]=' ';
+                               menustring[5][20]='\0';
+                               sprintf (temp, "%d",(int)accountcampaigntime[accountactive]);
+                               strcat(menustring[5],temp);
+                               startx[5]=200;
+                               endx[5]=startx[5]+strlen(menustring[5])*10;
+                               starty[5]=180;
+                               endy[5]=starty[5]+20;
+                               movex[5]=0;
+                               movey[5]=0;
+                               */
+                               for(i=0;i<255;i++)menustring[5][i]='\0';
+                               sprintf (temp, "Highest score:");
+                               strcpy(menustring[5],temp);
+                               for(i=0;i<20;i++)if(menustring[5][i]=='\0')menustring[5][i]=' ';
+                               menustring[5][20]='\0';
+                               sprintf (temp, "%d",(int)accountcampaignhighscore[accountactive]);
+                               strcat(menustring[5],temp);
+                               startx[5]=190;
+                               endx[5]=startx[5]+strlen(menustring[5])*10;
+                               starty[5]=180;
+                               endy[5]=starty[5]+20;
+                               movex[5]=0;
+                               movey[5]=0;
+                               /*
+                               for(i=0;i<255;i++)menustring[7][i]='\0';
+                               sprintf (temp, "Lowest time:");
+                               strcpy(menustring[7],temp);
+                               for(i=0;i<20;i++)if(menustring[7][i]=='\0')menustring[7][i]=' ';
+                               menustring[7][20]='\0';
+                               sprintf (temp, "%d",(int)accountcampaignfasttime[accountactive]);
+                               strcat(menustring[7],temp);
+                               startx[7]=200;
+                               endx[7]=startx[7]+strlen(menustring[7])*10;
+                               starty[7]=130;
+                               endy[7]=starty[7]+20;
+                               movex[7]=0;
+                               movey[7]=0;*/
+                       }
+               }
+
+               if(mainmenu==12){       
+                       menupulse+=multiplier*2;
+
+                       nummenuitems=6;
+                       char temp[255];
+
+                       sprintf (menustring[0], "Register now for only $19.95!");
+                       startx[0]=160;
+                       starty[0]=270;
+                       endx[0]=startx[0]+strlen(menustring[0])*10;
+                       endy[0]=starty[0]+20;
+                       movex[0]=0;
+                       movey[0]=0;
+
+                       sprintf (menustring[1], "Confront raiders, wolves, and more!");
+                       startx[1]=130;
+                       starty[1]=240;
+                       endx[1]=startx[1]+strlen(menustring[1])*10;
+                       endy[1]=starty[1]+20;
+                       movex[1]=0;
+                       movey[1]=0;
+
+                       sprintf (menustring[2], "Fight using swords, staves and armor!");
+                       startx[2]=125;
+                       starty[2]=210;
+                       endx[2]=startx[2]+strlen(menustring[2])*10;
+                       endy[2]=starty[2]+20;
+                       movex[2]=0;
+                       movey[2]=0;
+
+                       if(!tryquit)sprintf (menustring[3], "Back");
+                       else sprintf (menustring[3], "Quit");
+                       startx[3]=10;
+                       endx[3]=startx[3]+strlen(menustring[3])*10;
+                       starty[3]=10;
+                       endy[3]=starty[3]+20;
+                       movex[3]=0;
+                       movey[3]=0;
+
+                       sprintf (menustring[4], "Register now!");
+                       startx[4]=250;
+                       endx[4]=startx[4]+strlen(menustring[4])*10;
+                       starty[4]=140;
+                       endy[4]=starty[4]+20;
+                       movex[4]=0;
+                       movey[4]=0;
+
+                       sprintf (menustring[5], "Enter registration code!");
+                       startx[5]=190;
+                       endx[5]=startx[5]+strlen(menustring[5])*10;
+                       starty[5]=120;
+                       endy[5]=starty[5]+20;
+                       movex[5]=0;
+                       movey[5]=0;
+               }
+
+               if(mainmenu==15){       
+                       nummenuitems=2;
+                       char temp[255];
+
+                       sprintf (menustring[0], "Thank you for supporting Wolfire Software!");
+                       startx[0]=100;
+                       starty[0]=270;
+                       endx[0]=startx[0]+strlen(menustring[0])*10;
+                       endy[0]=starty[0]+20;
+                       movex[0]=0;
+                       movey[0]=0;
+
+                       sprintf (menustring[1], "Back");
+                       startx[1]=10;
+                       endx[1]=startx[1]+strlen(menustring[1])*10;
+                       starty[1]=10;
+                       endy[1]=starty[1]+20;
+                       movex[1]=0;
+                       movey[1]=0;
+               }
+
+               if(mainmenu==16){       
+                       nummenuitems=5;
+                       char temp[255];
+
+                       sprintf (menustring[0], "Sorry, that name/serial number combination is incorrect.");
+                       startx[0]=40;
+                       starty[0]=270;
+                       endx[0]=startx[0]+strlen(menustring[0])*10;
+                       endy[0]=starty[0]+20;
+                       movex[0]=0;
+                       movey[0]=0;
+
+                       sprintf (menustring[1], "Back");
+                       startx[1]=10;
+                       endx[1]=startx[1]+strlen(menustring[1])*10;
+                       starty[1]=10;
+                       endy[1]=starty[1]+20;
+                       movex[1]=0;
+                       movey[1]=0;
+
+                       sprintf (menustring[2], "Please make sure you are copying your name and serial");
+                       startx[2]=50;
+                       starty[2]=240;
+                       endx[2]=startx[2]+strlen(menustring[2])*10;
+                       endy[2]=starty[2]+20;
+                       movex[2]=0;
+                       movey[2]=0;
+
+                       sprintf (menustring[3], "number exactly as they appear in your email.");
+                       startx[3]=90;
+                       starty[3]=210;
+                       endx[3]=startx[3]+strlen(menustring[3])*10;
+                       endy[3]=starty[3]+20;
+                       movex[3]=0;
+                       movey[3]=0;
+
+                       sprintf (menustring[4], "Capitalization and punctuation matter!");
+                       startx[4]=120;
+                       starty[4]=180;
+                       endx[4]=startx[4]+strlen(menustring[4])*10;
+                       endy[4]=starty[4]+20;
+                       movex[4]=0;
+                       movey[4]=0;
+               }
+
+               if(mainmenu==13){       
+                       nummenuitems=2;
+                       char temp[255];
+
+                       sprintf (menustring[0], "Please enter your name:");
+                       startx[0]=50;
+                       starty[0]=250;
+                       endx[0]=startx[0]+strlen(menustring[0])*10;
+                       endy[0]=starty[0]+20;
+                       movex[0]=0;
+                       movey[0]=0;
+
+                       sprintf (menustring[1], "Please enter your name:");
+                       startx[1]=290;
+                       starty[1]=250;
+                       endx[1]=startx[1]+strlen(menustring[1])*10;
+                       endy[1]=starty[1]+20;
+                       movex[1]=0;
+                       movey[1]=0;
+               }
+
+               if(mainmenu==14){       
+                       nummenuitems=2;
+                       char temp[255];
+
+                       sprintf (menustring[0], "Please enter your number:");
+                       startx[0]=30;
+                       starty[0]=250;
+                       endx[0]=startx[0]+strlen(menustring[0])*10;
+                       endy[0]=starty[0]+20;
+                       movex[0]=0;
+                       movey[0]=0;
+
+                       sprintf (menustring[1], "Please enter your name:");
+                       startx[1]=290;
+                       starty[1]=250;
+                       endx[1]=startx[1]+strlen(menustring[1])*10;
+                       endy[1]=starty[1]+20;
+                       movex[1]=0;
+                       movey[1]=0;
+                       /*
+                       char tempstring[256];
+                       sprintf (tempstring, "%s", registrationname);
+                       long num1;
+                       long num2;
+                       long num3;
+                       long num4;
+                       long long longnum;
+                       longnum = MD5_string ( tempstring);
+                       //longnum = 1111111111111111;
+                       num1 = longnum/100000000;
+                       num2 = longnum%100000000;
+                       sprintf (tempstring, "%d-%d-%d-%d", num1/10000, num1%10000, num2/10000, num2%10000);
+
+                       sprintf (menustring[2], "%s", tempstring);
+                       startx[2]=290;
+                       starty[2]=230;
+                       endx[2]=startx[2]+strlen(menustring[2])*10;
+                       endy[2]=starty[2]+20;
+                       movex[2]=0;
+                       movey[2]=0;                             */      
+               }
+
+               if(mainmenu==1||mainmenu==2){
+                       nummenuitems=7;
+                       startx[0]=150;
+                       starty[0]=480-128;
+                       endx[0]=150+256;
+                       endy[0]=480;
+                       movex[0]=0;
+                       movey[0]=0;
+
+                       startx[1]=18;
+                       starty[1]=480-152-32;
+                       endx[1]=18+128;
+                       endy[1]=480-152;
+                       movex[1]=0;
+                       movey[1]=0;
+
+                       startx[2]=18;
+                       starty[2]=480-228-32;
+                       endx[2]=2+128;
+                       endy[2]=480-228;
+                       movex[2]=0;
+                       movey[2]=0;
+
+                       if(mainmenu==1){
+                               startx[3]=18;
+                               starty[3]=480-306-32;
+                               endx[3]=22+64;
+                               endy[3]=480-306;
+                               movex[3]=0;
+                               movey[3]=0;
+                       }
+
+                       if(mainmenu==2){
+                               startx[3]=18;
+                               starty[3]=480-306-32;
+                               endx[3]=22+128;
+                               endy[3]=480-306;
+                               movex[3]=0;
+                               movey[3]=0;
+                       }
+
+                       /*startx[4]=150;
+                       starty[4]=480-256;
+                       endx[4]=150+256;
+                       endy[4]=480;
+                       */
+                       if(anim==0){
+                               startx[4]=380;
+                               starty[4]=480-140-256;
+                               endx[4]=380+256;
+                               endy[4]=480-140;
+                               movex[4]=80;
+                               movey[4]=0;
+
+                               startx[5]=145;
+                               starty[5]=480-138-256;
+                               endx[5]=145+256;
+                               endy[5]=480-138;
+                               movex[5]=40;
+                               movey[5]=0;
+
+                               startx[6]=254;
+                               starty[6]=480-144-256;
+                               endx[6]=254+256;
+                               endy[6]=480-144;
+                               movex[6]=20;
+                               movey[6]=0;
+                       }
+                       if(anim==1){
+                               startx[4]=180;
+                               starty[4]=480-140-256;
+                               endx[4]=180+256;
+                               endy[4]=480-140;
+                               movex[4]=80;
+                               movey[4]=0;
+
+                               startx[5]=500;
+                               starty[5]=480-138-256;
+                               endx[5]=500+256;
+                               endy[5]=480-138;
+                               movex[5]=40;
+                               movey[5]=0;
+
+                               startx[6]=340;
+                               starty[6]=480-144-256;
+                               endx[6]=340+256;
+                               endy[6]=480-144;
+                               movex[6]=20;
+                               movey[6]=0;
+                       }
+                       if(anim==2){
+                               startx[4]=460;
+                               starty[4]=480-140-256;
+                               endx[4]=460+256;
+                               endy[4]=480-140;
+                               movex[4]=50;
+                               movey[4]=0;
+
+                               startx[5]=295;
+                               starty[5]=480-150-256;
+                               endx[5]=295+256;
+                               endy[5]=480-138;
+                               movex[5]=-10;
+                               movey[5]=0;
+
+                               startx[6]=204;
+                               starty[6]=480-144-256;
+                               endx[6]=204+256;
+                               endy[6]=480-144;
+                               movex[6]=-30;
+                               movey[6]=0;
+                       }
+                       if(anim==3){
+                               startx[4]=150;
+                               starty[4]=480-140-256;
+                               endx[4]=200+256;
+                               endy[4]=480-140;
+                               movex[4]=80;
+                               movey[4]=0;
+
+                               startx[5]=350;
+                               starty[5]=480-150-256;
+                               endx[5]=350+256;
+                               endy[5]=480-138;
+                               movex[5]=5;
+                               movey[5]=0;
+
+                               startx[6]=500;
+                               starty[6]=480-144-256;
+                               endx[6]=500+256;
+                               endy[6]=480-144;
+                               movex[6]=-10;
+                               movey[6]=0;
+                       }
+                       if(anim==4){
+                               startx[4]=190;
+                               starty[4]=480-100-256;
+                               endx[4]=190+256;
+                               endy[4]=480-100;
+                               movex[4]=-30;
+                               movey[4]=0;
+
+                               startx[5]=185;
+                               starty[5]=480-120-256;
+                               endx[5]=185+256;
+                               endy[5]=480-120;
+                               movex[5]=-5;
+                               movey[5]=0;
+
+                               startx[6]=400;
+                               starty[6]=480-144-256;
+                               endx[6]=400+256;
+                               endy[6]=480-144;
+                               movex[6]=20;
+                               movey[6]=0;
+                       }
+               }
+
+               selected=-1;
+
+               if(mainmenu==1||mainmenu==2)
+                       for(i=1;i<4;i++){
+                               if((mousecoordh/screenwidth*640)>startx[i]&&(mousecoordh/screenwidth*640)<endx[i]&&480-(mousecoordv/screenheight*480)>starty[i]&&480-(mousecoordv/screenheight*480)<endy[i]){
+                                       selected=i;
+                               }
+                       }
+
+                       if(mainmenu==3||mainmenu==4||mainmenu==5||mainmenu==6||mainmenu==7||mainmenu==8||mainmenu==9||mainmenu==10||mainmenu==11||mainmenu==12||mainmenu==13||mainmenu==14||mainmenu==15||mainmenu==16||mainmenu==17)
+                               for(i=0;i<nummenuitems;i++){
+                                       if((mousecoordh/screenwidth*640)>startx[i]&&(mousecoordh/screenwidth*640)<endx[i]&&480-(mousecoordv/screenheight*480)>starty[i]&&480-(mousecoordv/screenheight*480)<endy[i]){
+                                               if(mainmenu!=5)selected=i;
+                                               if(mainmenu==5&&(i!=0&&i!=6))selected=i;
+                                               if(mainmenu==9&&(i!=numchallengelevels+1))selected=i;
+                                               if(mainmenu==11&&(i!=numchallengelevels+1))selected=i;
+                                       }
+                               }
+
+                               if(nummenuitems>0)
+                                       for(i=0;i<nummenuitems;i++){
+                                               if(selected==i)selectedlong[i]+=multiplier*5;
+                                               if(selectedlong[i]>1)selectedlong[i]=1;
+                                               if(selected!=i)selectedlong[i]-=multiplier*5;
+                                               if(selectedlong[i]<0)selectedlong[i]=0; 
+                                               //if(i>=4)selectedlong[i]=.3;           
+                                               if(i>=4&&(mainmenu==1||mainmenu==2))selectedlong[i]=0;  
+                                       }
+
+                                       if(nummenuitems>0)
+                                               for(i=0;i<nummenuitems;i++){
+                                                       offsetx[i]=(startx[i]+endx[i])/2-(mousecoordh/screenwidth*640);
+                                                       offsety[i]=(starty[i]+endy[i])/2-(480-(mousecoordv/screenheight*480));
+                                                       offsetx[i]*=.06f;
+                                                       offsety[i]*=.06f;
+                                                       offsetx[i]=0;
+                                                       offsety[i]=0;
+                                                       if(i>=4&&(mainmenu==1||mainmenu==2)){
+                                                               offsetx[i]=(startx[i]+endx[i]+movex[i]*transition)/2-(640+190)/2;
+                                                               offsety[i]=(starty[i]+endy[i]+movey[i]*transition)/2-(336+150)/2;
+                                                               offsetx[i]*=.06f;
+                                                               offsety[i]*=.06f;
+                                                       }
+                                               }
+
+                                               if(mainmenu==1||mainmenu==2){
+                                                       glClear(GL_DEPTH_BUFFER_BIT);
+                                                       glEnable(GL_ALPHA_TEST);
+                                                       glAlphaFunc(GL_GREATER, 0.001f);
+                                                       glEnable(GL_TEXTURE_2D);
+                                                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                                                       glDisable(GL_CULL_FACE);
+                                                       glDisable(GL_LIGHTING);
+                                                       glDepthMask(0);
+                                                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                                       glPushMatrix();                                                                         // Store The Projection Matrix
+                                                               glLoadIdentity();                                                                       // Reset The Projection Matrix
+                                                               glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                                                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                               glPushMatrix();                                                                         // Store The Modelview Matrix
+                                                                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                                                                       glTranslatef(screenwidth/2,screenheight/2,0);
+                                                                       glPushMatrix();
+                                                                               glScalef((float)screenwidth/2,(float)screenheight/2,1);
+                                                                               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                                                                               glDisable(GL_BLEND);
+                                                                               glColor4f(0,0,0,1.0);
+                                                                               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
+                                                                               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
+                                                                               glDisable(GL_TEXTURE_2D);
+                                                                               glPushMatrix();
+                                                                                       //glScalef(.25,.25,.25);
+                                                                                       glBegin(GL_QUADS);
+                                                                                       glTexCoord2f(0,0);
+                                                                                       glVertex3f(-1,          -1,      0.0f);
+                                                                                       glTexCoord2f(1,0);
+                                                                                       glVertex3f(1,   -1,      0.0f);
+                                                                                       glTexCoord2f(1,1);
+                                                                                       glVertex3f(1,   1, 0.0f);
+                                                                                       glTexCoord2f(0,1);
+                                                                                       glVertex3f(-1,  1, 0.0f);
+                                                                                       glEnd();
+                                                                               glPopMatrix();
+                                                                               glEnable(GL_BLEND);
+                                                                               glColor4f(0.4,0.4,0.4,1.0);
+                                                                               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
+                                                                               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
+                                                                               glEnable(GL_TEXTURE_2D);
+                                                                               glBindTexture( GL_TEXTURE_2D, Mainmenuitems[4]);
+                                                                               glPushMatrix();
+                                                                                       //glScalef(.25,.25,.25);
+                                                                                       glBegin(GL_QUADS);
+                                                                                       glTexCoord2f(0,0);
+                                                                                       glVertex3f(-1,          -1,      0.0f);
+                                                                                       glTexCoord2f(1,0);
+                                                                                       glVertex3f(1,   -1,      0.0f);
+                                                                                       glTexCoord2f(1,1);
+                                                                                       glVertex3f(1,   1, 0.0f);
+                                                                                       glTexCoord2f(0,1);
+                                                                                       glVertex3f(-1,  1, 0.0f);
+                                                                                       glEnd();
+                                                                               glPopMatrix();
+                                                                       glPopMatrix();
+                                                               glPopMatrix();
+                                                               glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                                       glPopMatrix();
+
+                                                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                                       glPushMatrix();                                                                         // Store The Projection Matrix
+                                                               glLoadIdentity();                                                                       // Reset The Projection Matrix
+                                                               glOrtho(0,640,0,480,-100,100);                                          // Set Up An Ortho Screen
+                                                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                               glPushMatrix();                                                                         // Store The Modelview Matrix
+                                                                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                                                                       glPushMatrix();
+                                                                               glDisable(GL_TEXTURE_2D);
+                                                                               glColor4f(1,0,0,1);
+                                                                               /*glPushMatrix();
+                                                                               glBegin(GL_QUADS);
+                                                                               glTexCoord2f(0,0);
+                                                                               if(anim!=1)glVertex3f(190,      150,     0.0f);
+                                                                               if(anim==1)glVertex3f(190+movex[4]*transition,  150,     0.0f);
+                                                                               glTexCoord2f(1,0);
+                                                                               glVertex3f(640, 150,     0.0f);
+                                                                               glTexCoord2f(1,1);
+                                                                               glVertex3f(640, 336, 0.0f);
+                                                                               glTexCoord2f(0,1);
+                                                                               if(anim!=1)glVertex3f(190, 336, 0.0f);
+                                                                               if(anim==1)glVertex3f(190+movex[4]*transition, 336,      0.0f);
+                                                                               glEnd();
+                                                                               glPopMatrix();*/
+                                                                       glPopMatrix();
+                                                               glPopMatrix();
+                                                               glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                                       glPopMatrix();
+                                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+
+                                               }
+
+                                               glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                               glPushMatrix();                                                                         // Store The Projection Matrix
+                                               glLoadIdentity();                                                                       // Reset The Projection Matrix
+                                               glOrtho(0,640,0,480,-100,100);                                          // Set Up An Ortho Screen
+                                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                               glPushMatrix();                                                                         // Store The Modelview Matrix
+                                               glLoadIdentity();                                                               // Reset The Modelview Matrix
+                                               glEnable(GL_TEXTURE_2D);
+                                               if(nummenuitems>0)
+                                               {
+                                                       for(j=0;j<nummenuitems;j++)
+                                                       {
+                                                               if(j<=3||(mainmenu!=1&&mainmenu!=2))
+                                                               {
+                                                                       //glDisable(GL_BLEND);
+                                                                       glEnable(GL_ALPHA_TEST);
+                                                                       glEnable(GL_BLEND);
+                                                                       //glDisable(GL_ALPHA_TEST);
+                                                                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                                                                       if(mainmenu==1||mainmenu==2)
+                                                                       {
+                                                                               glColor4f(1,1,1,1);
+                                                                               glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+                                                                               glBindTexture( GL_TEXTURE_2D, Mainmenuitems[j]);
+                                                                               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+                                                                               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+                                                                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                                               glPushMatrix();
+                                                                                       glBegin(GL_QUADS);
+                                                                                       glTexCoord2f(0,0);
+                                                                                       glVertex3f(startx[j]+movex[j]*transition,       starty[j]+movey[j]*transition,   0.0f);
+                                                                                       glTexCoord2f(1,0);
+                                                                                       glVertex3f(endx[j]+movex[j]*transition,         starty[j]+movey[j]*transition,   0.0f);
+                                                                                       glTexCoord2f(1,1);
+                                                                                       glVertex3f(endx[j]+movex[j]*transition,         endy[j]+movey[j]*transition, 0.0f);
+                                                                                       glTexCoord2f(0,1);
+                                                                                       glVertex3f(startx[j]+movex[j]*transition,       endy[j]+movey[j]*transition, 0.0f);
+                                                                                       glEnd();
+                                                                               glPopMatrix();
+                                                                               glEnable(GL_BLEND);
+                                                                               //glDisable(GL_ALPHA_TEST);
+                                                                               if(j<4)glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+                                                                               for(i=0;i<10;i++)
+                                                                               {
+                                                                                       if(1-((float)i)/10-(1-selectedlong[j])>0)
+                                                                                       {
+                                                                                               glColor4f(1,1,1,(1-((float)i)/10-(1-selectedlong[j]))*.25);
+                                                                                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                                                               glPushMatrix();
+                                                                                                       glBegin(GL_QUADS);
+                                                                                                       glTexCoord2f(0,0);
+                                                                                                       glVertex3f(startx[j]-((float)i)*1/2+offsetx[j]*((float)i)/2+movex[j]*transition,        starty[j]-((float)i)*1/2+offsety[j]*((float)i)/2+movey[j]*transition,    0.0f);
+                                                                                                       glTexCoord2f(1,0);
+                                                                                                       glVertex3f(endx[j]+((float)i)*1/2+offsetx[j]*((float)i)/2+movex[j]*transition,  starty[j]-((float)i)*1/2+offsety[j]*((float)i)/2+movey[j]*transition,    0.0f);
+                                                                                                       glTexCoord2f(1,1);
+                                                                                                       glVertex3f(endx[j]+((float)i)*1/2+offsetx[j]*((float)i)/2+movex[j]*transition,  endy[j]+((float)i)*1/2+offsety[j]*((float)i)/2+movey[j]*transition, 0.0f);
+                                                                                                       glTexCoord2f(0,1);
+                                                                                                       glVertex3f(startx[j]-((float)i)*1/2+offsetx[j]*((float)i)/2+movex[j]*transition, endy[j]+((float)i)*1/2+offsety[j]*((float)i)/2+movey[j]*transition, 0.0f);
+                                                                                                       glEnd();
+                                                                                               glPopMatrix();
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                                       if(mainmenu==3||mainmenu==4||mainmenu==5||mainmenu==6||mainmenu==7||mainmenu==8||mainmenu==9||mainmenu==10||mainmenu==11||mainmenu==12||mainmenu==13||mainmenu==14||mainmenu==15||mainmenu==16||mainmenu==17)
+                                                                       {
+                                                                               if(mainmenu!=5||j<6)
+                                                                               {
+                                                                                       glColor4f(1,0,0,1);
+                                                                                       if(mainmenu==12&&j==4)glColor4f(1,(sin(menupulse)+1)/2,(sin(menupulse)+1)/2,1);
+                                                                                       if(mainmenu==9&&j>accountprogress[accountactive]&&j<numchallengelevels)glColor4f(0.5,0,0,1);
+                                                                                       if(mainmenu==11&&j>accountprogress[accountactive]&&j<numchallengelevels)glColor4f(0.5,0,0,1);
+                                                                                       //if(1-((float)i)/10-(1-selectedlong[j])>0){
+                                                                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                                                       glPushMatrix();
+                                                                                               if((mainmenu!=7||j!=0||!entername)&&(mainmenu!=13||j!=1)&&(mainmenu!=14||j!=1))text.glPrint(startx[j],starty[j],menustring[j],0,1,640,480);
+                                                                                               else
+                                                                                               {
+                                                                                                       if(displayblink){
+                                                                                                               sprintf (string, "_");
+                                                                                                               text.glPrint(startx[j]+(float)(displayselected)*10,starty[j],string,0,1,640,480);
+                                                                                                       }
+                                                                                                       k=0;
+                                                                                                       for(l=0;l<displaychars[k];l++){
+                                                                                                               if(l<displaychars[k]){
+                                                                                                                       sprintf (string, "%c",displaytext[k][l]);
+                                                                                                                       text.glPrint(startx[j]+l*10,starty[j],string,0,1,640,480);
+                                                                                                               }
+                                                                                                       }
+                                                                                               }
+                                                                                       glPopMatrix();
+                                                                                       /*}
+                                                                                       else{
+                                                                                       glPushMatrix();
+                                                                                       sprintf (string, "Hooo!");
+                                                                                       text.glPrint(startx[0],starty[0],string,0,1,640,480);
+                                                                                       glPopMatrix();
+                                                                                       }*/
+                                                                                       glEnable(GL_BLEND);
+                                                                                       glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+                                                                                       for(i=0;i<15;i++)
+                                                                                       {
+                                                                                               if(1-((float)i)/15-(1-selectedlong[j])>0)
+                                                                                               {
+                                                                                                       glColor4f(1,0,0,(1-((float)i)/10-(1-selectedlong[j]))*.25);
+                                                                                                       if(mainmenu==12&&j==4)glColor4f(1,(sin(menupulse)+1)/2,(sin(menupulse)+1)/2,(1-((float)i)/10-(1-selectedlong[j]))*.25);
+                                                                                                       if(mainmenu==9&&j>accountprogress[accountactive]&&j<numchallengelevels)glColor4f(0.5,0,0,(1-((float)i)/10-(1-selectedlong[j]))*.25);
+                                                                                                       if(mainmenu==11&&j>accountprogress[accountactive]&&j<numchallengelevels)glColor4f(0.5,0,0,(1-((float)i)/10-(1-selectedlong[j]))*.25);
+                                                                                                       if(mainmenu==3)text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4-((/*1*/+((float)i)/70)*strlen(menustring[j]))*3,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       if(mainmenu==4)text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4/*-((((float)i)/70)*strlen(menustring[j]))*3*/,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       if(mainmenu==5)text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4/*-((((float)i)/70)*strlen(menustring[j]))*3*/,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       if(mainmenu==6)text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4/*-((((float)i)/70)*strlen(menustring[j]))*3*/,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       if(mainmenu==7&&(j!=0||!entername))text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4/*-((((float)i)/70)*strlen(menustring[j]))*3*/,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       if(mainmenu==8)text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4/*-((((float)i)/70)*strlen(menustring[j]))*3*/,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       if(mainmenu==9)text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4/*-((((float)i)/70)*strlen(menustring[j]))*3*/,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       if(mainmenu==11)text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4/*-((((float)i)/70)*strlen(menustring[j]))*3*/,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       if(mainmenu==10)text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4/*-((((float)i)/70)*strlen(menustring[j]))*3*/,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       if(mainmenu==12)text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4/*-((((float)i)/70)*strlen(menustring[j]))*3*/,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       if(mainmenu==15)text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4/*-((((float)i)/70)*strlen(menustring[j]))*3*/,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       if(mainmenu==16)text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4/*-((((float)i)/70)*strlen(menustring[j]))*3*/,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       if(mainmenu==17)text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4/*-((((float)i)/70)*strlen(menustring[j]))*3*/,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       if(mainmenu==13&&j!=1)text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4/*-((((float)i)/70)*strlen(menustring[j]))*3*/,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       if(mainmenu==14&&j!=1)text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4/*-((((float)i)/70)*strlen(menustring[j]))*3*/,starty[j]/*-i*1/2*/+offsety[j]*((float)i)/4,menustring[j],0,1+((float)i)/70,640,480);
+                                                                                                       /*else{
+                                                                                                       if(displayblink){
+                                                                                                       sprintf (string, "_");
+                                                                                                       text.glPrint(startx[j]-((float)i)+offsetx[j]*((float)i)/4+(float)(displayselected)*10*(1+((float)i)/70),starty[j]+offsety[j]*((float)i)/4,string,0,1+((float)i)/70,640,480);
+                                                                                                       }
+                                                                                                       k=0;
+                                                                                                       for(l=0;l<displaychars[k];l++){
+                                                                                                       if(l<displaychars[k]){
+                                                                                                       sprintf (string, "%c",displaytext[k][l]);
+                                                                                                       text.glPrint(startx[j]-((float)k)+offsetx[j]*((float)k)/4+l*10*(1+((float)i)/70),starty[j]+offsety[j]*((float)i)/4,string,0,1+((float)i)/70,640,480);
+                                                                                                       }
+                                                                                                       }
+                                                                                                       }*/
+                                                                                               }
+                                                                                       }
+                                                                               }
+                                                                               else
+                                                                               {
+                                                                                       glClear(GL_DEPTH_BUFFER_BIT);
+                                                                                       glEnable(GL_ALPHA_TEST);
+                                                                                       glAlphaFunc(GL_GREATER, 0.001f);
+                                                                                       glEnable(GL_TEXTURE_2D);
+                                                                                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                                                                                       glDisable(GL_CULL_FACE);
+                                                                                       glDisable(GL_LIGHTING);
+                                                                                       if(j==6)glColor4f(1,1,1,1);
+                                                                                       else glColor4f(1,0,0,1);
+
+                                                                                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                                                                       glPushMatrix();                                                                         // Store The Projection Matrix
+                                                                                               glLoadIdentity();                                                                       // Reset The Projection Matrix
+                                                                                               glOrtho(0,640,0,480,-100,100);                                          // Set Up An Ortho Screen
+                                                                                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                                                               glPushMatrix();                                                                         // Store The Modelview Matrix
+                                                                                                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                                                                                                       glPushMatrix();
+
+                                                                                                               //Draw world, draw map
+                                                                                                               glTranslatef(2,-5,0);
+
+                                                                                                               if(j>6&&j<nummenuitems-1)
+                                                                                                               {
+                                                                                                                       XYZ linestart,lineend,offset;
+                                                                                                                       XYZ fac;
+                                                                                                                       float startsize;
+                                                                                                                       float endsize;
+                                                                                                                       linestart=0;
+                                                                                                                       lineend=0;
+                                                                                                                       offset=0;
+                                                                                                                       //float linestartx,lineendx,linestarty,lineendy,offsetx,offsety;
+                                                                                                                       linestart.x=(startx[j]+endx[j])/2;
+                                                                                                                       linestart.y=(starty[j]+endy[j])/2;
+                                                                                                                       if(j>=6+accountcampaignchoicesmade[accountactive]){
+                                                                                                                               linestart.x=(startx[6+accountcampaignchoicesmade[accountactive]]+endx[6+accountcampaignchoicesmade[accountactive]])/2;
+                                                                                                                               linestart.y=(starty[6+accountcampaignchoicesmade[accountactive]]+endy[6+accountcampaignchoicesmade[accountactive]])/2;
+                                                                                                                       }
+                                                                                                                       lineend.x=(startx[j+1]+endx[j+1])/2;
+                                                                                                                       lineend.y=(starty[j+1]+endy[j+1])/2;
+                                                                                                                       offset=lineend-linestart;
+                                                                                                                       fac=offset;
+                                                                                                                       Normalise(&fac);
+                                                                                                                       offset=DoRotation(offset,0,0,90);
+                                                                                                                       Normalise(&offset);
+                                                                                                                       glDisable(GL_TEXTURE_2D);                                                       
+
+                                                                                                                       if(j<6+accountcampaignchoicesmade[accountactive]){
+                                                                                                                               glColor4f(0.5,0,0,1);
+                                                                                                                               startsize=.5;
+                                                                                                                               endsize=.5;
+                                                                                                                       }
+                                                                                                                       if(j>=6+accountcampaignchoicesmade[accountactive]){
+                                                                                                                               glColor4f(1,0,0,1);
+                                                                                                                               endsize=1;
+                                                                                                                               startsize=.5;
+                                                                                                                       }
+
+                                                                                                                       linestart+=fac*4*startsize;
+                                                                                                                       lineend-=fac*4*endsize;
+
+                                                                                                                       if(!(j>7+accountcampaignchoicesmade[accountactive]+campaignchoicenum)){
+                                                                                                                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                                                                                               glPushMatrix();
+                                                                                                                                       glBegin(GL_QUADS);
+                                                                                                                                       glTexCoord2f(0,0);
+                                                                                                                                       glVertex3f(linestart.x-offset.x*startsize,      linestart.y-offset.y*startsize,          0.0f);
+                                                                                                                                       glTexCoord2f(1,0);
+                                                                                                                                       glVertex3f(linestart.x+offset.x*startsize,      linestart.y+offset.y*startsize,          0.0f);
+                                                                                                                                       glTexCoord2f(1,1);
+                                                                                                                                       glVertex3f(lineend.x+offset.x*endsize,          lineend.y+offset.y*endsize, 0.0f);
+                                                                                                                                       glTexCoord2f(0,1);
+                                                                                                                                       glVertex3f(lineend.x-offset.x*endsize,          lineend.y-offset.y*endsize, 0.0f);
+                                                                                                                                       glEnd();
+                                                                                                                               glPopMatrix();
+                                                                                                                       }
+                                                                                                                       glEnable(GL_TEXTURE_2D);
+                                                                                                               }
+
+
+                                                                                                               if(j==6)glBindTexture( GL_TEXTURE_2D, Mainmenuitems[7]);
+                                                                                                               else glBindTexture( GL_TEXTURE_2D, Mapcircletexture);
+                                                                                                               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+                                                                                                               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+                                                                                                               if(j-7<accountcampaignchoicesmade[accountactive])glColor4f(0.5,0,0,1);
+                                                                                                               if(j-7>=accountcampaignchoicesmade[accountactive])glColor4f(1,0,0,1);
+                                                                                                               if(j==6)glColor4f(1,1,1,1);
+                                                                                                               XYZ midpoint;
+                                                                                                               float itemsize;
+                                                                                                               itemsize=abs(startx[j]-endx[j])/2;
+                                                                                                               midpoint=0;
+                                                                                                               midpoint.x=(startx[j]+endx[j])/2;
+                                                                                                               midpoint.y=(starty[j]+endy[j])/2;
+                                                                                                               if(j>6&&(j-7<accountcampaignchoicesmade[accountactive]))itemsize*=.5;
+                                                                                                               if(!(j-7>accountcampaignchoicesmade[accountactive]+campaignchoicenum))
+                                                                                                               {
+                                                                                                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                                                                                       glPushMatrix();
+                                                                                                                               glBegin(GL_QUADS);
+                                                                                                                               glTexCoord2f(0,0);
+                                                                                                                               glVertex3f(midpoint.x-itemsize+movex[j]*transition,     midpoint.y-itemsize+movey[j]*transition,         0.0f);
+                                                                                                                               glTexCoord2f(1,0);
+                                                                                                                               glVertex3f(midpoint.x+itemsize+movex[j]*transition,             midpoint.y-itemsize+movey[j]*transition,         0.0f);
+                                                                                                                               glTexCoord2f(1,1);
+                                                                                                                               glVertex3f(midpoint.x+itemsize+movex[j]*transition,             midpoint.y+itemsize+movey[j]*transition, 0.0f);
+                                                                                                                               glTexCoord2f(0,1);
+                                                                                                                               glVertex3f(midpoint.x-itemsize+movex[j]*transition,     midpoint.y+itemsize+movey[j]*transition, 0.0f);
+                                                                                                                               glEnd();
+                                                                                                                       glPopMatrix();
+                                                                                                                       glEnable(GL_BLEND);
+                                                                                                                       //glDisable(GL_ALPHA_TEST);
+                                                                                                                       if(j<4)glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+                                                                                                                       for(i=0;i<10;i++)
+                                                                                                                       {
+                                                                                                                               if(1-((float)i)/10-(1-selectedlong[j])>0)
+                                                                                                                               {
+                                                                                                                                       glColor4f(1,0,0,(1-((float)i)/10-(1-selectedlong[j]))*.25);
+                                                                                                                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                                                                                                       glPushMatrix();
+                                                                                                                                               glBegin(GL_QUADS);
+                                                                                                                                               glTexCoord2f(0,0);
+                                                                                                                                               glVertex3f(midpoint.x-itemsize-((float)i)*1/2+offsetx[j]*((float)i)/2+movex[j]*transition,      midpoint.y-itemsize-((float)i)*1/2+offsety[j]*((float)i)/2+movey[j]*transition,          0.0f);
+                                                                                                                                               glTexCoord2f(1,0);
+                                                                                                                                               glVertex3f(midpoint.x+itemsize+((float)i)*1/2+offsetx[j]*((float)i)/2+movex[j]*transition,      midpoint.y-itemsize-((float)i)*1/2+offsety[j]*((float)i)/2+movey[j]*transition,          0.0f);
+                                                                                                                                               glTexCoord2f(1,1);
+                                                                                                                                               glVertex3f(midpoint.x+itemsize+((float)i)*1/2+offsetx[j]*((float)i)/2+movex[j]*transition,      midpoint.y+itemsize+((float)i)*1/2+offsety[j]*((float)i)/2+movey[j]*transition, 0.0f);
+                                                                                                                                               glTexCoord2f(0,1);
+                                                                                                                                               glVertex3f(midpoint.x-itemsize-((float)i)*1/2+offsetx[j]*((float)i)/2+movex[j]*transition, midpoint.y+itemsize+((float)i)*1/2+offsety[j]*((float)i)/2+movey[j]*transition, 0.0f);
+                                                                                                                                               glEnd();
+                                                                                                                                       glPopMatrix();
+                                                                                                                               }
+                                                                                                                       }
+                                                                                                               }
+                                                                                                       glPopMatrix();
+                                                                                               glPopMatrix();
+                                                                                               glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                                                                       glPopMatrix();
+                                                                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+
+                                                                                       if(j-7>=accountcampaignchoicesmade[accountactive]){
+                                                                                               //glColor4f(0,0,0,1);
+                                                                                               //text.glPrintOutline(startx[j]+10-1.5,starty[j]-4-1.5,menustring[j],0,0.6*1.25,640,480);
+                                                                                               //glColor4f(1,0,0,1);
+                                                                                               //text.glPrint(startx[j]+10,starty[j]-4,menustring[j],0,0.6,640,480);
+                                                                                               text.glPrintOutlined(0.9,0,0,startx[j]+10,starty[j]-4,menustring[j],0,0.6,640,480);
+                                                                                               glDisable(GL_DEPTH_TEST);
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                               glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                               glPopMatrix();
+                                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                               glPopMatrix();
+
+                                                       if(mainmenu==1||mainmenu==2)
+                                                               if(transition<.1||transition>.9){
+                                                                       glClear(GL_DEPTH_BUFFER_BIT);
+                                                                       glEnable(GL_ALPHA_TEST);
+                                                                       glAlphaFunc(GL_GREATER, 0.001f);
+                                                                       glEnable(GL_TEXTURE_2D);
+                                                                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                                                                       glDisable(GL_CULL_FACE);
+                                                                       glDisable(GL_LIGHTING);
+                                                                       glDepthMask(0);
+                                                                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                                                       glPushMatrix();                                                                         // Store The Projection Matrix
+                                                                               glLoadIdentity();                                                                       // Reset The Projection Matrix
+                                                                               glOrtho(0,640,0,480,-100,100);                                          // Set Up An Ortho Screen
+                                                                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                                               glPushMatrix();                                                                         // Store The Modelview Matrix
+                                                                                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                                                                                       glPushMatrix();
+                                                                                               glDisable(GL_TEXTURE_2D);
+                                                                                               if(transition<.1)glColor4f(1,0,0,1-(transition*10));
+                                                                                               if(transition>.9)glColor4f(1,0,0,1-((1-transition)*10));
+                                                                                               /*glPushMatrix();
+                                                                                               glBegin(GL_QUADS);
+                                                                                               glTexCoord2f(0,0);
+                                                                                               glVertex3f(190, 150,     0.0f);
+                                                                                               glTexCoord2f(1,0);
+                                                                                               glVertex3f(640, 150,     0.0f);
+                                                                                               glTexCoord2f(1,1);
+                                                                                               glVertex3f(640, 336, 0.0f);
+                                                                                               glTexCoord2f(0,1);
+                                                                                               glVertex3f(190, 336, 0.0f);
+                                                                                               glEnd();
+                                                                                               glPopMatrix();*/
+                                                                                       glPopMatrix();
+                                                                               glPopMatrix();
+                                                                               glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                                                       glPopMatrix();
+                                                               }
+
+                                                               glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                                               glPushMatrix();                                                                         // Store The Projection Matrix
+                                                                       glLoadIdentity();                                                                       // Reset The Projection Matrix
+                                                                       glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                                                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                                       glPushMatrix();                                                                         // Store The Modelview Matrix
+                                                                               glLoadIdentity();                                                               // Reset The Modelview Matrix
+                                                                               glTranslatef(screenwidth/2,screenheight/2,0);
+                                                                               glPushMatrix();
+                                                                                       glScalef((float)screenwidth/2,(float)screenheight/2,1);
+                                                                                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                                                                                       glEnable(GL_BLEND);
+                                                                                       glEnable(GL_TEXTURE_2D);
+                                                                                       glColor4f(1,1,1,1);
+                                                                                       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
+                                                                                       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
+                                                                               glPopMatrix();
+                                                                               glPushMatrix();
+                                                                                       glTranslatef(mousecoordh-screenwidth/2,mousecoordv*-1+screenheight/2,0);
+                                                                                       glScalef((float)screenwidth/64,(float)screenwidth/64,1);
+                                                                                       glTranslatef(1,-1,0);
+                                                                                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                                                                                       glColor4f(1,1,1,1);
+                                                                                       glBindTexture( GL_TEXTURE_2D, cursortexture);
+                                                                                       glPushMatrix();
+                                                                                               //glScalef(.25,.25,.25);
+                                                                                               glBegin(GL_QUADS);
+                                                                                               glTexCoord2f(0,0);
+                                                                                               glVertex3f(-1,          -1,      0.0f);
+                                                                                               glTexCoord2f(1,0);
+                                                                                               glVertex3f(1,   -1,      0.0f);
+                                                                                               glTexCoord2f(1,1);
+                                                                                               glVertex3f(1,   1, 0.0f);
+                                                                                               glTexCoord2f(0,1);
+                                                                                               glVertex3f(-1,  1, 0.0f);
+                                                                                               glEnd();
+                                                                                       glPopMatrix();
+                                                                               glPopMatrix();
+                                                                       glPopMatrix();
+                                                                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                                               glPopMatrix();
+
+
+                                                               if(flashamount>0)
+                                                               {
+                                                                       if(flashamount>1)flashamount=1;
+                                                                       if(flashdelay<=0)flashamount-=multiplier;
+                                                                       flashdelay--;
+                                                                       if(flashamount<0)flashamount=0;
+                                                                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                                                                       glDisable(GL_CULL_FACE);
+                                                                       glDisable(GL_LIGHTING);
+                                                                       glDisable(GL_TEXTURE_2D);
+                                                                       glDepthMask(0);
+                                                                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                                                       glPushMatrix();                                                                         // Store The Projection Matrix
+                                                                               glLoadIdentity();                                                                       // Reset The Projection Matrix
+                                                                               glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                                                                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                                               glPushMatrix();                                                                         // Store The Modelview Matrix
+                                                                                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                                                                                       glScalef(screenwidth,screenheight,1);
+                                                                                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                                                                                       glEnable(GL_BLEND);
+                                                                                       glColor4f(flashr,flashg,flashb,flashamount);
+                                                                                       glBegin(GL_QUADS);
+                                                                                       glVertex3f(0,           0,       0.0f);
+                                                                                       glVertex3f(256, 0,       0.0f);
+                                                                                       glVertex3f(256, 256, 0.0f);
+                                                                                       glVertex3f(0,   256, 0.0f);
+                                                                                       glEnd();
+                                                                                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                                                                               glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                                                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                                                                       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+                                                                       glEnable(GL_CULL_FACE);
+                                                                       glDisable(GL_BLEND);
+                                                                       glDepthMask(1);
+                                                               }       
+       }
+
+       if(freeze||winfreeze||(mainmenu&&gameon)||(!gameon&&gamestarted)||(!gameon&&gamestarted)){
+               tempmult=multiplier;
+               multiplier=0;
+       }
+
+
+       //glFlush();
+       if(drawmode!=motionblurmode||mainmenu){
+#ifdef WIN32
+               if(drawmode!=motionblurmode) SwapBuffers( hDC);
+#else
+               if(drawmode!=motionblurmode)aglSwapBuffers(gaglContext); // send swap command
+#endif // send swap command
+       }
+
+       //myassert(glGetError() == GL_NO_ERROR);
+       glDrawBuffer(GL_BACK);
+       glReadBuffer(GL_BACK);
+       //glFlush();
+
+       weapons.DoStuff();
+
+       if(drawtoggle==2)drawtoggle=0;
+
+       if(freeze||winfreeze||(mainmenu&&gameon)||(!gameon&&gamestarted)){
+               multiplier=tempmult;
+       }
+       //Jordan fixed your warning!
+       return 0;
+}
diff --git a/Source/GameInitDispose.cpp b/Source/GameInitDispose.cpp
new file mode 100644 (file)
index 0000000..d966a35
--- /dev/null
@@ -0,0 +1,2019 @@
+#include "Game.h"      
+extern float screenwidth,screenheight;
+extern float viewdistance;
+extern XYZ viewer;
+extern XYZ lightlocation;
+extern float lightambient[3],lightbrightness[3];
+extern float fadestart;
+extern float texscale;
+extern float gravity;
+extern Light light;
+extern Animation animation[animation_count];
+extern Skeleton testskeleton;
+extern int numsounds;
+extern FSOUND_SAMPLE   *samp[100];
+extern int channels[100];
+extern Terrain terrain;
+extern Sprites sprites;
+extern int kTextureSize;
+extern float texdetail;
+extern float realtexdetail;
+extern float terraindetail;
+extern float volume;
+extern Objects objects;
+extern int detail;
+extern bool cellophane;
+extern GLubyte bloodText[512*512*3];
+extern GLubyte wolfbloodText[512*512*3];
+extern bool ismotionblur;
+extern bool trilinear;
+#ifdef WIN32
+extern HDC hDC;
+#else
+extern AGLContext gaglContext;
+#endif
+extern bool osx;
+extern bool musictoggle;
+extern Weapons weapons;
+extern Person player[maxplayers];
+extern int numplayers;
+extern int environment;
+extern bool ambientsound;
+extern float multiplier;
+extern int newnetmessages;
+extern int netdatanew;
+extern float mapinfo;
+extern bool stillloading;
+extern TGAImageRec texture;
+extern short vRefNum;
+extern long dirID;
+extern int mainmenu;
+extern int oldmainmenu;
+extern bool visibleloading;
+extern int loadscreencolor;
+extern float flashamount,flashr,flashg,flashb;
+extern int flashdelay;
+extern int whichjointstartarray[26];
+extern int whichjointendarray[26];
+extern int difficulty;
+extern float tintr,tintg,tintb;
+extern float slomospeed;
+extern char mapname[256];
+extern bool gamestarted;
+
+extern int numaccounts;
+extern int accountactive;
+extern int accountdifficulty[10];
+extern int accountprogress[10];
+extern float accountpoints[10];
+extern float accounthighscore[10][50];
+extern float accountfasttime[10][50];
+extern bool accountunlocked[10][60];
+extern char accountname[10][256];
+
+extern int numdialogues;
+extern int numdialogueboxes[20];
+extern int dialoguetype[20];
+extern int dialogueboxlocation[20][20];
+extern float dialogueboxcolor[20][20][3];
+extern int dialogueboxsound[20][20];
+extern char dialoguetext[20][20][128];
+extern char dialoguename[20][20][64];
+extern XYZ dialoguecamera[20][20];
+extern float dialoguecamerarotation[20][20];
+extern float dialoguecamerarotation2[20][20];
+extern int indialogue;
+extern int whichdialogue;
+extern float dialoguetime;
+
+extern float accountcampaignhighscore[10];
+extern float accountcampaignfasttime[10];
+extern float accountcampaignscore[10];
+extern float accountcampaigntime[10];
+
+extern int accountcampaignchoicesmade[10];
+extern int accountcampaignchoices[10][5000];
+
+extern FSOUND_STREAM * strm[10];
+
+extern "C"     void PlaySoundEx(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused);
+extern "C" void PlayStreamEx(int chan, FSOUND_STREAM *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused);
+
+Game::TextureList Game::textures;
+
+void Game::Dispose()
+{
+       int i,j;
+
+       LOGFUNC;
+
+       if(endgame==2){
+               accountcampaignchoicesmade[accountactive]=0;
+               accountcampaignscore[accountactive]=0;
+               accountcampaigntime[accountactive]=0;
+               endgame=0;
+       }
+
+
+       sprintf (mapname, ":Data:Users");
+
+       FILE                    *tfile;
+       tfile=fopen( mapname, "wb" );
+       if (tfile)
+       {
+               fpackf(tfile, "Bi", numaccounts);
+               fpackf(tfile, "Bi", accountactive);
+               if(numaccounts>0)
+               {
+                       for(i=0;i<numaccounts;i++)
+                       {
+                               fpackf(tfile, "Bf", accountcampaigntime[i]);
+                               fpackf(tfile, "Bf", accountcampaignscore[i]);
+                               fpackf(tfile, "Bf", accountcampaignfasttime[i]);
+                               fpackf(tfile, "Bf", accountcampaignhighscore[i]);
+                               fpackf(tfile, "Bi", accountdifficulty[i]);
+                               fpackf(tfile, "Bi", accountprogress[i]);
+                               fpackf(tfile, "Bi", accountcampaignchoicesmade[i]);
+                               for(j=0;j<accountcampaignchoicesmade[i];j++)
+                               {
+                                       fpackf(tfile, "Bi", accountcampaignchoices[i][j]);
+                               }
+                               fpackf(tfile, "Bf", accountpoints[i]);
+                               for(j=0;j<50;j++)
+                               {
+                                       fpackf(tfile, "Bf", accounthighscore[i][j]);
+                                       fpackf(tfile, "Bf", accountfasttime[i][j]);
+                               }
+                               for(j=0;j<60;j++)
+                               {
+                                       fpackf(tfile, "Bb",  accountunlocked[i][j]);
+                               }
+                               fpackf(tfile, "Bi",  strlen(accountname[i]));
+                               if(strlen(accountname[i])>0)
+                               {
+                                       for(j=0;j<(int)strlen(accountname[i]);j++)
+                                       {
+                                               fpackf(tfile, "Bb",  accountname[i][j]);
+                                       }
+                               }
+                       }
+               }
+
+               fclose(tfile);
+       }
+
+       TexIter it = textures.begin();
+       for (; it != textures.end(); ++it)
+       {
+               if (glIsTexture(it->second))
+                       glDeleteTextures(1, &it->second);
+       }
+       textures.clear();
+
+       LOG("Shutting down sound system...");
+
+       FSOUND_StopSound(FSOUND_ALL);
+
+#define streamcount 20
+#define samplecount 100
+
+       for (i=0; i < samplecount; ++i)
+       {
+               FSOUND_Sample_Free(samp[i]);
+       }
+
+       for (i=0; i < streamcount; ++i)
+       {
+               FSOUND_Stream_Close(strm[i]);
+       }
+
+       FSOUND_Close();
+       if (texture.data)
+       {
+               free(texture.data);
+       }
+       texture.data = 0;
+}
+
+
+//void Game::LoadSounds();
+void Game::LoadSounds()
+{
+       LOGFUNC;
+
+       LOG(std::string("Loading sounds..."));
+
+       FSOUND_3D_SetDopplerFactor(0);
+
+       FSOUND_SetSFXMasterVolume((int)(volume*255));
+       
+       samp[footstepsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepsnow1.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[footstepsound], 4.0f, 1000.0f);    
+
+       samp[footstepsound2] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepsnow2.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[footstepsound2], 4.0f, 1000.0f);   
+
+       samp[footstepsound3] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepstone1.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[footstepsound3], 4.0f, 1000.0f);   
+
+       samp[footstepsound4] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepstone2.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[footstepsound4], 4.0f, 1000.0f);   
+
+       samp[landsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:land.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[landsound], 4.0f, 1000.0f);        
+
+       samp[jumpsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:jump.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[jumpsound], 4.0f, 1000.0f);        
+
+       samp[hawksound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:hawk.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[hawksound], 40.0f, 10000.0f);      
+
+       samp[whooshsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:whoosh.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[whooshsound], 4.0f, 1000.0f);      
+       FSOUND_Sample_SetMode(samp[whooshsound], FSOUND_LOOP_NORMAL);
+
+       samp[landsound1] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:land1.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[landsound1], 4.0f, 1000.0f);       
+
+
+
+       samp[landsound2] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:land2.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[landsound2], 4.0f, 1000.0f);       
+
+       samp[breaksound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:broken.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[breaksound], 8.0f, 2000.0f);       
+
+       samp[lowwhooshsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:Lowwhoosh.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[lowwhooshsound], 8.0f, 2000.0f);   
+
+       samp[midwhooshsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:midwhoosh.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[midwhooshsound], 8.0f, 2000.0f);   
+
+       samp[highwhooshsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:highwhoosh.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[highwhooshsound], 8.0f, 2000.0f);  
+
+       samp[movewhooshsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:movewhoosh.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[movewhooshsound], 8.0f, 2000.0f);  
+
+       samp[heavyimpactsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:heavyimpact.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[heavyimpactsound], 8.0f, 2000.0f); 
+
+       samp[whooshhitsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:Whooshhit.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[whooshhitsound], 8.0f, 2000.0f);   
+
+       samp[thudsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:thud.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[thudsound], 8.0f, 2000.0f);        
+
+       samp[alarmsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:alarm.ogg", FSOUND_2D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[alarmsound], 8.0f, 2000.0f);       
+
+       samp[breaksound2] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:break.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[breaksound2], 8.0f, 2000.0f);      
+
+       samp[knifedrawsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:knifedraw.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[knifedrawsound], 8.0f, 2000.0f);
+
+       samp[knifesheathesound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:knifesheathe.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[knifesheathesound], 8.0f, 2000.0f);
+
+       samp[fleshstabsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:Fleshstab.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[fleshstabsound], 8.0f, 2000.0f);
+
+       samp[fleshstabremovesound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:Fleshstabremove.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[fleshstabremovesound], 8.0f, 2000.0f);
+
+       samp[knifeswishsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:knifeswish.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[knifeswishsound], 8.0f, 2000.0f);
+
+       samp[knifeslicesound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:knifeslice.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[knifeslicesound], 8.0f, 2000.0f);
+
+       samp[swordslicesound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:swordslice.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[swordslicesound], 8.0f, 2000.0f);
+
+       samp[skidsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:skid.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[skidsound], 8.0f, 2000.0f);
+
+       samp[snowskidsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:snowskid.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[snowskidsound], 8.0f, 2000.0f);
+
+       samp[bushrustle] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:bushrustle.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[bushrustle], 4.0f, 1000.0f);       
+
+       samp[clank1sound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:clank1.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[clank1sound], 8.0f, 2000.0f);
+
+       samp[clank2sound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:clank2.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[clank2sound], 8.0f, 2000.0f);
+
+       samp[clank3sound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:clank3.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[clank3sound], 8.0f, 2000.0f);
+
+       samp[clank4sound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:clank4.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[clank4sound], 8.0f, 2000.0f);
+
+       samp[consolesuccesssound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:consolesuccess.ogg", FSOUND_2D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[consolesuccesssound], 4.0f, 1000.0f);      
+
+       samp[consolefailsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:consolefail.ogg", FSOUND_2D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[consolefailsound], 4.0f, 1000.0f); 
+
+       samp[metalhitsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:MetalHit.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[metalhitsound], 8.0f, 2000.0f);
+
+       samp[clawslicesound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:clawslice.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[clawslicesound], 8.0f, 2000.0f);
+
+       samp[splattersound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:splatter.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[splattersound], 8.0f, 2000.0f);
+
+       samp[growlsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:Growl.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[growlsound], 1000.0f, 2000.0f);
+
+       samp[growl2sound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:Growl2.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[growl2sound], 1000.0f, 2000.0f);
+
+       samp[barksound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:bark.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[barksound], 1000.0f, 2000.0f);
+
+       samp[bark2sound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:bark2.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[bark2sound], 1000.0f, 2000.0f);
+
+       samp[bark3sound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:bark3.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[bark3sound], 1000.0f, 2000.0f);
+
+       samp[snarlsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:snarl.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[snarlsound], 1000.0f, 2000.0f);
+
+
+       samp[snarl2sound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:snarl2.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[snarl2sound], 1000.0f, 2000.0f);
+
+       samp[barkgrowlsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:barkgrowl.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[barkgrowlsound], 1000.0f, 2000.0f);
+
+       samp[rabbitattacksound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:rabbitattack.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[rabbitattacksound], 1000.0f, 2000.0f);
+
+       samp[rabbitattack2sound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:rabbitattack2.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[rabbitattack2sound], 1000.0f, 2000.0f);
+
+       samp[rabbitattack3sound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:rabbitattack3.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[rabbitattack3sound], 1000.0f, 2000.0f);
+
+       samp[rabbitattack4sound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:rabbitattack4.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[rabbitattack4sound], 1000.0f, 2000.0f);
+
+       samp[rabbitpainsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:rabbitpain.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[rabbitpainsound], 1000.0f, 2000.0f);
+
+       samp[rabbitpain1sound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:rabbitpain2.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[rabbitpain1sound], 1000.0f, 2000.0f);
+
+       /*samp[rabbitpain2sound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:rabbitpain2.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[rabbitpain2sound], 1000.0f, 2000.0f);
+       */
+       samp[rabbitchitter] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:rabbitchitter.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[rabbitchitter], 1000.0f, 2000.0f);
+
+       samp[rabbitchitter2] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:rabbitchitter2.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[rabbitchitter2], 1000.0f, 2000.0f);
+
+       samp[swordstaffsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:swordstaff.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[swordstaffsound], 8.0f, 2000.0f);
+
+       samp[staffbodysound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:staffbody.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[staffbodysound], 8.0f, 2000.0f);
+
+       samp[staffheadsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:staffhead.ogg", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[staffheadsound], 8.0f, 2000.0f);
+
+       samp[staffbreaksound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:staffbreak.wav", FSOUND_HW3D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[staffbreaksound], 8.0f, 2000.0f);
+
+
+
+}
+
+void Game::LoadTexture(char *fileName, GLuint *textureid,int mipmap, bool hasalpha)
+{
+       GLuint          type;
+
+       LOGFUNC;
+
+       LOG(std::string("Loading texture...") + fileName);
+
+       unsigned char fileNamep[256];
+       CopyCStringToPascal(fileName,fileNamep);
+       //Load Image
+       upload_image( fileNamep ,hasalpha); 
+
+//     std::string fname(fileName);
+//     std::transform(fname.begin(), fname.end(), tolower);
+//     TexIter it = textures.find(fname);
+
+       //Is it valid?
+       if(1==1)
+       //if(textures.end() == it)
+       {
+               //Alpha channel?
+               if ( texture.bpp == 24 )
+                       type = GL_RGB;
+               else
+                       type = GL_RGBA;
+
+               glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+               if(!*textureid)glGenTextures( 1, textureid );
+               glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+               glBindTexture( GL_TEXTURE_2D, *textureid);
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+               if(trilinear)if(mipmap)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
+               if(!trilinear)if(mipmap)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
+               if(!mipmap)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+
+               //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.sizeX, texture.sizeY, 0,
+               //          GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, texture.data);
+
+               //gluBuild2DMipmaps( GL_TEXTURE_2D, type, texture.sizeX, texture.sizeY, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, texture.data );
+
+               gluBuild2DMipmaps( GL_TEXTURE_2D, type, texture.sizeX, texture.sizeY, type, GL_UNSIGNED_BYTE, texture.data );
+
+//             textures.insert(std::make_pair(fname, *textureid));
+       }
+//     else
+//     {
+//             *textureid = it->second;
+//     }
+}
+
+void Game::LoadTextureSave(char *fileName, GLuint *textureid,int mipmap,GLubyte *array, int *skinsize)
+{
+       GLuint          type;
+       int i;
+       int bytesPerPixel;
+
+       LOGFUNC;
+
+       LOG(std::string("Loading texture (S)...") + fileName);
+
+       //Load Image
+       unsigned char fileNamep[256];
+       CopyCStringToPascal(fileName,fileNamep);
+       //Load Image
+       upload_image( fileNamep ,0); 
+       //LoadTGA( fileName ); 
+
+//     std::string fname(fileName);
+//     std::transform(fname.begin(), fname.end(), tolower);
+//     TexIter it = textures.find(fname);
+
+       //Is it valid?
+       if(1==1)
+       //if(textures.end() == it)
+       {
+               bytesPerPixel=texture.bpp/8;
+
+               //Alpha channel?
+               if ( texture.bpp == 24 )
+                       type = GL_RGB;
+               else
+                       type = GL_RGBA;
+
+               glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+               if(!*textureid)glGenTextures( 1, textureid );
+               glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+               glBindTexture( GL_TEXTURE_2D, *textureid);
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+               if(trilinear)if(mipmap)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
+               if(!trilinear)if(mipmap)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
+               if(!mipmap)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+
+               int tempnum=0;
+               for(i=0;i<(int)(texture.sizeY*texture.sizeX*bytesPerPixel);i++){
+                       if((i+1)%4||type==GL_RGB){
+                               array[tempnum]=texture.data[i];
+                               tempnum++;
+                       }
+               }
+
+               *skinsize=texture.sizeX;
+
+               gluBuild2DMipmaps( GL_TEXTURE_2D, type, texture.sizeX, texture.sizeY, GL_RGB, GL_UNSIGNED_BYTE, array );
+
+//             textures.insert(std::make_pair(fname, *textureid));
+       }
+//     else
+//     {
+//             *textureid = it->second;
+//     }
+}
+
+void Game::LoadSave(char *fileName, GLuint *textureid,bool mipmap,GLubyte *array, int *skinsize)
+{
+       int i;
+       int bytesPerPixel;
+
+       LOGFUNC;
+
+       LOG(std::string("Loading (S)...") + fileName);
+
+       //Load Image
+       float temptexdetail=texdetail;
+       texdetail=1;
+       //upload_image( fileName ); 
+       //LoadTGA( fileName ); 
+       //Load Image
+       unsigned char fileNamep[256];
+       CopyCStringToPascal(fileName,fileNamep);
+       //Load Image
+       upload_image( fileNamep ,0); 
+       texdetail=temptexdetail;
+
+       //Is it valid?
+       if(1==1){
+               bytesPerPixel=texture.bpp/8;
+
+               int tempnum=0;
+               for(i=0;i<(int)(texture.sizeY*texture.sizeX*bytesPerPixel);i++){
+                       if((i+1)%4||bytesPerPixel==3){
+                               array[tempnum]=texture.data[i];
+                               tempnum++;
+                       }
+               }
+       }
+}
+
+bool Game::AddClothes(char *fileName, GLuint *textureid,bool mipmap,GLubyte *array, int *skinsize)
+{
+       int i;
+       int bytesPerPixel;
+
+       LOGFUNC;
+
+       //upload_image( fileName ); 
+       //LoadTGA( fileName ); 
+       //Load Image
+       unsigned char fileNamep[256];
+       CopyCStringToPascal(fileName,fileNamep);
+       //Load Image
+       bool opened;
+       opened=upload_image( fileNamep ,1); 
+
+       float alphanum;
+       //Is it valid?
+       if(opened){
+               if(tintr>1)tintr=1;
+               if(tintg>1)tintg=1;
+               if(tintb>1)tintb=1;
+
+               if(tintr<0)tintr=0;
+               if(tintg<0)tintg=0;
+               if(tintb<0)tintb=0;
+
+               bytesPerPixel=texture.bpp/8;
+
+               int tempnum=0;
+               alphanum=255;
+               for(i=0;i<(int)(texture.sizeY*texture.sizeX*bytesPerPixel);i++){
+                       if(bytesPerPixel==3)alphanum=255;
+                       else if((i+1)%4==0)alphanum=texture.data[i];
+                       //alphanum/=2;
+                       if((i+1)%4||bytesPerPixel==3){
+                               if((i%4)==0)texture.data[i]*=tintr;
+                               if((i%4)==1)texture.data[i]*=tintg;
+                               if((i%4)==2)texture.data[i]*=tintb;
+                               array[tempnum]=(float)array[tempnum]*(1-alphanum/255)+(float)texture.data[i]*(alphanum/255);
+                               tempnum++;
+                       }
+               }
+       }
+       else return 0;
+       return 1;
+}
+
+
+//***************> ResizeGLScene() <******/
+GLvoid Game::ReSizeGLScene(float fov, float pnear)
+{
+       if (screenheight==0)
+       {
+               screenheight=1;
+       }
+
+       glViewport(0,0,screenwidth,screenheight);
+
+       glMatrixMode(GL_PROJECTION);
+       glLoadIdentity();
+
+       gluPerspective(fov,(GLfloat)screenwidth/(GLfloat)screenheight,pnear,viewdistance);
+
+       glMatrixMode(GL_MODELVIEW);                                                     
+       glLoadIdentity();                                                                       
+}
+
+void Game::LoadingScreen()                                                                             
+{
+       static float loadprogress,minprogress,maxprogress;
+       static AbsoluteTime time = {0,0};
+       static AbsoluteTime frametime = {0,0};
+       AbsoluteTime currTime = UpTime ();
+       double deltaTime = (float) AbsoluteDeltaToDuration (currTime, frametime);
+
+       if (0 > deltaTime)      // if negative microseconds
+               deltaTime /= -1000000.0;
+       else                            // else milliseconds
+               deltaTime /= 1000.0;
+
+       multiplier=deltaTime;
+       if(multiplier<.001)multiplier=.001;
+       if(multiplier>10)multiplier=10;
+       if(multiplier>.05){
+               frametime = currTime;   // reset for next time interval
+
+               float size=1;
+               glLoadIdentity();
+               //Clear to black
+               glClearColor(0,0,0,1);
+               glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+
+               loadtime+=multiplier*4;
+
+               loadprogress=loadtime;
+               if(loadprogress>100)loadprogress=100;
+
+               //loadprogress=abs(Random()%100);
+
+               //Background
+
+               glEnable(GL_TEXTURE_2D);
+               glBindTexture( GL_TEXTURE_2D, loadscreentexture);
+               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+               glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+               glDisable(GL_CULL_FACE);
+               glDisable(GL_LIGHTING);
+               glDepthMask(0);
+               glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+               glPushMatrix();                                                                         // Store The Projection Matrix
+               glLoadIdentity();                                                                       // Reset The Projection Matrix
+               glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+               glPushMatrix();                                                                         // Store The Modelview Matrix
+               glLoadIdentity();                                                               // Reset The Modelview Matrix
+               glTranslatef(screenwidth/2,screenheight/2,0);
+               glScalef((float)screenwidth/2,(float)screenheight/2,1);
+               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+               glDisable(GL_BLEND);
+               glColor4f(loadprogress/100,loadprogress/100,loadprogress/100,1);
+               //glColor4f(1,1,1,1);
+               /*if(loadscreencolor==0)glColor4f(1,1,1,1);
+               if(loadscreencolor==1)glColor4f(1,0,0,1);
+               if(loadscreencolor==2)glColor4f(0,1,0,1);
+               if(loadscreencolor==3)glColor4f(0,0,1,1);
+               if(loadscreencolor==4)glColor4f(1,1,0,1);
+               if(loadscreencolor==5)glColor4f(1,0,1,1);
+               */
+               glPushMatrix();
+               //glScalef(.25,.25,.25);
+               glBegin(GL_QUADS);
+               glTexCoord2f(.1-loadprogress/100,0+loadprogress/100+.3);
+               glVertex3f(-1,          -1,      0.0f);
+               glTexCoord2f(.1-loadprogress/100,0+loadprogress/100+.3);
+               glVertex3f(1,   -1,      0.0f);
+               glTexCoord2f(.1-loadprogress/100,1+loadprogress/100+.3);
+               glVertex3f(1,   1, 0.0f);
+               glTexCoord2f(.1-loadprogress/100,1+loadprogress/100+.3);
+               glVertex3f(-1,  1, 0.0f);
+               glEnd();
+               glPopMatrix();
+               glEnable(GL_BLEND);
+               glPushMatrix();
+               //glScalef(.25,.25,.25);
+               glBegin(GL_QUADS);
+               glTexCoord2f(.4+loadprogress/100,0+loadprogress/100);
+               glVertex3f(-1,          -1,      0.0f);
+               glTexCoord2f(.4+loadprogress/100,0+loadprogress/100);
+               glVertex3f(1,   -1,      0.0f);
+               glTexCoord2f(.4+loadprogress/100,1+loadprogress/100);
+               glVertex3f(1,   1, 0.0f);
+               glTexCoord2f(.4+loadprogress/100,1+loadprogress/100);
+               glVertex3f(-1,  1, 0.0f);
+               glEnd();
+               glPopMatrix();
+               glDisable(GL_TEXTURE_2D);
+               glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+               glPopMatrix();                                                                          // Restore The Old Projection Matrix
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+               glPopMatrix();                                                                          // Restore The Old Projection Matrix
+               glDisable(GL_BLEND);
+               glDepthMask(1);
+
+               glEnable(GL_TEXTURE_2D);
+               glBindTexture( GL_TEXTURE_2D, loadscreentexture);
+               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+               glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+               glDisable(GL_CULL_FACE);
+               glDisable(GL_LIGHTING);
+               glDepthMask(0);
+               glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+               glPushMatrix();                                                                         // Store The Projection Matrix
+               glLoadIdentity();                                                                       // Reset The Projection Matrix
+               glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+               glPushMatrix();                                                                         // Store The Modelview Matrix
+               glLoadIdentity();                                                               // Reset The Modelview Matrix
+               glTranslatef(screenwidth/2,screenheight/2,0);
+               glScalef((float)screenwidth/2*(1.5-(loadprogress)/200),(float)screenheight/2*(1.5-(loadprogress)/200),1);
+               glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+               glEnable(GL_BLEND);
+               //glColor4f(loadprogress/100,loadprogress/100,loadprogress/100,1);
+               glColor4f(loadprogress/100,loadprogress/100,loadprogress/100,1);
+               /*if(loadscreencolor==0)glColor4f(1,1,1,1);
+               if(loadscreencolor==1)glColor4f(1,0,0,1);
+               if(loadscreencolor==2)glColor4f(0,1,0,1);
+               if(loadscreencolor==3)glColor4f(0,0,1,1);
+               if(loadscreencolor==4)glColor4f(1,1,0,1);
+               if(loadscreencolor==5)glColor4f(1,0,1,1);
+               */
+               glPushMatrix();
+               //glScalef(.25,.25,.25);
+               glBegin(GL_QUADS);
+               glTexCoord2f(0+.5,0+.5);
+               glVertex3f(-1,          -1,      0.0f);
+               glTexCoord2f(1+.5,0+.5);
+               glVertex3f(1,   -1,      0.0f);
+               glTexCoord2f(1+.5,1+.5);
+               glVertex3f(1,   1, 0.0f);
+               glTexCoord2f(0+.5,1+.5);
+               glVertex3f(-1,  1, 0.0f);
+               glEnd();
+               glPopMatrix();
+               glDisable(GL_TEXTURE_2D);
+               glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+               glPopMatrix();                                                                          // Restore The Old Projection Matrix
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+               glPopMatrix();                                                                          // Restore The Old Projection Matrix
+               glDisable(GL_BLEND);
+               glDepthMask(1);
+
+               glEnable(GL_TEXTURE_2D);
+               glBindTexture( GL_TEXTURE_2D, loadscreentexture);
+               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+               glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+               glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+               glDisable(GL_CULL_FACE);
+               glDisable(GL_LIGHTING);
+               glDepthMask(0);
+               glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+               glPushMatrix();                                                                         // Store The Projection Matrix
+               glLoadIdentity();                                                                       // Reset The Projection Matrix
+               glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+               glPushMatrix();                                                                         // Store The Modelview Matrix
+               glLoadIdentity();                                                               // Reset The Modelview Matrix
+               glTranslatef(screenwidth/2,screenheight/2,0);
+               glScalef((float)screenwidth/2*(100+loadprogress)/100,(float)screenheight/2*(100+loadprogress)/100,1);
+               glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+               glEnable(GL_BLEND);
+               glColor4f(loadprogress/100,loadprogress/100,loadprogress/100,.4);
+               glPushMatrix();
+               //glScalef(.25,.25,.25);
+               glBegin(GL_QUADS);
+               glTexCoord2f(0+.2,0+.8);
+               glVertex3f(-1,          -1,      0.0f);
+               glTexCoord2f(1+.2,0+.8);
+               glVertex3f(1,   -1,      0.0f);
+               glTexCoord2f(1+.2,1+.8);
+               glVertex3f(1,   1, 0.0f);
+               glTexCoord2f(0+.2,1+.8);
+               glVertex3f(-1,  1, 0.0f);
+               glEnd();
+               glPopMatrix();
+               glDisable(GL_TEXTURE_2D);
+               glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+               glPopMatrix();                                                                          // Restore The Old Projection Matrix
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+               glPopMatrix();                                                                          // Restore The Old Projection Matrix
+               glDisable(GL_BLEND);
+               glDepthMask(1);
+
+               //Text
+               /*
+               glEnable(GL_TEXTURE_2D);
+               static char string[256]="";
+               sprintf (string, "LOADING... %d%",(int)loadprogress);
+               glColor4f(1,1,1,.2);
+               text.glPrint(280-280*loadprogress/100/2/4,125-125*loadprogress/100/2/4,string,1,1+loadprogress/100,640,480);
+               glColor4f(1.2-loadprogress/100,1.2-loadprogress/100,1.2-loadprogress/100,1);
+               text.glPrint(280,125,string,1,1,640,480);
+               */
+
+               if(flashamount>0){
+                       if(flashamount>1)flashamount=1;
+                       if(flashdelay<=0)flashamount-=multiplier;
+                       flashdelay--;
+                       if(flashamount<0)flashamount=0;
+                       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+                       glDisable(GL_CULL_FACE);
+                       glDisable(GL_LIGHTING);
+                       glDisable(GL_TEXTURE_2D);
+                       glDepthMask(0);
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPushMatrix();                                                                         // Store The Projection Matrix
+                       glLoadIdentity();                                                                       // Reset The Projection Matrix
+                       glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPushMatrix();                                                                         // Store The Modelview Matrix
+                       glLoadIdentity();                                                               // Reset The Modelview Matrix
+                       glScalef(screenwidth,screenheight,1);
+                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       glEnable(GL_BLEND);
+                       glColor4f(flashr,flashg,flashb,flashamount);
+                       glBegin(GL_QUADS);
+                       glVertex3f(0,           0,       0.0f);
+                       glVertex3f(256, 0,       0.0f);
+                       glVertex3f(256, 256, 0.0f);
+                       glVertex3f(0,   256, 0.0f);
+                       glEnd();
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+                       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+                       glEnable(GL_CULL_FACE);
+                       glDisable(GL_BLEND);
+                       glDepthMask(1);
+               }       
+
+#ifdef WIN32
+               SwapBuffers( hDC);
+#else
+               aglSwapBuffers(gaglContext);
+#endif
+
+               loadscreencolor=0;
+       }
+}
+
+void Game::FadeLoadingScreen(float howmuch)                                                                            
+{
+       static float loadprogress,minprogress,maxprogress;
+
+       float size=1;
+       glLoadIdentity();
+       //Clear to black
+       glClearColor(0,0,0,1);
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+       loadprogress=howmuch;
+
+       //loadprogress=abs(Random()%100);
+
+       //Background
+
+       //glEnable(GL_TEXTURE_2D);
+       glDisable(GL_TEXTURE_2D);
+       //glBindTexture( GL_TEXTURE_2D, loadscreentexture);
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+       glDisable(GL_CULL_FACE);
+       glDisable(GL_LIGHTING);
+       glDepthMask(0);
+       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+       glPushMatrix();                                                                         // Store The Projection Matrix
+       glLoadIdentity();                                                                       // Reset The Projection Matrix
+       glOrtho(0,screenwidth,0,screenheight,-100,100);                                         // Set Up An Ortho Screen
+       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+       glPushMatrix();                                                                         // Store The Modelview Matrix
+       glLoadIdentity();                                                               // Reset The Modelview Matrix
+       glTranslatef(screenwidth/2,screenheight/2,0);
+       glScalef((float)screenwidth/2,(float)screenheight/2,1);
+       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+       glDisable(GL_BLEND);
+       glColor4f(loadprogress/100,0,0,1);
+       /*if(loadscreencolor==0)glColor4f(1,1,1,1);
+       if(loadscreencolor==1)glColor4f(1,0,0,1);
+       if(loadscreencolor==2)glColor4f(0,1,0,1);
+       if(loadscreencolor==3)glColor4f(0,0,1,1);
+       if(loadscreencolor==4)glColor4f(1,1,0,1);
+       if(loadscreencolor==5)glColor4f(1,0,1,1);
+       */
+       glPushMatrix();
+       //glScalef(.25,.25,.25);
+       glBegin(GL_QUADS);
+       glTexCoord2f(0,0);
+       glVertex3f(-1,          -1,      0.0f);
+       glTexCoord2f(1,0);
+       glVertex3f(1,   -1,      0.0f);
+       glTexCoord2f(1,1);
+       glVertex3f(1,   1, 0.0f);
+       glTexCoord2f(0,1);
+       glVertex3f(-1,  1, 0.0f);
+       glEnd();
+       glPopMatrix();
+       glDisable(GL_TEXTURE_2D);
+       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+       glDisable(GL_BLEND);
+       glDepthMask(1);
+       //Text
+       /*
+       glEnable(GL_TEXTURE_2D);
+       static char string[256]="";
+       sprintf (string, "LOADING... %d%",(int)loadprogress);
+       glColor4f(1,1,1,.2);
+       text.glPrint(280-280*loadprogress/100/2/4,125-125*loadprogress/100/2/4,string,1,1+loadprogress/100,640,480);
+       glColor4f(1.2-loadprogress/100,1.2-loadprogress/100,1.2-loadprogress/100,1);
+       text.glPrint(280,125,string,1,1,640,480);
+       */
+#ifdef WIN32
+       SwapBuffers( hDC);
+#else
+       aglSwapBuffers(gaglContext); // send swap command
+#endif
+
+       loadscreencolor=0;
+}
+
+
+void Game::InitGame()                                                                          
+{
+#ifndef WIN32
+       ProcessSerialNumber PSN;
+       ProcessInfoRec pinfo;
+       FSSpec pspec;
+       OSStatus err;
+       /* set up process serial number */
+       PSN.highLongOfPSN = 0;
+       PSN.lowLongOfPSN = kCurrentProcess;
+       /* set up info block */
+       pinfo.processInfoLength = sizeof(pinfo);
+       pinfo.processName = NULL;
+       pinfo.processAppSpec = &pspec;
+       /* grab the vrefnum and directory */
+       err = GetProcessInformation(&PSN, &pinfo);
+       if (err == noErr) {
+               vRefNum = pspec.vRefNum;
+               dirID = pspec.parID;
+       }
+#endif
+
+       LOGFUNC;
+
+       autocam=0;
+
+       int i,j;
+
+       numchallengelevels=14;
+
+       registered=0;
+
+       /*char tempstring[256];
+       sprintf (tempstring, "%s", registrationname);
+       long num1;
+       long num2;
+       long num3;
+       long num4;
+       long long longnum;
+       longnum = MD5_string ( tempstring);
+       //longnum = 1111111111111111;
+       num1 = longnum/100000000;
+       num2 = longnum%100000000;
+       sprintf (tempstring, "%d-%d-%d-%d", num1/10000, num1%10000, num2/10000, num2%10000);
+       */
+
+       FILE                    *tfile;
+       tfile=fopen( ":Data:Sounds:flame.ogg", "rb" );
+       if(tfile)
+       {
+               long num1;
+               long num2;
+               long long longnum;
+               long long longnuma;
+               long num1a;
+               long num2a;
+
+               int numchars;
+               funpackf(tfile, "Bb", &registered);
+               if(registered)
+               {
+                       funpackf(tfile, "Bi", &numchars);
+                       if(numchars>0)
+                       {
+                               for(j=0;j<numchars;j++)
+                               {
+                                       funpackf(tfile, "Bb",  &registrationname[j]);
+                               }
+                               registrationname[numchars]='\0';
+                               funpackf(tfile, "Bi", &num1);
+                               funpackf(tfile, "Bi", &num2);
+                               longnum=num2+num1*100000000;
+
+                               char tempstring[256];
+                               sprintf (tempstring, "%s-windows", registrationname);
+                               longnuma = MD5_string ( tempstring);    
+                               num1a = longnuma/100000000;
+                               num2a = longnuma%100000000;
+                               //if(num1a==num1&&num2a==num2)registered=1;
+                               if(numchars>2)registered=1;
+                               else registered=0;
+                       }
+               }
+               fclose(tfile);
+       }
+       else registered=0;
+
+       accountactive=-1;
+
+       sprintf (mapname, ":Data:Users");
+       tfile=fopen( mapname, "rb" );
+       if(tfile)
+       {
+               funpackf(tfile, "Bi", &numaccounts);
+               funpackf(tfile, "Bi", &accountactive);
+               if(numaccounts>0)
+               {
+                       for(i=0;i<numaccounts;i++)
+                       {
+                               funpackf(tfile, "Bf", &accountcampaigntime[i]);
+                               funpackf(tfile, "Bf", &accountcampaignscore[i]);
+                               funpackf(tfile, "Bf", &accountcampaignfasttime[i]);
+                               funpackf(tfile, "Bf", &accountcampaignhighscore[i]);
+                               funpackf(tfile, "Bi", &accountdifficulty[i]);
+                               funpackf(tfile, "Bi", &accountprogress[i]);
+                               funpackf(tfile, "Bi", &accountcampaignchoicesmade[i]);
+                               for(j=0;j<accountcampaignchoicesmade[i];j++)
+                               {
+                                       funpackf(tfile, "Bi", &accountcampaignchoices[i][j]);
+                                       if (accountcampaignchoices[i][j] >= 10)
+                                       {
+                                               accountcampaignchoices[i][j] = 0;
+                                       }
+                               }
+                               funpackf(tfile, "Bf", &accountpoints[i]);
+                               for(j=0;j<50;j++)
+                               {
+                                       funpackf(tfile, "Bf", &accounthighscore[i][j]);
+                                       funpackf(tfile, "Bf", &accountfasttime[i][j]);
+                               }
+                               for(j=0;j<60;j++)
+                               {
+                                       funpackf(tfile, "Bb",  &accountunlocked[i][j]);
+                               }
+                               int temp;
+                               funpackf(tfile, "Bi",  &temp);
+                               if(temp>0)
+                               {
+                                       for(j=0;j<temp;j++)
+                                       {
+                                               funpackf(tfile, "Bb",  &accountname[i][j]);
+                                       }
+                               }
+                       }
+               }
+
+               fclose(tfile);
+       }
+
+       tintr=1;
+       tintg=1;
+       tintb=1;
+
+       whichjointstartarray[0]=righthip;
+       whichjointendarray[0]=rightfoot;
+
+       whichjointstartarray[1]=righthip;
+       whichjointendarray[1]=rightankle;
+
+       whichjointstartarray[2]=righthip;
+       whichjointendarray[2]=rightknee;
+
+       whichjointstartarray[3]=rightknee;
+       whichjointendarray[3]=rightankle;
+
+       whichjointstartarray[4]=rightankle;
+       whichjointendarray[4]=rightfoot;
+
+       whichjointstartarray[5]=lefthip;
+       whichjointendarray[5]=leftfoot;
+
+       whichjointstartarray[6]=lefthip;
+       whichjointendarray[6]=leftankle;
+
+       whichjointstartarray[7]=lefthip;
+       whichjointendarray[7]=leftknee;
+
+       whichjointstartarray[8]=leftknee;
+       whichjointendarray[8]=leftankle;
+
+       whichjointstartarray[9]=leftankle;
+       whichjointendarray[9]=leftfoot;
+
+       whichjointstartarray[10]=abdomen;
+       whichjointendarray[10]=rightshoulder;
+
+       whichjointstartarray[11]=abdomen;
+       whichjointendarray[11]=rightelbow;
+
+       whichjointstartarray[12]=abdomen;
+       whichjointendarray[12]=rightwrist;
+
+       whichjointstartarray[13]=abdomen;
+       whichjointendarray[13]=righthand;
+
+       whichjointstartarray[14]=rightshoulder;
+       whichjointendarray[14]=rightelbow;
+
+       whichjointstartarray[15]=rightelbow;
+       whichjointendarray[15]=rightwrist;
+
+       whichjointstartarray[16]=rightwrist;
+       whichjointendarray[16]=righthand;
+
+       whichjointstartarray[17]=abdomen;
+       whichjointendarray[17]=leftshoulder;
+
+       whichjointstartarray[18]=abdomen;
+       whichjointendarray[18]=leftelbow;
+
+       whichjointstartarray[19]=abdomen;
+       whichjointendarray[19]=leftwrist;
+
+       whichjointstartarray[20]=abdomen;
+       whichjointendarray[20]=lefthand;
+
+       whichjointstartarray[21]=leftshoulder;
+       whichjointendarray[21]=leftelbow;
+
+       whichjointstartarray[22]=leftelbow;
+       whichjointendarray[22]=leftwrist;
+
+       whichjointstartarray[23]=leftwrist;
+       whichjointendarray[23]=lefthand;
+
+       whichjointstartarray[24]=abdomen;
+       whichjointendarray[24]=neck;
+
+       whichjointstartarray[25]=neck;
+       whichjointendarray[25]=head;
+
+       FadeLoadingScreen(0);
+
+       stillloading=1;
+
+       texture.data = ( GLubyte* )malloc( 1024*1024*4 );
+
+       int temptexdetail=texdetail;
+       texdetail=1;
+       text.LoadFontTexture(":Data:Textures:Font.png");
+       text.BuildFont();
+       texdetail=temptexdetail;
+
+       FadeLoadingScreen(10);
+
+       if(detail==2){
+               texdetail=1;
+               terraindetail=1;
+       }
+       if(detail==1){
+               texdetail=2;
+               terraindetail=1;
+       }
+       if(detail==0){
+               texdetail=4;
+               terraindetail=1;
+               //terraindetail=2;
+       }
+
+       for (int it = 0; it < 100; ++it)
+       {
+               channels[it] = -1;
+               samp[it] = NULL;
+       }
+       for (int it = 0; it < 20; ++it)
+       {
+               strm[it] = NULL;
+       }
+
+       LOG("Initializing sound system...");
+
+       FSOUND_Init(44100, 32, 0);
+
+       FSOUND_SetSFXMasterVolume((int)(volume*255));
+
+       strm[stream_music3] = FSOUND_Stream_Open(ConvertFileName(":Data:Sounds:music3.mp3"), FSOUND_2D, 0, 0); if(visibleloading){LoadingScreen(); loadscreencolor=0;}
+//     FSOUND_Sample_SetMinMaxDistance(strm[stream_music3], 4.0f, 1000.0f);    
+       FSOUND_Stream_SetMode(strm[stream_music3], FSOUND_LOOP_NORMAL);
+
+       if(musictoggle){
+//             PlaySoundEx( stream_music3, strm[stream_music3], NULL, TRUE);
+               PlayStreamEx(stream_music3, strm[stream_music3], 0, TRUE);
+               FSOUND_SetPaused(channels[stream_music3], FALSE);
+               FSOUND_SetVolume(channels[stream_music3], 256);
+       }
+
+       FadeLoadingScreen(20);
+
+       if(ambientsound){
+               strm[stream_wind] = FSOUND_Stream_Open(ConvertFileName(":Data:Sounds:wind.mp3"), FSOUND_2D, 0, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+//             FSOUND_Sample_SetMinMaxDistance(strm[stream_wind], 4.0f, 1000.0f);      
+               FSOUND_Stream_SetMode(strm[stream_wind], FSOUND_LOOP_NORMAL);
+
+               FadeLoadingScreen(30);
+
+               strm[stream_desertambient] = FSOUND_Stream_Open(ConvertFileName(":Data:Sounds:desertambient.mp3"), FSOUND_2D, 0, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+//             FSOUND_Sample_SetMinMaxDistance(strm[stream_desertambient], 4.0f, 1000.0f);     
+               FSOUND_Stream_SetMode(strm[stream_desertambient], FSOUND_LOOP_NORMAL);
+       }
+
+       FadeLoadingScreen(40);
+
+       samp[firestartsound] = FSOUND_Sample_Load(FSOUND_FREE, ConvertFileName(":Data:Sounds:firestart.ogg"), FSOUND_2D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+       strm[stream_firesound] = FSOUND_Stream_Open(":Data:Sounds:fire.ogg", FSOUND_2D, 0, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+//     FSOUND_Sample_SetMinMaxDistance(strm[stream_firesound], 8.0f, 2000.0f); 
+       FSOUND_Stream_SetMode(strm[stream_firesound], FSOUND_LOOP_NORMAL);
+
+       FadeLoadingScreen(50);
+
+       samp[fireendsound] = FSOUND_Sample_Load(FSOUND_FREE, ConvertFileName(":Data:Sounds:fireend.ogg"), FSOUND_2D, 0); if(visibleloading){LoadingScreen(); loadscreencolor=5;}
+       FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+       //if(musictoggle){
+       strm[stream_music1grass] = FSOUND_Stream_Open(ConvertFileName(":Data:Sounds:music1grass.mp3"), FSOUND_2D, 0, 0); if(visibleloading){LoadingScreen(); loadscreencolor=1;}
+//     FSOUND_Sample_SetMinMaxDistance(strm[stream_music1grass], 4.0f, 1000.0f);       
+       FSOUND_Stream_SetMode(strm[stream_music1grass], FSOUND_LOOP_NORMAL);
+
+       strm[stream_music1snow] = FSOUND_Stream_Open(ConvertFileName(":Data:Sounds:music1snow.mp3"), FSOUND_2D, 0, 0); if(visibleloading){LoadingScreen(); loadscreencolor=2;}
+//     FSOUND_Sample_SetMinMaxDistance(strm[stream_music1snow], 4.0f, 1000.0f);        
+       FSOUND_Stream_SetMode(strm[stream_music1snow], FSOUND_LOOP_NORMAL);
+
+       FadeLoadingScreen(60);
+
+       strm[stream_music1desert] = FSOUND_Stream_Open(ConvertFileName(":Data:Sounds:music1desert.mp3"), FSOUND_2D, 0, 0); if(visibleloading){LoadingScreen(); loadscreencolor=3;}
+//     FSOUND_Sample_SetMinMaxDistance(strm[stream_music1desert], 4.0f, 1000.0f);      
+       FSOUND_Stream_SetMode(strm[stream_music1desert], FSOUND_LOOP_NORMAL);
+
+       FadeLoadingScreen(80);
+       strm[stream_music2] = FSOUND_Stream_Open(ConvertFileName(":Data:Sounds:music2.ogg"), FSOUND_2D, 0, 0); if(visibleloading){LoadingScreen(); loadscreencolor=4;}
+//     FSOUND_Sample_SetMinMaxDistance(strm[stream_music2], 4.0f, 1000.0f);    
+       FSOUND_Stream_SetMode(strm[stream_music2], FSOUND_LOOP_NORMAL);
+
+       //}
+
+
+       FadeLoadingScreen(90);
+
+
+       LoadTexture(":Data:Textures:Cursor.png",&cursortexture,0,1);
+
+       LoadTexture(":Data:Textures:MapCircle.png",&Mapcircletexture,0,1);
+       LoadTexture(":Data:Textures:MapBox.png",&Mapboxtexture,0,1);
+       LoadTexture(":Data:Textures:MapArrow.png",&Maparrowtexture,0,1);
+
+       temptexdetail=texdetail;
+       if(texdetail>2)texdetail=2;
+       LoadTexture(":Data:Textures:Lugaru.png",&Mainmenuitems[0],0,0);
+       LoadTexture(":Data:Textures:Newgame.png",&Mainmenuitems[1],0,0);
+       LoadTexture(":Data:Textures:Options.png",&Mainmenuitems[2],0,0);
+       LoadTexture(":Data:Textures:Quit.png",&Mainmenuitems[3],0,0);
+       LoadTexture(":Data:Textures:World.png",&Mainmenuitems[7],0,0);
+       LoadTexture(":Data:Textures:Eyelid.png",&Mainmenuitems[4],0,1);
+       //LoadTexture(":Data:Textures:Eye.jpg",&Mainmenuitems[5],0,1);
+       texdetail=temptexdetail;
+
+       loaddistrib=0;
+       anim=0;
+
+       FadeLoadingScreen(95);
+
+
+       gameon=0;
+       mainmenu=1;
+
+       stillloading=0;
+       firstload=0;
+       oldmainmenu=0;
+
+       newdetail=detail;
+       newscreenwidth=screenwidth;
+       newscreenheight=screenheight;
+
+       
+       
+       /*
+       float gLoc[3]={0,0,0};
+       float vel[3]={0,0,0};
+       FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+       PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+       FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+       FSOUND_SetVolume(channels[firestartsound], 256);
+       FSOUND_SetPaused(channels[firestartsound], FALSE);
+       FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+       flashr=1;
+       flashg=0;
+       flashb=0;
+       flashamount=1;
+       flashdelay=1;
+       */
+}
+
+
+void Game::LoadStuff()                                                                         
+{
+       static float temptexdetail;
+       static float viewdistdetail;
+       static int i,j,texsize; 
+       float megascale =1;
+
+       LOGFUNC;
+
+       visibleloading=1;
+
+       /*musicvolume[3]=512;
+       PlaySoundEx( music4, samp[music4], NULL, TRUE);
+       FSOUND_SetPaused(channels[music4], FALSE);
+       FSOUND_SetVolume(channels[music4], 512);
+       */
+       loadtime=0;
+
+       stillloading=1;
+
+       //texture.data = ( GLubyte* )malloc( 1024*1024*4 );
+
+       newnetmessages=0;
+
+       for(i=0;i<maxplayers;i++)
+       {
+               if (glIsTexture(player[i].skeleton.drawmodel.textureptr))
+               {
+                       glDeleteTextures(1, &player[i].skeleton.drawmodel.textureptr);
+               }
+               player[i].skeleton.drawmodel.textureptr=0;;
+       }
+
+       //temptexdetail=texdetail;
+       //texdetail=1;
+       i=abs(Random()%4);
+       LoadTexture(":Data:Textures:fire.jpg",&loadscreentexture,1,0);
+       //texdetail=temptexdetail;
+
+       temptexdetail=texdetail;
+       texdetail=1;
+       text.LoadFontTexture(":Data:Textures:Font.png");
+       text.BuildFont();
+       texdetail=temptexdetail;
+
+       numsounds=71;           
+
+       viewdistdetail=2;
+       viewdistance=50*megascale*viewdistdetail;
+
+       brightness=100;
+
+
+
+       if(detail==2){
+               texdetail=1;
+               terraindetail=1;
+       }
+       if(detail==1){
+               texdetail=2;
+               terraindetail=1;
+       }
+       if(detail==0){
+               texdetail=4;
+               terraindetail=1;
+               //terraindetail=2;
+       }
+
+       realtexdetail=texdetail;
+
+       /*texdetail/=4;
+       if(texdetail<1)texdetail=1;
+       realtexdetail=texdetail*4;
+       */
+       numplayers=1;
+
+
+
+       /*LoadTexture(":Data:Textures:snow.png",&terraintexture,1);
+
+       LoadTexture(":Data:Textures:rock.png",&terraintexture2,1);
+
+       LoadTexture(":Data:Textures:detail.png",&terraintexture3,1);
+       */
+
+
+       LOG("Loading weapon data...");
+
+       LoadTexture(":Data:Textures:knife.png",&weapons.knifetextureptr,0,1);
+       LoadTexture(":Data:Textures:bloodknife.png",&weapons.bloodknifetextureptr,0,1);
+       LoadTexture(":Data:Textures:lightbloodknife.png",&weapons.lightbloodknifetextureptr,0,1);
+       LoadTexture(":Data:Textures:sword.jpg",&weapons.swordtextureptr,1,0);
+       LoadTexture(":Data:Textures:Swordblood.jpg",&weapons.bloodswordtextureptr,1,0);
+       LoadTexture(":Data:Textures:Swordbloodlight.jpg",&weapons.lightbloodswordtextureptr,1,0);
+       LoadTexture(":Data:Textures:Staff.jpg",&weapons.stafftextureptr,1,0);
+
+       weapons.throwingknifemodel.load((char *)":Data:Models:throwingknife.solid",1);
+       weapons.throwingknifemodel.Scale(.001,.001,.001);
+       //weapons.throwingknifemodel.Rotate(0,0,-90);
+       weapons.throwingknifemodel.Rotate(90,0,0);
+       weapons.throwingknifemodel.Rotate(0,90,0);
+       weapons.throwingknifemodel.flat=0;
+       weapons.throwingknifemodel.CalculateNormals(1);
+       //weapons.throwingknifemodel.ScaleNormals(-1,-1,-1);
+
+       weapons.swordmodel.load((char *)":Data:Models:sword.solid",1);
+       weapons.swordmodel.Scale(.001,.001,.001);
+       //weapons.swordmodel.Rotate(0,0,-90);
+       weapons.swordmodel.Rotate(90,0,0);
+       weapons.swordmodel.Rotate(0,90,0);
+       weapons.swordmodel.Rotate(0,0,90);
+       weapons.swordmodel.flat=1;
+       weapons.swordmodel.CalculateNormals(1);
+       //weapons.swordmodel.ScaleNormals(-1,-1,-1);
+
+       weapons.staffmodel.load((char *)":Data:Models:staff.solid",1);
+       weapons.staffmodel.Scale(.005,.005,.005);
+       //weapons.staffmodel.Rotate(0,0,-90);
+       weapons.staffmodel.Rotate(90,0,0);
+       weapons.staffmodel.Rotate(0,90,0);
+       weapons.staffmodel.Rotate(0,0,90);
+       weapons.staffmodel.flat=1;
+       weapons.staffmodel.CalculateNormals(1);
+       //weapons.staffmodel.ScaleNormals(-1,-1,-1);
+
+       //temptexdetail=texdetail;
+       //if(texdetail>4)texdetail=4;
+       LoadTexture(":Data:Textures:shadow.png",&terrain.shadowtexture,0,1);
+
+       LoadTexture(":Data:Textures:blood.png",&terrain.bloodtexture,0,1);
+
+       LoadTexture(":Data:Textures:break.png",&terrain.breaktexture,0,1);
+
+       LoadTexture(":Data:Textures:blood.png",&terrain.bloodtexture2,0,1);
+
+
+       LoadTexture(":Data:Textures:footprint.png",&terrain.footprinttexture,0,1);
+
+       LoadTexture(":Data:Textures:bodyprint.png",&terrain.bodyprinttexture,0,1);
+
+       /*LoadTexture(":Data:Textures:cloud.png",&sprites.cloudtexture,1);
+
+       LoadTexture(":Data:Textures:cloudimpact.png",&sprites.cloudimpacttexture,1);
+
+       LoadTexture(":Data:Textures:bloodparticle.png",&sprites.bloodtexture,1);
+
+       LoadTexture(":Data:Textures:snowflake.png",&sprites.snowflaketexture,1);
+
+       LoadTexture(":Data:Textures:flame.png",&sprites.flametexture,1);
+
+       LoadTexture(":Data:Textures:smoke.png",&sprites.smoketexture,1);
+       //texdetail=temptexdetail;
+       LoadTexture(":Data:Textures:shine.png",&sprites.shinetexture,1);*/
+
+
+
+       LoadTexture(":Data:Textures:hawk.png",&hawktexture,0,1);
+
+       LoadTexture(":Data:Textures:logo.png",&logotexture,0,1);
+
+
+       //LoadTexture(":Data:Textures:box.jpg",&objects.boxtextureptr,1,0);
+
+
+       LoadTexture(":Data:Textures:cloud.png",&sprites.cloudtexture,1,1);
+       LoadTexture(":Data:Textures:cloudimpact.png",&sprites.cloudimpacttexture,1,1);
+       LoadTexture(":Data:Textures:bloodparticle.png",&sprites.bloodtexture,1,1);
+       LoadTexture(":Data:Textures:snowflake.png",&sprites.snowflaketexture,1,1);
+       LoadTexture(":Data:Textures:flame.png",&sprites.flametexture,1,1);
+       LoadTexture(":Data:Textures:bloodflame.png",&sprites.bloodflametexture,1,1);
+       LoadTexture(":Data:Textures:smoke.png",&sprites.smoketexture,1,1);
+       LoadTexture(":Data:Textures:shine.png",&sprites.shinetexture,1,0);
+       LoadTexture(":Data:Textures:splinter.png",&sprites.splintertexture,1,1);
+       LoadTexture(":Data:Textures:leaf.png",&sprites.leaftexture,1,1);
+       LoadTexture(":Data:Textures:tooth.png",&sprites.toothtexture,1,1);
+
+       rotation=0;
+       rotation2=0;
+       ReSizeGLScene(90,.01);
+
+       viewer=0;
+
+
+
+
+       if(detail)kTextureSize=1024;
+       if(detail==1)kTextureSize=512;
+       if(detail==0)kTextureSize=256;
+
+
+       //drawmode=motionblurmode;
+
+       //Set up distant light
+       light.color[0]=.95;
+       light.color[1]=.95;
+       light.color[2]=1;
+       light.ambient[0]=.2;
+       light.ambient[1]=.2;
+       light.ambient[2]=.24;
+       light.location.x=1;
+       light.location.y=1;
+       light.location.z=-.2;
+       Normalise(&light.location);
+
+       LoadingScreen();
+
+       SetUpLighting();
+
+
+       fadestart=.6;
+       gravity=-10;
+
+       texscale=.2/megascale/viewdistdetail;
+       terrain.scale=3*megascale*terraindetail*viewdistdetail;
+
+       viewer.x=terrain.size/2*terrain.scale;
+       viewer.z=terrain.size/2*terrain.scale;
+
+       hawk.load((char *)":Data:Models:hawk.solid",1);
+       hawk.Scale(.03,.03,.03);
+       hawk.Rotate(90,1,1);
+       hawk.CalculateNormals(0);
+       hawk.ScaleNormals(-1,-1,-1);
+       hawkcoords.x=terrain.size/2*terrain.scale-5-7;
+       hawkcoords.z=terrain.size/2*terrain.scale-5-7;
+       hawkcoords.y=terrain.getHeight(hawkcoords.x,hawkcoords.z)+25;
+
+
+       eye.load((char *)":Data:Models:eye.solid",1);
+       eye.Scale(.03,.03,.03);
+       eye.CalculateNormals(0);
+
+       cornea.load((char *)":Data:Models:cornea.solid",1);
+       cornea.Scale(.03,.03,.03);
+       cornea.CalculateNormals(0);
+
+       iris.load((char *)":Data:Models:iris.solid",1);
+       iris.Scale(.03,.03,.03);
+       iris.CalculateNormals(0);
+
+       LoadSave(":Data:Textures:Bloodfur.png",0,1,&bloodText[0],0);
+       LoadSave(":Data:Textures:Wolfbloodfur.png",0,1,&wolfbloodText[0],0);
+
+       oldenvironment=-4;
+
+       gameon=1;
+       mainmenu=0;
+
+       firstload=0;
+       //if(targetlevel!=7)
+               Loadlevel(targetlevel);
+
+
+       rabbitcoords=player[0].coords;
+       rabbitcoords.y=terrain.getHeight(rabbitcoords.x,rabbitcoords.z);
+
+       animation[runanim].Load((char *)":Data:Animations:Run",middleheight,neutral);
+
+       animation[bounceidleanim].Load((char *)":Data:Animations:Idle",middleheight,neutral);
+       animation[stopanim].Load((char *)":Data:Animations:Stop",middleheight,neutral);
+
+       animation[jumpupanim].Load((char *)":Data:Animations:JumpUp",highheight,neutral);
+       animation[jumpdownanim].Load((char *)":Data:Animations:JumpDown",highheight,neutral);
+
+       animation[landanim].Load((char *)":Data:Animations:Landing",lowheight,neutral);
+       animation[landhardanim].Load((char *)":Data:Animations:Landhard",lowheight,neutral);
+       animation[climbanim].Load((char *)":Data:Animations:Climb",lowheight,neutral);
+       animation[hanganim].Load((char *)":Data:Animations:Hangon",lowheight,neutral);
+       animation[spinkickanim].Load((char *)":Data:Animations:SpinKick",middleheight,normalattack);
+
+       animation[getupfromfrontanim].Load((char *)":Data:Animations:GetUpFromFront",lowheight,neutral);
+       animation[getupfrombackanim].Load((char *)":Data:Animations:GetUpFromBack",lowheight,neutral);
+       animation[crouchanim].Load((char *)":Data:Animations:Crouch",lowheight,neutral);
+       animation[sneakanim].Load((char *)":Data:Animations:Sneak",lowheight,neutral);
+       animation[rollanim].Load((char *)":Data:Animations:Roll",lowheight,neutral);
+       animation[flipanim].Load((char *)":Data:Animations:Flip",highheight,neutral);
+       animation[frontflipanim].Load((char *)":Data:Animations:Flip",highheight,neutral);
+       animation[spinkickreversedanim].Load((char *)":Data:Animations:SpinKickCaught",middleheight,reversed);
+
+       animation[spinkickreversalanim].Load((char *)":Data:Animations:SpinKickCatch",middleheight,reversal);
+       animation[lowkickanim].Load((char *)":Data:Animations:lowkick",middleheight,normalattack);
+       animation[sweepanim].Load((char *)":Data:Animations:sweep",lowheight,normalattack);
+       animation[sweepreversedanim].Load((char *)":Data:Animations:SweepCaught",lowheight,reversed);
+       animation[sweepreversalanim].Load((char *)":Data:Animations:SweepCatch",middleheight,reversal);
+       animation[rabbitkickanim].Load((char *)":Data:Animations:RabbitKick",middleheight,normalattack);
+       animation[rabbitkickreversedanim].Load((char *)":Data:Animations:RabbitKickCaught",middleheight,reversed);
+       animation[rabbitkickreversalanim].Load((char *)":Data:Animations:RabbitKickCatch",lowheight,reversal);
+       animation[upunchanim].Load((char *)":Data:Animations:Upunch",middleheight,normalattack);
+       animation[staggerbackhighanim].Load((char *)":Data:Animations:Staggerbackhigh",middleheight,neutral);
+       animation[upunchreversedanim].Load((char *)":Data:Animations:UpunchCaught",middleheight,reversed);
+
+       animation[upunchreversalanim].Load((char *)":Data:Animations:UpunchCatch",middleheight,reversal);
+       animation[hurtidleanim].Load((char *)":Data:Animations:Hurtidle",middleheight,neutral);
+       animation[backhandspringanim].Load((char *)":Data:Animations:Backhandspring",middleheight,neutral);
+       animation[fightidleanim].Load((char *)":Data:Animations:Fightidle",middleheight,neutral);
+       animation[walkanim].Load((char *)":Data:Animations:Walk",middleheight,neutral);
+
+       animation[fightsidestep].Load((char *)":Data:Animations:Fightsidestep",middleheight,neutral);
+       animation[killanim].Load((char *)":Data:Animations:Kill",middleheight,normalattack);
+       animation[sneakattackanim].Load((char *)":Data:Animations:Sneakattack",middleheight,reversal);
+       animation[sneakattackedanim].Load((char *)":Data:Animations:Sneakattacked",middleheight,reversed);
+       animation[drawrightanim].Load((char *)":Data:Animations:drawright",middleheight,neutral);
+       animation[knifeslashstartanim].Load((char *)":Data:Animations:slashstart",middleheight,normalattack);
+       animation[crouchdrawrightanim].Load((char *)":Data:Animations:crouchdrawright",lowheight,neutral);
+       animation[crouchstabanim].Load((char *)":Data:Animations:crouchstab",lowheight,normalattack);
+
+       animation[knifefollowanim].Load((char *)":Data:Animations:slashfollow",middleheight,reversal);
+       animation[knifefollowedanim].Load((char *)":Data:Animations:slashfollowed",middleheight,reversed);
+       animation[knifethrowanim].Load((char *)":Data:Animations:knifethrow",middleheight,normalattack);
+       animation[removeknifeanim].Load((char *)":Data:Animations:removeknife",middleheight,neutral);
+       animation[crouchremoveknifeanim].Load((char *)":Data:Animations:crouchremoveknife",lowheight,neutral);
+       animation[jumpreversedanim].Load((char *)":Data:Animations:JumpCaught",middleheight,reversed);
+       animation[jumpreversalanim].Load((char *)":Data:Animations:JumpCatch",middleheight,reversal);
+       animation[staggerbackhardanim].Load((char *)":Data:Animations:Staggerbackhard",middleheight,neutral);
+
+       animation[dropkickanim].Load((char *)":Data:Animations:Dropkick",middleheight,normalattack);
+       animation[winduppunchanim].Load((char *)":Data:Animations:Winduppunch",middleheight,normalattack);
+       animation[winduppunchblockedanim].Load((char *)":Data:Animations:Winduppunchblocked",middleheight,normalattack);
+       animation[blockhighleftanim].Load((char *)":Data:Animations:Blockhighleft",middleheight,normalattack);
+       animation[blockhighleftstrikeanim].Load((char *)":Data:Animations:Blockhighleftstrike",middleheight,normalattack);
+       animation[backflipanim].Load((char *)":Data:Animations:Backflip",highheight,neutral);
+       animation[walljumpbackanim].Load((char *)":Data:Animations:Walljumpback",highheight,neutral);
+       animation[walljumpfrontanim].Load((char *)":Data:Animations:Walljumpfront",highheight,neutral);
+       animation[rightflipanim].Load((char *)":Data:Animations:Rightflip",highheight,neutral);
+       animation[walljumprightanim].Load((char *)":Data:Animations:Walljumpright",highheight,neutral);
+       animation[leftflipanim].Load((char *)":Data:Animations:Leftflip",highheight,neutral);
+       animation[walljumpleftanim].Load((char *)":Data:Animations:Walljumpleft",highheight,neutral);
+       animation[walljumprightkickanim].Load((char *)":Data:Animations:Walljumprightkick",highheight,neutral);
+       animation[walljumpleftkickanim].Load((char *)":Data:Animations:Walljumpleftkick",highheight,neutral);
+       animation[knifefightidleanim].Load((char *)":Data:Animations:Knifefightidle",middleheight,neutral);
+       animation[knifesneakattackanim].Load((char *)":Data:Animations:Knifesneakattack",middleheight,reversal);
+       animation[knifesneakattackedanim].Load((char *)":Data:Animations:Knifesneakattacked",middleheight,reversed);
+       animation[swordfightidleanim].Load((char *)":Data:Animations:swordfightidle",middleheight,neutral);
+       animation[drawleftanim].Load((char *)":Data:Animations:drawleft",middleheight,neutral);
+       animation[swordslashanim].Load((char *)":Data:Animations:swordslash",middleheight,normalattack);
+       animation[swordgroundstabanim].Load((char *)":Data:Animations:swordgroundstab",lowheight,normalattack);
+       animation[dodgebackanim].Load((char *)":Data:Animations:dodgeback",middleheight,neutral);
+       animation[swordsneakattackanim].Load((char *)":Data:Animations:Swordsneakattack",middleheight,reversal);
+       animation[swordsneakattackedanim].Load((char *)":Data:Animations:Swordsneakattacked",middleheight,reversed);
+       animation[swordslashreversedanim].Load((char *)":Data:Animations:swordslashCaught",middleheight,reversed);
+       animation[swordslashreversalanim].Load((char *)":Data:Animations:swordslashCatch",middleheight,reversal);
+       animation[knifeslashreversedanim].Load((char *)":Data:Animations:knifeslashCaught",middleheight,reversed);
+       animation[knifeslashreversalanim].Load((char *)":Data:Animations:knifeslashCatch",middleheight,reversal);
+       animation[swordfightidlebothanim].Load((char *)":Data:Animations:swordfightidleboth",middleheight,neutral);
+       animation[swordslashparryanim].Load((char *)":Data:Animations:sworduprightparry",middleheight,normalattack);
+       animation[swordslashparriedanim].Load((char *)":Data:Animations:swordslashparried",middleheight,normalattack);
+       animation[wolfidle].Load((char *)":Data:Animations:Wolfidle",middleheight,neutral);
+       animation[wolfcrouchanim].Load((char *)":Data:Animations:Wolfcrouch",lowheight,neutral);
+       animation[wolflandanim].Load((char *)":Data:Animations:Wolflanding",lowheight,neutral);
+       animation[wolflandhardanim].Load((char *)":Data:Animations:Wolflandhard",lowheight,neutral);
+       animation[wolfrunanim].Load((char *)":Data:Animations:Wolfrun",middleheight,neutral);
+       animation[wolfrunninganim].Load((char *)":Data:Animations:Wolfrunning",middleheight,neutral);
+       animation[rabbitrunninganim].Load((char *)":Data:Animations:Rabbitrunning",middleheight,neutral);
+       animation[wolfstopanim].Load((char *)":Data:Animations:Wolfstop",middleheight,neutral);
+       animation[rabbittackleanim].Load((char *)":Data:Animations:Rabbittackle",middleheight,neutral);
+       animation[rabbittacklinganim].Load((char *)":Data:Animations:Rabbittackling",middleheight,reversal);
+       animation[rabbittackledbackanim].Load((char *)":Data:Animations:Rabbittackledback",middleheight,reversed);
+       animation[rabbittackledfrontanim].Load((char *)":Data:Animations:Rabbittackledfront",middleheight,reversed);
+       animation[wolfslapanim].Load((char *)":Data:Animations:Wolfslap",middleheight,normalattack);
+       animation[staffhitanim].Load((char *)":Data:Animations:StaffHit",middleheight,normalattack);
+       animation[staffgroundsmashanim].Load((char *)":Data:Animations:StaffGroundSmash",lowheight,normalattack);
+       animation[staffspinhitanim].Load((char *)":Data:Animations:Spinwhack",middleheight,normalattack);
+       animation[staffhitreversedanim].Load((char *)":Data:Animations:StaffHitCaught",middleheight,reversed);
+       animation[staffhitreversalanim].Load((char *)":Data:Animations:StaffHitCatch",middleheight,reversal);
+       animation[staffspinhitreversedanim].Load((char *)":Data:Animations:SpinWhackCaught",middleheight,reversed);
+       animation[staffspinhitreversalanim].Load((char *)":Data:Animations:SpinWhackCatch",middleheight,reversal);
+
+       animation[sitanim].Load((char *)":Data:Animations:Sit",lowheight,neutral);
+       animation[sleepanim].Load((char *)":Data:Animations:Sleep",lowheight,neutral);
+       animation[talkidleanim].Load((char *)":Data:Animations:TalkIdle",middleheight,neutral);
+
+       animation[sitwallanim].Load((char *)":Data:Animations:Dying",lowheight,neutral);
+       animation[dead1anim].Load((char *)":Data:Animations:Dead1",lowheight,neutral);
+       animation[dead2anim].Load((char *)":Data:Animations:Dead2",lowheight,neutral);
+       animation[dead3anim].Load((char *)":Data:Animations:Dead3",lowheight,neutral);
+       animation[dead4anim].Load((char *)":Data:Animations:Dead4",lowheight,neutral);
+       //Fix knife stab, too lazy to do it manually
+       XYZ moveamount;
+       moveamount=0;
+       moveamount.z=2;
+       for(i=0;i<player[0].skeleton.num_joints;i++){
+               for(j=0;j<animation[knifesneakattackanim].numframes;j++){
+                       animation[knifesneakattackanim].position[i][j]+=moveamount;
+               }       
+       }
+
+       loadscreencolor=4;
+       LoadingScreen();
+
+       for(i=0;i<player[0].skeleton.num_joints;i++){
+               for(j=0;j<animation[knifesneakattackedanim].numframes;j++){
+                       animation[knifesneakattackedanim].position[i][j]+=moveamount;
+               }       
+       }
+
+       loadscreencolor=4;
+       LoadingScreen();
+
+       for(i=0;i<player[0].skeleton.num_joints;i++){
+               animation[dead1anim].position[i][1]=animation[dead1anim].position[i][0];
+               animation[dead2anim].position[i][1]=animation[dead2anim].position[i][0];
+               animation[dead3anim].position[i][1]=animation[dead3anim].position[i][0];
+               animation[dead4anim].position[i][1]=animation[dead4anim].position[i][0];
+       }
+       animation[dead1anim].speed[0]=0.001;
+       animation[dead2anim].speed[0]=0.001;
+       animation[dead3anim].speed[0]=0.001;
+       animation[dead4anim].speed[0]=0.001;
+
+       animation[dead1anim].speed[1]=0.001;
+       animation[dead2anim].speed[1]=0.001;
+       animation[dead3anim].speed[1]=0.001;
+       animation[dead4anim].speed[1]=0.001;
+
+       for(i=0;i<player[0].skeleton.num_joints;i++){
+               for(j=0;j<animation[swordsneakattackanim].numframes;j++){
+                       animation[swordsneakattackanim].position[i][j]+=moveamount;
+               }       
+       }
+       loadscreencolor=4;
+       LoadingScreen();
+       for(j=0;j<animation[swordsneakattackanim].numframes;j++){
+               animation[swordsneakattackanim].weapontarget[j]+=moveamount;
+       }       
+
+       loadscreencolor=4;
+       LoadingScreen();
+
+       for(i=0;i<player[0].skeleton.num_joints;i++){
+               for(j=0;j<animation[swordsneakattackedanim].numframes;j++){
+                       animation[swordsneakattackedanim].position[i][j]+=moveamount;
+               }       
+       }
+       /*
+       for(i=0;i<player[0].skeleton.num_joints;i++){
+       for(j=0;j<animation[sleepanim].numframes;j++){
+       animation[sleepanim].position[i][j]=DoRotation(animation[sleepanim].position[i][j],0,180,0);
+       }       
+       }
+       */
+       loadscreencolor=4;
+       LoadingScreen();
+       temptexdetail=texdetail;
+       texdetail=1;
+       texdetail=temptexdetail;
+
+       loadscreencolor=4;
+       LoadingScreen();
+
+       //if(ismotionblur){
+       if(!screentexture){
+               glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+               glGenTextures( 1, &screentexture );
+               glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+
+               glEnable(GL_TEXTURE_2D);
+               glBindTexture( GL_TEXTURE_2D, screentexture);
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+
+               glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, kTextureSize, kTextureSize, 0);                
+       }
+       //}
+
+       LoadSounds();
+
+       /*PlaySoundEx( consolesuccesssound, samp[consolesuccesssound], NULL, TRUE);
+       FSOUND_SetVolume(channels[consolesuccesssound], 256);
+       FSOUND_SetPaused(channels[consolesuccesssound], FALSE);
+       */
+       if(targetlevel!=7){
+               float gLoc[3]={0,0,0};
+               float vel[3]={0,0,0};
+               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+               FSOUND_SetVolume(channels[fireendsound], 256);
+               FSOUND_SetPaused(channels[fireendsound], FALSE);
+               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+       }
+
+       stillloading=0;
+       loading=0;
+       changedelay=1;
+
+       visibleloading=0;
+}
+
+Game::Game()
+{
+       terraintexture = 0;
+       terraintexture2 = 0;
+       terraintexture3 = 0;
+       screentexture = 0;
+       screentexture2 = 0;
+       logotexture = 0;
+       loadscreentexture = 0;
+       Maparrowtexture = 0;
+       Mapboxtexture = 0;
+       Mapcircletexture = 0;
+       cursortexture = 0;
+
+       memset(Mainmenuitems, 0, sizeof(Mainmenuitems));
+
+       nummenuitems = 0;
+
+       memset(startx, 0, sizeof(startx));
+       memset(starty, 0, sizeof(starty));
+       memset(endx, 0, sizeof(endx));
+       memset(endy, 0, sizeof(endy));
+
+       memset(selectedlong, 0, sizeof(selectedlong));
+       memset(offsetx, 0, sizeof(offsetx));
+       memset(offsety, 0, sizeof(offsety));
+       memset(movex, 0, sizeof(movex));
+       memset(movey, 0, sizeof(movey));
+       memset(endy, 0, sizeof(endy));
+
+       transition = 0;
+       anim = 0;
+       selected = 0;
+       loaddistrib = 0;
+       keyselect = 0;
+       indemo = 0;
+       registered = 0;
+
+       won = 0;
+
+       entername = 0;
+
+       memset(menustring, 0, sizeof(menustring));
+       memset(registrationname, 0, sizeof(registrationname));
+       registrationnumber = 0;
+
+       newdetail = 0;
+       newscreenwidth = 0;
+       newscreenheight = 0;
+
+       gameon = 0;
+       deltah = 0,deltav = 0;
+       mousecoordh = 0,mousecoordv = 0;
+       oldmousecoordh = 0,oldmousecoordv = 0;
+       rotation = 0,rotation2 = 0;
+
+//     SkyBox skybox;
+
+       cameramode = 0;
+       cameratogglekeydown = 0;
+       chattogglekeydown = 0;
+       olddrawmode = 0;
+       drawmode = 0;
+       drawmodetogglekeydown = 0;
+       explodetogglekeydown = 0;
+       detailtogglekeydown = 0;
+       firstload = 0;
+       oldbutton = 0;
+
+       leveltime = 0;
+       loadtime = 0;
+
+//     Model hawk;
+
+//     XYZ hawkcoords;
+//     XYZ realhawkcoords;
+
+       hawktexture = 0;
+       hawkrotation = 0;
+       hawkcalldelay = 0;
+/*
+       Model eye;
+       Model iris;
+       Model cornea;
+*/
+       stealthloading = 0;
+
+       campaignnumlevels = 0;
+
+       memset(campaignmapname, 0, sizeof(campaignmapname));
+       memset(campaigndescription, 0, sizeof(campaigndescription));
+       memset(campaignchoosenext, 0, sizeof(campaignchoosenext));
+       memset(campaignnumnext, 0, sizeof(campaignnumnext));
+       memset(campaignnextlevel, 0, sizeof(campaignnextlevel));
+       int campaignchoicesmade;
+       memset(campaignchoices, 0, sizeof(campaignchoices));
+       memset(campaignlocationx, 0, sizeof(campaignlocationx));
+       memset(campaignlocationy, 0, sizeof(campaignlocationy));
+       memset(campaignlocationy, 0, sizeof(campaignlocationy));
+
+       campaignchoicenum = 0;
+
+       memset(campaignchoicewhich, 0, sizeof(campaignchoicewhich));
+
+       whichchoice = 0;
+
+       numlevelspassed = 0;
+
+       memset(levelorder, 0, sizeof(levelorder));
+       memset(levelvisible, 0, sizeof(levelvisible));
+       memset(levelhighlight, 0, sizeof(levelhighlight));
+
+       minimap = 0;
+
+       musictype = 0,oldmusictype = 0,oldoldmusictype = 0;
+       realthreat = 0;
+
+//     Model rabbit;
+//     XYZ rabbitcoords;
+
+//     XYZ mapcenter;
+       mapradius = 0;
+
+//     Text text;
+       fps = 0;
+
+//     XYZ cameraloc;
+       cameradist = 0;
+
+       envtogglekeydown = 0;
+       slomotogglekeydown = 0;
+       texturesizetogglekeydown = 0;
+       freezetogglekeydown = 0;
+       drawtoggle = 0;
+
+       editorenabled = 0;
+       editortype = 0;
+       editorsize = 0;
+       editorrotation = 0;
+       editorrotation2 = 0;
+
+       brightness = 0;
+
+       quit = 0;
+       tryquit = 0;
+
+//     XYZ pathpoint[30];
+       numpathpoints = 0;
+       memset(numpathpointconnect, 0, sizeof(numpathpointconnect));
+       memset(pathpointconnect, 0, sizeof(pathpointconnect));
+       pathpointselected = 0;
+
+       endgame = 0;
+       scoreadded = 0;
+       numchallengelevels = 0;
+
+       console = 0;
+       archiveselected = 0;
+
+       memset(consoletext, 0, sizeof(consoletext));
+       memset(consolechars, 0, sizeof(consolechars));
+       chatting = 0;
+       memset(displaytext, 0, sizeof(displaytext));
+       memset(displaychars, 0, sizeof(displaychars));
+       memset(displaytime, 0, sizeof(displaytime));
+       displayblinkdelay = 0;
+       displayblink = 0;
+       displayselected = 0;
+       consolekeydown = 0;
+       consoletogglekeydown = 0;
+       consoleblinkdelay = 0;
+       consoleblink = 0;
+       consoleselected = 0;
+       memset(togglekey, 0, sizeof(togglekey));
+       memset(togglekeydelay, 0, sizeof(togglekeydelay));
+       registernow = 0;
+       autocam = 0;
+
+       crouchkey = 0,jumpkey = 0,forwardkey = 0,chatkey = 0,backkey = 0,leftkey = 0,rightkey = 0,drawkey = 0,throwkey = 0,attackkey = 0;
+       oldattackkey = 0;
+
+       loading = 0;
+       talkdelay = 0;
+
+       numboundaries = 0;
+//     XYZ boundary[360];
+
+       whichlevel = 0;
+       oldenvironment = 0;
+       targetlevel = 0;
+       changedelay = 0;
+
+       memset(musicvolume, 0, sizeof(musicvolume));
+       memset(oldmusicvolume, 0, sizeof(oldmusicvolume));
+       musicselected = 0;
+       change = 0;
+}
diff --git a/Source/GameTick.cpp b/Source/GameTick.cpp
new file mode 100644 (file)
index 0000000..b8c4eee
--- /dev/null
@@ -0,0 +1,11579 @@
+#include <direct.h>
+#include <ctime>
+#include "Game.h"
+
+using namespace std;
+
+extern float multiplier;
+extern XYZ viewer;
+extern int environment;
+extern float texscale;
+extern Terrain terrain;
+extern FSOUND_SAMPLE   *samp[100];
+extern int channels[100];
+extern Sprites sprites;
+extern int kTextureSize;
+extern float screenwidth,screenheight;
+extern float gravity;
+extern int detail;
+extern float texdetail;
+extern Objects objects;
+extern int slomo;
+extern float slomodelay;
+extern bool floatjump;
+extern float volume;
+extern Animation animation[animation_count];
+extern Light light;
+extern float texdetail;
+extern GLubyte bloodText[512*512*3];
+extern GLubyte wolfbloodText[512*512*3];
+extern float terraindetail;
+extern float camerashake;
+extern float woozy;
+extern float blackout;
+extern bool cellophane;
+extern bool musictoggle;
+extern int difficulty;
+extern Weapons weapons;
+extern Person player[maxplayers];
+extern int numplayers;
+extern int bloodtoggle;
+extern bool invertmouse;
+extern float windvar;
+extern float precipdelay;
+extern XYZ viewerfacing;
+extern bool ambientsound;
+extern bool mousejump;
+extern float viewdistance;
+extern bool freeze;
+extern bool autoslomo;
+extern int newnetmessages;
+extern char netmessages[256];
+extern bool keyboardfrozen;
+extern int netdatanew;
+extern bool loadingstuff;
+extern char mapname[256];
+extern XYZ windvector;
+extern bool buttons[3];
+extern bool debugmode;
+static int music1;
+extern int mainmenu;
+extern int oldmainmenu;
+extern bool visibleloading;
+extern int loadscreencolor;
+extern float flashamount,flashr,flashg,flashb;
+extern int flashdelay;
+extern XYZ envsound[30];
+extern float envsoundvol[30];
+extern int numenvsounds;
+extern float envsoundlife[30];
+extern float usermousesensitivity;
+extern bool ismotionblur;
+extern bool foliage;
+extern bool trilinear;
+extern bool damageeffects;
+extern bool showpoints;
+extern bool texttoggle;
+extern bool alwaysblur;
+extern float gamespeed;
+extern bool decals;
+extern bool vblsync;
+extern bool immediate;
+extern bool velocityblur;
+extern int bonus;
+extern int oldbonus;
+extern float bonusvalue;
+extern float bonustotal;
+extern float bonustime;
+extern float startbonustotal;
+extern float tintr,tintg,tintb;
+extern float bonusnum[100];
+extern bool skyboxtexture;
+extern float skyboxr;
+extern float skyboxg;
+extern float skyboxb;
+extern float skyboxlightr;
+extern float skyboxlightg;
+extern float skyboxlightb;
+extern float fadestart;
+extern float slomospeed;
+extern float slomofreq;
+extern int tutoriallevel;
+extern float smoketex;
+extern float tutorialstagetime;
+extern int tutorialstage;
+extern float tutorialmaxtime;
+extern float tutorialsuccess;
+extern bool againbonus;
+extern bool reversaltrain;
+extern bool canattack;
+extern bool cananger;
+extern float damagedealt;
+extern float damagetaken;
+extern int maptype;
+extern int editoractive;
+extern int editorpathtype;
+extern bool oldbuttons[3];
+
+extern float hostiletime;
+
+extern bool gamestarted;
+
+extern int numhotspots;
+extern int winhotspot;
+extern int windialogue;
+extern int killhotspot;
+extern XYZ hotspot[40];
+extern int hotspottype[40];
+extern float hotspotsize[40];
+extern char hotspottext[40][256];
+extern int currenthotspot;
+
+extern int kBitsPerPixel;
+extern int hostile;
+
+extern int numaccounts;
+extern int accountactive;
+extern int accountdifficulty[10];
+extern int accountprogress[10];
+extern float accountpoints[10];
+extern float accounthighscore[10][50];
+extern float accountfasttime[10][50];
+extern bool accountunlocked[10][60];
+extern char accountname[10][256];
+
+extern bool stillloading;
+extern bool winfreeze;
+
+extern int numfalls;
+extern int numflipfail;
+extern int numseen;
+extern int numstaffattack;
+extern int numswordattack;
+extern int numknifeattack;
+extern int numunarmedattack;
+extern int numescaped;
+extern int numflipped;
+extern int numwallflipped;
+extern int numthrowkill;
+extern int numafterkill;
+extern int numreversals;
+extern int numattacks;
+extern int maxalarmed;
+extern int numresponded;
+
+extern int numdialogues;
+extern int numdialogueboxes[max_dialogues];
+extern int dialoguetype[max_dialogues];
+extern int dialogueboxlocation[max_dialogues][max_dialoguelength];
+extern float dialogueboxcolor[max_dialogues][max_dialoguelength][3];
+extern int dialogueboxsound[max_dialogues][max_dialoguelength];
+extern char dialoguetext[max_dialogues][max_dialoguelength][128];
+extern char dialoguename[max_dialogues][max_dialoguelength][64];
+extern XYZ dialoguecamera[max_dialogues][max_dialoguelength];
+extern XYZ participantlocation[max_dialogues][10];
+extern int participantfocus[max_dialogues][max_dialoguelength];
+extern int participantaction[max_dialogues][max_dialoguelength];
+extern float participantrotation[max_dialogues][10];
+extern XYZ participantfacing[max_dialogues][max_dialoguelength][10];
+extern float dialoguecamerarotation[max_dialogues][max_dialoguelength];
+extern float dialoguecamerarotation2[max_dialogues][max_dialoguelength];
+extern int indialogue;
+extern int whichdialogue;
+extern int directing;
+extern float dialoguetime;
+extern int dialoguegonethrough[20];
+
+extern bool campaign;
+
+extern float oldgamespeed;
+
+extern float accountcampaignhighscore[10];
+extern float accountcampaignfasttime[10];
+extern float accountcampaignscore[10];
+extern float accountcampaigntime[10];
+
+extern int accountcampaignchoicesmade[10];
+extern int accountcampaignchoices[10][5000];
+/********************> Tick() <*****/
+extern FSOUND_STREAM * strm[10];
+extern "C"     void PlaySoundEx(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused);
+extern "C" void PlayStreamEx(int chan, FSOUND_STREAM *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused);
+
+extern void ScreenShot(const char * fname);
+void Screenshot        (void)
+{
+       char temp[1024];
+       time_t  t = time(NULL);
+       struct  tm *tme = localtime(&t);
+       sprintf(temp, "Screenshots\\Screenshot_%04d_%02d_%02d--%02d_%02d_%02d.png", tme->tm_year + 1900, tme->tm_mon + 1, tme->tm_mday, tme->tm_hour, tme->tm_min, tme->tm_sec);
+
+       mkdir("Screenshots");
+       ScreenShot(temp/*"Screenshots\\Screenshot.png"*/);
+
+       /*FSSpec                                MAC_file;
+       GraphicsExportComponent         QT_exporter;
+       OSErr                           MAC_error_code;
+       CGrafPtr                        MAC_currentPort;
+       GDHandle                        MAC_currentDevice;
+       unsigned char*          MAC_pixels;
+       Rect                            MAC_picture_rectangle;
+       GWorldPtr                       MAC_offscreen_graphics_port;
+
+       static int numscreenshots=0;
+
+       // Make an FSSpec
+       static char buf[256];
+       if(numscreenshots==0){
+       buf[0]=26;
+       buf[1]=':';
+       buf[2]='S';
+       buf[3]='c';
+       buf[4]='r';
+       buf[5]='e';
+       buf[6]='e';
+       buf[7]='n';
+       buf[8]='s';
+       buf[9]='h';
+       buf[10]='o';
+       buf[11]='t';
+       buf[12]='s';
+       buf[13]=':';
+       buf[14]='S';
+       buf[15]='c';
+       buf[16]='r';
+       buf[17]='e';
+       buf[18]='e';
+       buf[19]='n';
+       buf[20]='s';
+       buf[21]='h';
+       buf[22]='o';
+       buf[23]='t';
+       buf[24]='0';
+       buf[25]='0';
+       buf[26]='0';
+       }
+
+       FInfo *fndrInfo;
+       FSMakeFSSpec(0, 0, (unsigned char*)buf, &MAC_file);
+       while(!FSpGetFInfo (&MAC_file, fndrInfo)){
+       FSMakeFSSpec(0, 0, (unsigned char*)buf, &MAC_file);
+       if(!FSpGetFInfo (&MAC_file, fndrInfo)){
+       numscreenshots++;
+       buf[26]++;
+       if(buf[26]==':'){
+       buf[26]='0';
+       buf[25]++;
+       if(buf[25]==':'){
+       buf[25]='0';
+       buf[24]++;
+       if(buf[24]==':'){
+       buf[24]='9';
+       buf[25]='9';
+       buf[26]='9';
+       }
+       }
+       }
+       }
+       }
+
+
+       // Get the GWorld
+       GWorldPtr                       MAC_gWorld = (CGrafPtr) FrontWindow();
+       //assert(MAC_gWorld != NULL);
+
+       // Allocate memory for loading image
+       MAC_pixels = new unsigned char[(int)(screenheight * screenwidth * 4)];
+       if (MAC_pixels == NULL) {
+       //UTIL_Error("Could not create Texture data.");
+       return;
+       }
+
+       // Get GWorld
+       ::GetGWorld(&MAC_currentPort, &MAC_currentDevice);      
+
+       // Make a picture Rectangle
+       MAC_picture_rectangle.left = 0;
+       MAC_picture_rectangle.right = screenwidth;
+       MAC_picture_rectangle.top = 0;
+       MAC_picture_rectangle.bottom = screenheight;    
+
+       // Create new offscreen GWorld
+       MAC_error_code = ::QTNewGWorldFromPtr (&MAC_offscreen_graphics_port, k32ARGBPixelFormat, &MAC_picture_rectangle, NULL, NULL, 0, (char *) MAC_pixels, screenwidth * 4);
+       if (MAC_error_code)     {
+       ::SetGWorld(MAC_currentPort, MAC_currentDevice);        
+       delete MAC_pixels;
+       //UTIL_Error("Could not create offscreen GWorld. ");
+       return;
+
+       }
+
+       // Copy OpenGL Context to new GWorld
+       glReadBuffer(GL_FRONT); 
+       glReadPixels(0,0,screenwidth,screenheight,GL_RGBA,GL_UNSIGNED_BYTE,MAC_pixels);
+
+       // Swizzle texture
+       for (unsigned long byte = 0; byte < screenheight * screenwidth * 4; byte+=4) {
+       unsigned char temp = MAC_pixels[byte+0];
+       MAC_pixels[byte+0] = MAC_pixels[byte+3];
+       MAC_pixels[byte+3] = MAC_pixels[byte+2];
+       MAC_pixels[byte+2] = MAC_pixels[byte+1];
+       MAC_pixels[byte+1] = temp;
+       }
+
+       // Flip the image  :(   This could probably be optimized
+       int vert;
+       int src_index;
+       int dst_index;
+       unsigned char temp;
+       for (int horz = 0; horz < screenwidth; ++horz)
+       for (vert = 0; vert < screenheight / 2; ++vert) {               
+       src_index = (screenwidth * vert + horz) * 4;
+       dst_index = (screenwidth * (screenheight - vert - 1) + horz) * 4;
+
+       temp=MAC_pixels[src_index+0];
+       MAC_pixels[src_index+0]=MAC_pixels[dst_index+0];
+       MAC_pixels[dst_index+0]=temp;
+
+       temp=MAC_pixels[src_index+1];
+       MAC_pixels[src_index+1]=MAC_pixels[dst_index+1];
+       MAC_pixels[dst_index+1]=temp;
+
+       temp=MAC_pixels[src_index+2];
+       MAC_pixels[src_index+2]=MAC_pixels[dst_index+2];
+       MAC_pixels[dst_index+2]=temp;
+
+       temp=MAC_pixels[src_index+3];
+       MAC_pixels[src_index+3]=MAC_pixels[dst_index+3];
+       MAC_pixels[dst_index+3]=temp;
+       }
+
+
+
+       // Export the Gworld
+       MAC_error_code =  OpenADefaultComponent(GraphicsExporterComponentType, kQTFileTypeBMP, &QT_exporter);
+       if (MAC_error_code) {
+       //UTIL_Warning("Unable to export screenshot."); 
+       ::SetGWorld(MAC_currentPort, MAC_currentDevice);        
+       ::DisposeGWorld(MAC_offscreen_graphics_port);
+       delete MAC_pixels;
+       return;
+       }                                                                                               
+
+       MAC_error_code =  GraphicsExportSetInputGWorld(QT_exporter,MAC_offscreen_graphics_port);
+       if (MAC_error_code) {
+       ::CloseComponent(QT_exporter);
+       ::SetGWorld(MAC_currentPort, MAC_currentDevice);
+       ::DisposeGWorld(MAC_offscreen_graphics_port);
+       delete MAC_pixels;
+       //UTIL_Warning("Unable to export screenshot.");
+       return;
+       }                                                               
+
+       MAC_error_code = GraphicsExportSetOutputFile(QT_exporter,&MAC_file);
+       if (MAC_error_code) {
+       ::CloseComponent(QT_exporter);
+       ::SetGWorld(MAC_currentPort, MAC_currentDevice);        
+       ::DisposeGWorld(MAC_offscreen_graphics_port);
+       delete MAC_pixels;
+       //UTIL_Warning("Unable to export screenshot.");
+       return;
+       }                                                       
+
+       MAC_error_code = GraphicsExportDoExport(QT_exporter,NULL);
+       if (MAC_error_code) {
+       ::CloseComponent(QT_exporter);
+       ::SetGWorld(MAC_currentPort, MAC_currentDevice);                        
+       ::DisposeGWorld(MAC_offscreen_graphics_port);
+       delete MAC_pixels;
+       //UTIL_Warning("Unable to export screenshot.");
+       return;
+       }                                               
+
+       ::CloseComponent(QT_exporter);
+       ::SetGWorld(MAC_currentPort, MAC_currentDevice);
+       ::DisposeGWorld(MAC_offscreen_graphics_port);
+
+       delete MAC_pixels;*/
+}
+
+
+
+void   Game::SetUpLighting(){
+       if(environment==snowyenvironment){
+               light.color[0]=.65;
+               light.color[1]=.65;
+               light.color[2]=.7;
+               light.ambient[0]=.4;
+               light.ambient[1]=.4;
+               light.ambient[2]=.44;           
+       }
+       if(environment==desertenvironment){
+               light.color[0]=.95;
+               light.color[1]=.95;
+               light.color[2]=.95;
+               light.ambient[0]=.4;
+               light.ambient[1]=.35;
+               light.ambient[2]=.3;            
+       }
+
+       if(environment==grassyenvironment){
+               light.color[0]=.95;
+               light.color[1]=.95;
+               light.color[2]=1;
+               light.ambient[0]=.4;
+               light.ambient[1]=.4;
+               light.ambient[2]=.44;           
+       }
+       if(!skyboxtexture){
+               light.color[0]=1;
+               light.color[1]=1;
+               light.color[2]=1;
+               light.ambient[0]=.4;
+               light.ambient[1]=.4;
+               light.ambient[2]=.4;    
+       }
+       float average;
+       average=(skyboxlightr+skyboxlightg+skyboxlightb)/3;
+       light.color[0]*=(skyboxlightr+average)/2;
+       light.color[1]*=(skyboxlightg+average)/2;
+       light.color[2]*=(skyboxlightb+average)/2;
+       light.ambient[0]=light.ambient[0]*(skyboxlightr+average)/2*1;
+       light.ambient[1]=light.ambient[1]*(skyboxlightg+average)/2*1;
+       light.ambient[2]=light.ambient[2]*(skyboxlightb+average)/2*1;   
+       /*
+       light.ambient[0]=0;
+       light.ambient[1]=0;
+       light.ambient[2]=0;     */
+}
+
+int Game::findPathDist(int start,int end){
+       int i,j,k,smallestcount,count,connected;
+       int last,last2,last3,last4;
+       int closest;
+
+       smallestcount=1000;
+       for(i=0;i<50;i++){
+               count=0;
+               last=start;
+               last2=-1;
+               last3=-1;
+               last4=-1;
+               while(last!=end&&count<30){
+                       closest=-1;
+                       for(j=0;j<numpathpoints;j++){
+                               if(j!=last&&j!=last2&&j!=last3&&j!=last4)
+                               {
+                                       connected=0;
+                                       if(numpathpointconnect[j])
+                                               for(k=0;k<numpathpointconnect[j];k++){
+                                                       if(pathpointconnect[j][k]==last)connected=1;
+                                               }
+                                               if(!connected)
+                                                       if(numpathpointconnect[last])
+                                                               for(k=0;k<numpathpointconnect[last];k++){
+                                                                       if(pathpointconnect[last][k]==j)connected=1;
+                                                               }
+                                                               if(connected)
+                                                                       if(closest==-1||Random()%2==0){
+                                                                               closest=j;
+                                                                       }
+                               }
+                       }
+                       last4=last3;
+                       last3=last2;
+                       last2=last;
+                       last=closest;
+                       count++;
+               }
+               if(count<smallestcount)smallestcount=count;
+       }
+       return smallestcount;
+}
+
+int Game::checkcollide(XYZ startpoint,XYZ endpoint){
+       static XYZ colpoint,colviewer,coltarget;
+       static float minx,minz,maxx,maxz,miny,maxy;
+       static int i;
+
+       //startpoint.y+=.7;
+       //endpoint.y+=.7;
+       //startpoint.y-=.1;
+       //endpoint.y-=.1;
+
+       minx=startpoint.x;
+       if(minx>endpoint.x)minx=endpoint.x;
+       miny=startpoint.y;
+       if(miny>endpoint.y)miny=endpoint.y;
+       minz=startpoint.z;
+       if(minz>endpoint.z)minz=endpoint.z;
+
+       maxx=startpoint.x;
+       if(maxx<endpoint.x)maxx=endpoint.x;
+       maxy=startpoint.y;
+       if(maxy<endpoint.y)maxy=endpoint.y;
+       maxz=startpoint.z;
+       if(maxz<endpoint.z)maxz=endpoint.z;
+
+       minx-=1;
+       miny-=1;
+       minz-=1;
+       maxx+=1;
+       maxy+=1;
+       maxz+=1;
+
+       for(i=0;i<objects.numobjects;i++){
+               if(objects.position[i].x>minx-objects.model[i].boundingsphereradius&&objects.position[i].x<maxx+objects.model[i].boundingsphereradius&&objects.position[i].y>miny-objects.model[i].boundingsphereradius&&objects.position[i].y<maxy+objects.model[i].boundingsphereradius&&objects.position[i].z>minz-objects.model[i].boundingsphereradius&&objects.position[i].z<maxz+objects.model[i].boundingsphereradius){
+                       if(objects.type[i]!=treeleavestype&&objects.type[i]!=bushtype&&objects.type[i]!=firetype){
+                               colviewer=startpoint;
+                               coltarget=endpoint;
+                               if(objects.model[i].LineCheck(&colviewer,&coltarget,&colpoint,&objects.position[i],&objects.rotation[i])!=-1)return i;  
+                       }
+               }
+       }
+
+       //if(terrain.lineTerrain(startpoint,endpoint,&colpoint)!=-1)return 1000;
+
+       return -1;
+}
+
+int Game::checkcollide(XYZ startpoint,XYZ endpoint,int what){
+       static XYZ colpoint,colviewer,coltarget;
+       static float minx,minz,maxx,maxz,miny,maxy;
+       static int i;
+
+       //startpoint.y+=.7;
+       //endpoint.y+=.7;
+       //startpoint.y-=.1;
+       //endpoint.y-=.1;
+
+       minx=startpoint.x;
+       if(minx>endpoint.x)minx=endpoint.x;
+       miny=startpoint.y;
+       if(miny>endpoint.y)miny=endpoint.y;
+       minz=startpoint.z;
+       if(minz>endpoint.z)minz=endpoint.z;
+
+       maxx=startpoint.x;
+       if(maxx<endpoint.x)maxx=endpoint.x;
+       maxy=startpoint.y;
+       if(maxy<endpoint.y)maxy=endpoint.y;
+       maxz=startpoint.z;
+       if(maxz<endpoint.z)maxz=endpoint.z;
+
+       minx-=1;
+       miny-=1;
+       minz-=1;
+       maxx+=1;
+       maxy+=1;
+       maxz+=1;
+
+       if(what!=1000){
+               if(objects.position[what].x>minx-objects.model[what].boundingsphereradius&&objects.position[what].x<maxx+objects.model[what].boundingsphereradius&&objects.position[what].y>miny-objects.model[what].boundingsphereradius&&objects.position[what].y<maxy+objects.model[what].boundingsphereradius&&objects.position[what].z>minz-objects.model[what].boundingsphereradius&&objects.position[what].z<maxz+objects.model[what].boundingsphereradius){
+                       if(objects.type[what]!=treeleavestype&&objects.type[what]!=bushtype&&objects.type[what]!=firetype){
+                               colviewer=startpoint;
+                               coltarget=endpoint;
+                               if(objects.model[what].LineCheck(&colviewer,&coltarget,&colpoint,&objects.position[what],&objects.rotation[what])!=-1)return i; 
+                       }
+               }
+       }
+
+       if(what==1000)if(terrain.lineTerrain(startpoint,endpoint,&colpoint)!=-1)return 1000;
+
+       return -1;
+}
+
+void   Game::Setenvironment(int which)
+{
+       LOGFUNC;
+
+       LOG(" Setting environment...");
+
+       float temptexdetail;
+       environment=which;
+/*
+       FSOUND_SetPaused(channels[music1snow], TRUE);
+       FSOUND_SetPaused(channels[music1grass], TRUE);
+       FSOUND_SetPaused(channels[music1desert], TRUE);
+       FSOUND_SetPaused(channels[wind], TRUE);
+       FSOUND_SetPaused(channels[desertambient], TRUE);
+*/
+       FSOUND_SetPaused(channels[stream_music1snow], TRUE);
+       FSOUND_SetPaused(channels[stream_music1grass], TRUE);
+       FSOUND_SetPaused(channels[stream_music1desert], TRUE);
+       FSOUND_SetPaused(channels[stream_wind], TRUE);
+       FSOUND_SetPaused(channels[stream_desertambient], TRUE);
+
+
+       if(environment==snowyenvironment){
+               windvector=0;
+               windvector.z=3;
+               if(ambientsound){
+                       //PlaySoundEx( wind, samp[wind], NULL, TRUE);
+                       PlayStreamEx(stream_wind, strm[stream_wind], 0, TRUE);
+                       FSOUND_SetPaused(channels[stream_wind], FALSE);
+                       FSOUND_SetVolume(channels[stream_wind], 256);
+               }
+
+               LoadTexture(":Data:Textures:snowtree.png",&objects.treetextureptr,0,1);
+               LoadTexture(":Data:Textures:bushsnow.png",&objects.bushtextureptr,0,1);
+               LoadTexture(":Data:Textures:bouldersnow.jpg",&objects.rocktextureptr,1,0);
+               LoadTexture(":Data:Textures:snowbox.jpg",&objects.boxtextureptr,1,0);
+
+               FSOUND_Sample_Free(samp[footstepsound]);
+               FSOUND_Sample_Free(samp[footstepsound2]);
+               FSOUND_Sample_Free(samp[footstepsound3]);
+               FSOUND_Sample_Free(samp[footstepsound4]);
+               samp[footstepsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepsnow1.ogg", FSOUND_HW3D, 0);
+               samp[footstepsound2] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepsnow2.ogg", FSOUND_HW3D, 0);
+               samp[footstepsound3] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepstone1.ogg", FSOUND_HW3D, 0);
+               samp[footstepsound4] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepstone2.ogg", FSOUND_HW3D, 0);
+               FSOUND_Sample_SetMinMaxDistance(samp[footstepsound], 4.0f, 1000.0f);    
+               FSOUND_Sample_SetMinMaxDistance(samp[footstepsound2], 4.0f, 1000.0f);   
+               FSOUND_Sample_SetMinMaxDistance(samp[footstepsound3], 4.0f, 1000.0f);   
+               FSOUND_Sample_SetMinMaxDistance(samp[footstepsound4], 4.0f, 1000.0f);   
+
+               LoadTexture(":Data:Textures:snow.jpg",&terraintexture,1,0);
+
+               LoadTexture(":Data:Textures:rock.jpg",&terraintexture2,1,0);
+
+               //LoadTexture(":Data:Textures:detailgrain.png",&terraintexture3,1);
+
+
+
+
+               temptexdetail=texdetail;
+               if(texdetail>1)texdetail=4;
+               skybox.load(    ":Data:Textures:Skybox(snow):Front.jpg",
+                       ":Data:Textures:Skybox(snow):Left.jpg",
+                       ":Data:Textures:Skybox(snow):Back.jpg",
+                       ":Data:Textures:Skybox(snow):Right.jpg",
+                       ":Data:Textures:Skybox(snow):Up.jpg",
+                       ":Data:Textures:Skybox(snow):Down.jpg",
+                       ":Data:Textures:Skybox(snow):Cloud.jpg",
+                       ":Data:Textures:Skybox(snow):Reflect.jpg");
+
+
+
+
+               texdetail=temptexdetail;
+       }
+       if(environment==desertenvironment){
+               windvector=0;
+               windvector.z=2;
+               LoadTexture(":Data:Textures:deserttree.png",&objects.treetextureptr,0,1);
+               LoadTexture(":Data:Textures:bushdesert.png",&objects.bushtextureptr,0,1);
+               LoadTexture(":Data:Textures:boulderdesert.jpg",&objects.rocktextureptr,1,0);
+               LoadTexture(":Data:Textures:desertbox.jpg",&objects.boxtextureptr,1,0);
+
+
+               if(ambientsound){
+                       //PlaySoundEx( desertambient, samp[desertambient], NULL, TRUE);
+                       PlayStreamEx( stream_desertambient, strm[stream_desertambient], NULL, TRUE);
+                       FSOUND_SetPaused(channels[stream_desertambient], FALSE);
+                       FSOUND_SetVolume(channels[stream_desertambient], 256);
+               }
+
+               FSOUND_Sample_Free(samp[footstepsound]);
+               FSOUND_Sample_Free(samp[footstepsound2]);
+               FSOUND_Sample_Free(samp[footstepsound3]);
+               FSOUND_Sample_Free(samp[footstepsound4]);
+               samp[footstepsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepsnow1.ogg", FSOUND_HW3D, 0);
+               samp[footstepsound2] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepsnow2.ogg", FSOUND_HW3D, 0);
+               samp[footstepsound3] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepsnow1.ogg", FSOUND_HW3D, 0);
+               samp[footstepsound4] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepsnow2.ogg", FSOUND_HW3D, 0);
+               FSOUND_Sample_SetMinMaxDistance(samp[footstepsound], 4.0f, 1000.0f);    
+               FSOUND_Sample_SetMinMaxDistance(samp[footstepsound2], 4.0f, 1000.0f);   
+               FSOUND_Sample_SetMinMaxDistance(samp[footstepsound3], 4.0f, 1000.0f);   
+               FSOUND_Sample_SetMinMaxDistance(samp[footstepsound4], 4.0f, 1000.0f);   
+
+               LoadTexture(":Data:Textures:sand.jpg",&terraintexture,1,0);
+
+               LoadTexture(":Data:Textures:sandslope.jpg",&terraintexture2,1,0);
+
+               //LoadTexture(":Data:Textures:detailgrain.png",&terraintexture3,1);
+
+
+
+               temptexdetail=texdetail;
+               if(texdetail>1)texdetail=4;
+               skybox.load(    ":Data:Textures:Skybox(sand):Front.jpg",
+                       ":Data:Textures:Skybox(sand):Left.jpg",
+                       ":Data:Textures:Skybox(sand):Back.jpg",
+                       ":Data:Textures:Skybox(sand):Right.jpg",
+                       ":Data:Textures:Skybox(sand):Up.jpg",
+                       ":Data:Textures:Skybox(sand):Down.jpg",
+                       ":Data:Textures:Skybox(sand):Cloud.jpg",
+                       ":Data:Textures:Skybox(sand):Reflect.jpg");
+
+
+
+
+               texdetail=temptexdetail;
+       }
+       if(environment==grassyenvironment){
+               windvector=0;
+               windvector.z=2;
+               LoadTexture(":Data:Textures:tree.png",&objects.treetextureptr,0,1);
+               LoadTexture(":Data:Textures:bush.png",&objects.bushtextureptr,0,1);
+               LoadTexture(":Data:Textures:boulder.jpg",&objects.rocktextureptr,1,0);
+               LoadTexture(":Data:Textures:grassbox.jpg",&objects.boxtextureptr,1,0);
+
+               if(ambientsound){
+                       PlayStreamEx( stream_wind, strm[stream_wind], NULL, TRUE);
+                       FSOUND_SetPaused(channels[stream_wind], FALSE);
+                       FSOUND_SetVolume(channels[stream_wind], 100);
+               }
+
+               FSOUND_Sample_Free(samp[footstepsound]);
+               FSOUND_Sample_Free(samp[footstepsound2]);
+               FSOUND_Sample_Free(samp[footstepsound3]);
+               FSOUND_Sample_Free(samp[footstepsound4]);
+               samp[footstepsound] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepgrass1.ogg", FSOUND_HW3D, 0);
+               samp[footstepsound2] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepgrass2.ogg", FSOUND_HW3D, 0);
+               samp[footstepsound3] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepstone1.ogg", FSOUND_HW3D, 0);
+               samp[footstepsound4] = FSOUND_Sample_Load(FSOUND_FREE, ":Data:Sounds:footstepstone2.ogg", FSOUND_HW3D, 0);
+               FSOUND_Sample_SetMinMaxDistance(samp[footstepsound], 4.0f, 1000.0f);    
+               FSOUND_Sample_SetMinMaxDistance(samp[footstepsound2], 4.0f, 1000.0f);   
+               FSOUND_Sample_SetMinMaxDistance(samp[footstepsound3], 4.0f, 1000.0f);   
+               FSOUND_Sample_SetMinMaxDistance(samp[footstepsound4], 4.0f, 1000.0f);   
+
+               LoadTexture(":Data:Textures:grassdirt.jpg",&terraintexture,1,0);
+
+               LoadTexture(":Data:Textures:mossrock.jpg",&terraintexture2,1,0);
+
+               //LoadTexture(":Data:Textures:detail.png",&terraintexture3,1);
+
+
+
+               temptexdetail=texdetail;
+               if(texdetail>1)texdetail=4;
+               skybox.load(    ":Data:Textures:Skybox(grass):Front.jpg",
+                       ":Data:Textures:Skybox(grass):Left.jpg",
+                       ":Data:Textures:Skybox(grass):Back.jpg",
+                       ":Data:Textures:Skybox(grass):Right.jpg",
+                       ":Data:Textures:Skybox(grass):Up.jpg",
+                       ":Data:Textures:Skybox(grass):Down.jpg",
+                       ":Data:Textures:Skybox(grass):Cloud.jpg",
+                       ":Data:Textures:Skybox(grass):Reflect.jpg");
+
+
+
+               texdetail=temptexdetail;
+       }
+       temptexdetail=texdetail;
+       texdetail=1;
+       terrain.load(":Data:Textures:heightmap.png");
+
+       texdetail=temptexdetail;
+}
+
+
+void   Game::Loadlevel(int which){
+       stealthloading=0;
+
+       if(which==0)Loadlevel((char *)":Data:Maps:map1");
+       else if(which==1)Loadlevel((char *)":Data:Maps:map2");
+       else if(which==2)Loadlevel((char *)":Data:Maps:map3");
+       else if(which==3)Loadlevel((char *)":Data:Maps:map4");
+       else if(which==4)Loadlevel((char *)":Data:Maps:map5");
+       else if(which==5)Loadlevel((char *)":Data:Maps:map6");
+       else if(which==6)Loadlevel((char *)":Data:Maps:map7");
+       else if(which==7)Loadlevel((char *)":Data:Maps:map8");
+       else if(which==8)Loadlevel((char *)":Data:Maps:map9");
+       else if(which==9)Loadlevel((char *)":Data:Maps:map10");
+       else if(which==10)Loadlevel((char *)":Data:Maps:map11");
+       else if(which==11)Loadlevel((char *)":Data:Maps:map12");
+       else if(which==12)Loadlevel((char *)":Data:Maps:map13");
+       else if(which==13)Loadlevel((char *)":Data:Maps:map14");
+       else if(which==14)Loadlevel((char *)":Data:Maps:map15");
+       else if(which==15)Loadlevel((char *)":Data:Maps:map16");
+       else if(which==-1){tutoriallevel=-1;Loadlevel((char *)":Data:Maps:tutorial");}
+       else Loadlevel((char *)":Data:Maps:mapsave");
+
+       whichlevel=which;
+}
+
+/*char * Game::MD5_string (unsigned char *string){
+char temp[50];
+char temp2[100];
+
+strcpy(temp2,(const char *)string);
+strcat((char *)temp2,(const char *)"Lugaru");                                  
+sprintf (temp, "%d",strlen((char *)temp2));
+strcat((char *)temp2,temp);                                    
+
+MD5 context;
+unsigned int len = strlen ( (char *)temp2);
+
+context.update   ((unsigned char *)temp2, len);
+context.finalize ();
+
+return context.hex_digest();
+}*/
+
+
+
+void   Game::Loadlevel(char *name){
+       int i,j,k,l,m;
+       static int oldlevel;
+       int templength;
+       float lamefloat;
+       int lameint;
+
+       float headprop,legprop,armprop,bodyprop;
+
+       LOGFUNC;
+
+       LOG(std::string("Loading level...") + name);
+
+       if(!gameon)visibleloading=1;
+
+       if(stealthloading)visibleloading=0;
+
+       if(!stillloading)loadtime=0;
+       gamestarted=1;
+
+       numenvsounds=0;
+       //visibleloading=1;
+       if(tutoriallevel!=-1)tutoriallevel=0;
+       else tutoriallevel=1;
+
+       if(tutoriallevel==1)tutorialstage=0;
+       if(tutorialstage==0){
+               tutorialstagetime=0;
+               tutorialmaxtime=1;
+       }
+       loadingstuff=1;
+       if(!firstload){
+               oldlevel=50;
+       }
+       FSOUND_SetPaused(channels[whooshsound], TRUE);
+       FSOUND_SetPaused(channels[stream_firesound], TRUE);
+
+       int mapvers;
+       FILE                    *tfile;
+       tfile=fopen( name, "rb" );
+       if(tfile)
+       {
+               FSOUND_SetPaused(channels[stream_firesound], TRUE);
+
+
+               scoreadded=0;
+               windialogue=0;
+
+               hostiletime=0;
+
+               won=0;
+
+               //campaign=0;
+               animation[bounceidleanim].Load((char *)":Data:Animations:Idle",middleheight,neutral);
+
+               numdialogues=0;
+
+               for(i=0;i<20;i++)
+               {
+                       dialoguegonethrough[i]=0;
+               }
+
+               indialogue=-1;
+               cameramode=0;
+
+               damagedealt=0;
+               damagetaken=0;
+
+               if(accountactive!=-1)difficulty=accountdifficulty[accountactive];
+
+               if(difficulty!=2)minimap=1;
+               else minimap=0;
+
+               numhotspots=0;
+               currenthotspot=-1;
+               bonustime=1;
+
+               skyboxtexture=1;
+               skyboxr=1;
+               skyboxg=1;
+               skyboxb=1;
+
+               freeze=0;
+               winfreeze=0;
+
+               for(i=0;i<100;i++)
+               {
+                       bonusnum[i]=0;
+               }
+
+               numfalls=0;
+               numflipfail=0;
+               numseen=0;
+               numstaffattack=0;
+               numswordattack=0;
+               numknifeattack=0;
+               numunarmedattack=0;
+               numescaped=0;
+               numflipped=0;
+               numwallflipped=0;
+               numthrowkill=0;
+               numafterkill=0;
+               numreversals=0;
+               numattacks=0;
+               maxalarmed=0;
+               numresponded=0;
+
+               bonustotal=startbonustotal;
+               bonus=0;
+               gameon=1;
+               changedelay=0;
+               if(console)
+               {
+                       PlaySoundEx( consolesuccesssound, samp[consolesuccesssound], NULL, TRUE);
+                       FSOUND_SetVolume(channels[consolesuccesssound], 256);
+                       FSOUND_SetPaused(channels[consolesuccesssound], FALSE);
+                       freeze=0;
+                       console=0;
+               }
+
+               if(!stealthloading)
+               {
+                       terrain.numdecals=0;
+                       sprites.numsprites=0;
+                       for(i=0;i<objects.numobjects;i++)
+                       {
+                               objects.model[i].numdecals=0;
+                       }
+
+                       j=objects.numobjects;
+                       for(i=0;i<j;i++)
+                       {
+                               objects.DeleteObject(0);
+                               if(visibleloading){loadscreencolor=4; LoadingScreen();}
+                       }
+
+                       for(i=0;i<subdivision;i++)
+                       {
+                               for(j=0;j<subdivision;j++)
+                               {
+                                       terrain.patchobjectnum[i][j]=0;
+                               }
+                       }
+                       if(visibleloading){loadscreencolor=4; LoadingScreen();}
+               }
+
+               weapons.numweapons=0;
+
+               funpackf(tfile, "Bi", &mapvers);
+               if(mapvers>=15)funpackf(tfile, "Bi", &indemo);
+               else indemo=0;
+               if(mapvers>=5)funpackf(tfile, "Bi", &maptype);
+               else maptype=mapkilleveryone;
+               if(mapvers>=6)funpackf(tfile, "Bi", &hostile);
+               else hostile=1;
+               if(mapvers>=4)funpackf(tfile, "Bf Bf", &viewdistance, &fadestart);
+               else
+               {
+                       viewdistance=100;
+                       fadestart=.6;
+               }
+               if(mapvers>=2)funpackf(tfile, "Bb Bf Bf Bf", &skyboxtexture, &skyboxr, &skyboxg, &skyboxb);
+               else
+               {
+                       skyboxtexture=1;
+                       skyboxr=1;
+                       skyboxg=1;
+                       skyboxb=1;
+               }
+               if(mapvers>=10)funpackf(tfile, "Bf Bf Bf", &skyboxlightr, &skyboxlightg, &skyboxlightb);
+               else
+               {
+                       skyboxlightr=skyboxr;
+                       skyboxlightg=skyboxg;
+                       skyboxlightb=skyboxb;
+               }
+               if(!stealthloading)funpackf(tfile, "Bf Bf Bf Bf Bf Bi", &player[0].coords.x,&player[0].coords.y,&player[0].coords.z,&player[0].rotation,&player[0].targetrotation, &player[0].num_weapons);
+               if(stealthloading)funpackf(tfile, "Bf Bf Bf Bf Bf Bi", &lamefloat,&lamefloat,&lamefloat,&lamefloat,&lamefloat, &player[0].num_weapons);
+               player[0].originalcoords=player[0].coords;
+               if(player[0].num_weapons>0&&player[0].num_weapons<5)
+               {
+                       for(j=0;j<player[0].num_weapons;j++)
+                       {
+                               player[0].weaponids[j]=weapons.numweapons;
+                               funpackf(tfile, "Bi", &weapons.type[weapons.numweapons]);
+                               weapons.owner[weapons.numweapons]=0;
+                               weapons.numweapons++;
+                       }
+               }
+
+               if(visibleloading){loadscreencolor=4; LoadingScreen();}
+
+               funpackf(tfile, "Bf Bf Bf", &player[0].armorhead, &player[0].armorhigh, &player[0].armorlow);
+               funpackf(tfile, "Bf Bf Bf", &player[0].protectionhead, &player[0].protectionhigh, &player[0].protectionlow);
+               funpackf(tfile, "Bf Bf Bf", &player[0].metalhead, &player[0].metalhigh, &player[0].metallow);
+               funpackf(tfile, "Bf Bf", &player[0].power, &player[0].speedmult);
+
+               funpackf(tfile, "Bi", &player[0].numclothes);
+
+               if(mapvers>=9)
+               {
+                       funpackf(tfile, "Bi Bi", &player[0].whichskin, &player[0].creature);
+               }
+               else
+               {
+                       player[0].whichskin=0;
+                       player[0].creature=rabbittype;
+               }
+
+               for(i=0;i<max_dialogues;i++)
+               {
+                       for(j=0;j<max_dialoguelength;j++)
+                       {
+                               for(k=0;k<128;k++)
+                               {
+                                       dialoguetext[i][j][k]='\0';
+                               }
+                               for(k=0;k<64;k++)
+                               {
+                                       dialoguename[i][j][k]='\0';
+                               }
+                       }
+               }
+
+               player[0].lastattack=-1;
+               player[0].lastattack2=-1;
+               player[0].lastattack3=-1;
+
+               if(mapvers>=8)
+               {
+                       funpackf(tfile, "Bi", &numdialogues);
+                       if(numdialogues)
+                       {
+                               for(k=0;k<numdialogues;k++)
+                               {
+                                       funpackf(tfile, "Bi", &numdialogueboxes[k]);
+                                       funpackf(tfile, "Bi", &dialoguetype[k]);
+                                       for(l=0;l<10;l++)
+                                       {
+                                               funpackf(tfile, "Bf Bf Bf", &participantlocation[k][l].x, &participantlocation[k][l].y, &participantlocation[k][l].z);
+                                               funpackf(tfile, "Bf", &participantrotation[k][l]);
+                                       }
+                                       if(numdialogueboxes)
+                                       {
+                                               for(l=0;l<numdialogueboxes[k];l++)
+                                               {
+                                                       funpackf(tfile, "Bi", &dialogueboxlocation[k][l]);
+                                                       funpackf(tfile, "Bf", &dialogueboxcolor[k][l][0]);
+                                                       funpackf(tfile, "Bf", &dialogueboxcolor[k][l][1]);
+                                                       funpackf(tfile, "Bf", &dialogueboxcolor[k][l][2]);
+                                                       funpackf(tfile, "Bi", &dialogueboxsound[k][l]);
+
+                                                       bool doneread;
+
+                                                       funpackf(tfile, "Bi",&templength);
+                                                       if(templength>128||templength<=0)templength=128;
+                                                       for(m=0;m<templength;m++){
+                                                               funpackf(tfile, "Bb", &dialoguetext[k][l][m]);
+                                                               if(dialoguetext[k][l][m]=='\0')break;
+                                                       }
+
+                                                       funpackf(tfile, "Bi",&templength);
+                                                       if(templength>64||templength<=0)templength=64;
+                                                       for(m=0;m<templength;m++){
+                                                               funpackf(tfile, "Bb", &dialoguename[k][l][m]);
+                                                               if(dialoguename[k][l][m]=='\0'){
+                                                                       break;  
+                                                               }
+                                                       }
+                                                       funpackf(tfile, "Bf Bf Bf", &dialoguecamera[k][l].x, &dialoguecamera[k][l].y, &dialoguecamera[k][l].z);
+                                                       funpackf(tfile, "Bi", &participantfocus[k][l]);
+                                                       funpackf(tfile, "Bi", &participantaction[k][l]);
+
+                                                       for(m=0;m<10;m++)
+                                                               funpackf(tfile, "Bf Bf Bf", &participantfacing[k][l][m].x, &participantfacing[k][l][m].y, &participantfacing[k][l][m].z);
+
+                                                       funpackf(tfile, "Bf Bf",&dialoguecamerarotation[k][l],&dialoguecamerarotation2[k][l]);
+                                               }
+                                       }
+                               }
+                       }
+               }
+               else numdialogues=0;
+
+               if(player[0].numclothes)
+               {
+                       for(k=0;k<player[0].numclothes;k++)
+                       {
+                               funpackf(tfile, "Bi", &templength);
+                               for(l=0;l<templength;l++)
+                                       funpackf(tfile, "Bb", &player[0].clothes[k][l]);
+                               player[0].clothes[k][templength]='\0';
+                               funpackf(tfile, "Bf Bf Bf", &player[0].clothestintr[k], &player[0].clothestintg[k], &player[0].clothestintb[k]);                                                                        
+                       }
+               }
+
+               funpackf(tfile, "Bi", &environment);
+
+               funpackf(tfile, "Bi", &objects.numobjects);
+               if(objects.numobjects)
+               {
+                       for(i=0;i<objects.numobjects;i++)
+                       {
+                               funpackf(tfile, "Bi Bf Bf Bf Bf Bf Bf", &objects.type[i],&objects.rotation[i],&objects.rotation2[i], &objects.position[i].x, &objects.position[i].y, &objects.position[i].z,&objects.scale[i]);
+                               if(objects.type[i]==treeleavestype)objects.scale[i]=objects.scale[i-1];
+                       }
+               }
+
+               if(mapvers>=7)
+               {
+                       funpackf(tfile, "Bi", &numhotspots);
+                       if(numhotspots)
+                       {
+                               for(i=0;i<numhotspots;i++)
+                               {
+                                       funpackf(tfile, "Bi Bf Bf Bf Bf", &hotspottype[i],&hotspotsize[i],&hotspot[i].x,&hotspot[i].y,&hotspot[i].z);
+                                       funpackf(tfile, "Bi", &templength);
+                                       if(templength)
+                                               for(l=0;l<templength;l++)
+                                                       funpackf(tfile, "Bb", &hotspottext[i][l]);
+                                       hotspottext[i][templength]='\0';
+                                       if(hotspottype[i]==-111)indemo=1;
+                               }
+                       }
+               }
+               else numhotspots=0;
+
+               if(visibleloading){loadscreencolor=4; LoadingScreen();}
+
+               if(!stealthloading)
+               {
+                       objects.center=0;
+                       for(i=0;i<objects.numobjects;i++)
+                       {
+                               objects.center+=objects.position[i];    
+                       }
+                       objects.center/=objects.numobjects;
+
+
+                       if(visibleloading){loadscreencolor=4; LoadingScreen();}
+
+                       float maxdistance=0;
+                       float tempdist;
+                       int whichclosest;
+                       for(i=0;i<objects.numobjects;i++)
+                       {
+                               tempdist=findDistancefast(&objects.center,&objects.position[i]);
+                               if(tempdist>maxdistance)
+                               {
+                                       whichclosest=i;
+                                       maxdistance=tempdist;
+                               }
+                       }
+                       objects.radius=fast_sqrt(maxdistance);
+               }                               
+
+               if(visibleloading){loadscreencolor=4; LoadingScreen();}
+               //mapcenter=objects.center;
+               //mapradius=objects.radius;
+
+               funpackf(tfile, "Bi", &numplayers);
+               int howmanyremoved=0;
+               bool removeanother=0;
+               if(numplayers>1&&numplayers<maxplayers)
+               {
+                       for(i=1;i<numplayers;i++)
+                       {
+                               if(visibleloading){loadscreencolor=4; LoadingScreen();}
+                               removeanother=0;
+
+                               funpackf(tfile, "Bi Bi Bf Bf Bf Bi",&player[i-howmanyremoved].whichskin,&player[i-howmanyremoved].creature, &player[i-howmanyremoved].coords.x,&player[i-howmanyremoved].coords.y,&player[i-howmanyremoved].coords.z,&player[i-howmanyremoved].num_weapons);
+                               if(mapvers>=5)funpackf(tfile, "Bi", &player[i-howmanyremoved].howactive);
+                               else player[i-howmanyremoved].howactive=typeactive;
+                               if(mapvers>=3)funpackf(tfile, "Bf",&player[i-howmanyremoved].scale);
+                               else player[i-howmanyremoved].scale=-1;
+                               if(mapvers>=11)funpackf(tfile, "Bb",&player[i-howmanyremoved].immobile);
+                               else player[i-howmanyremoved].immobile=0;
+                               if(mapvers>=12)funpackf(tfile, "Bf",&player[i-howmanyremoved].rotation);
+                               else player[i-howmanyremoved].rotation=0;
+                               player[i-howmanyremoved].targetrotation=player[i-howmanyremoved].rotation;
+                               if(player[i-howmanyremoved].num_weapons<0||player[i-howmanyremoved].num_weapons>5){
+                                       removeanother=1;
+                                       howmanyremoved++;
+                               }
+                               if(!removeanother)
+                               {
+                                       if(player[i-howmanyremoved].num_weapons>0&&player[i-howmanyremoved].num_weapons<5)
+                                       {
+                                               for(j=0;j<player[i-howmanyremoved].num_weapons;j++)
+                                               {
+                                                       player[i-howmanyremoved].weaponids[j]=weapons.numweapons;
+                                                       funpackf(tfile, "Bi", &weapons.type[player[i-howmanyremoved].weaponids[j]]);
+                                                       weapons.owner[player[i-howmanyremoved].weaponids[j]]=i;
+                                                       weapons.numweapons++;
+                                               }
+                                       }
+                                       funpackf(tfile, "Bi", &player[i-howmanyremoved].numwaypoints);
+                                       //player[i-howmanyremoved].numwaypoints=10;
+                                       for(j=0;j<player[i-howmanyremoved].numwaypoints;j++)
+                                       {
+                                               funpackf(tfile, "Bf", &player[i-howmanyremoved].waypoints[j].x);
+                                               funpackf(tfile, "Bf", &player[i-howmanyremoved].waypoints[j].y);
+                                               funpackf(tfile, "Bf", &player[i-howmanyremoved].waypoints[j].z);
+                                               if(mapvers>=5)funpackf(tfile, "Bi", &player[i-howmanyremoved].waypointtype[j]);
+                                               else player[i-howmanyremoved].waypointtype[j] = wpkeepwalking;
+                                       }
+
+                                       funpackf(tfile, "Bi", &player[i-howmanyremoved].waypoint);
+                                       if(player[i-howmanyremoved].waypoint>player[i-howmanyremoved].numwaypoints-1)player[i-howmanyremoved].waypoint=0;
+
+                                       funpackf(tfile, "Bf Bf Bf", &player[i-howmanyremoved].armorhead, &player[i-howmanyremoved].armorhigh, &player[i-howmanyremoved].armorlow);
+                                       funpackf(tfile, "Bf Bf Bf", &player[i-howmanyremoved].protectionhead, &player[i-howmanyremoved].protectionhigh, &player[i-howmanyremoved].protectionlow);
+                                       funpackf(tfile, "Bf Bf Bf", &player[i-howmanyremoved].metalhead, &player[i-howmanyremoved].metalhigh, &player[i-howmanyremoved].metallow);
+                                       funpackf(tfile, "Bf Bf", &player[i-howmanyremoved].power, &player[i-howmanyremoved].speedmult);
+
+                                       if(mapvers>=4)funpackf(tfile, "Bf Bf Bf Bf", &headprop, &bodyprop, &armprop, &legprop);
+                                       else
+                                       {
+                                               headprop=1;
+                                               bodyprop=1;
+                                               armprop=1;
+                                               legprop=1;
+                                       }
+                                       if(player[i-howmanyremoved].creature==wolftype)
+                                       {
+                                               player[i-howmanyremoved].proportionhead=1.1*headprop;
+                                               player[i-howmanyremoved].proportionbody=1.1*bodyprop;
+                                               player[i-howmanyremoved].proportionarms=1.1*armprop;
+                                               player[i-howmanyremoved].proportionlegs=1.1*legprop;
+                                       }
+
+                                       if(player[i-howmanyremoved].creature==rabbittype)
+                                       {
+                                               player[i-howmanyremoved].proportionhead=1.2*headprop;
+                                               player[i-howmanyremoved].proportionbody=1.05*bodyprop;
+                                               player[i-howmanyremoved].proportionarms=1.00*armprop;
+                                               player[i-howmanyremoved].proportionlegs=1.1*legprop;
+                                               player[i-howmanyremoved].proportionlegs.y=1.05*legprop;
+                                       }
+
+                                       funpackf(tfile, "Bi", &player[i-howmanyremoved].numclothes);
+                                       if(player[i-howmanyremoved].numclothes)
+                                       {
+                                               for(k=0;k<player[i-howmanyremoved].numclothes;k++)
+                                               {
+                                                       int templength;
+                                                       funpackf(tfile, "Bi", &templength);
+                                                       for(l=0;l<templength;l++)
+                                                               funpackf(tfile, "Bb", &player[i-howmanyremoved].clothes[k][l]);
+                                                       player[i-howmanyremoved].clothes[k][templength]='\0';
+                                                       funpackf(tfile, "Bf Bf Bf", &player[i-howmanyremoved].clothestintr[k], &player[i-howmanyremoved].clothestintg[k], &player[i-howmanyremoved].clothestintb[k]);                                                                   
+                                               }
+                                       }
+                               }
+                       }
+               }
+               if(visibleloading){loadscreencolor=4; LoadingScreen();}
+
+               numplayers-=howmanyremoved;
+               funpackf(tfile, "Bi", &numpathpoints);
+               if(numpathpoints>30||numpathpoints<0)
+                       numpathpoints=0;
+               if(numpathpoints)
+               {
+                       for(j=0;j<numpathpoints;j++)
+                       {
+                               funpackf(tfile, "Bf Bf Bf Bi", &pathpoint[j].x,&pathpoint[j].y,&pathpoint[j].z,&numpathpointconnect[j]);
+                               for(k=0;k<numpathpointconnect[j];k++){
+                                       funpackf(tfile, "Bi", &pathpointconnect[j][k]);
+                               }
+                       }
+               }
+               if(visibleloading){loadscreencolor=4; LoadingScreen();}
+
+               funpackf(tfile, "Bf Bf Bf Bf", &mapcenter.x,&mapcenter.y,&mapcenter.z,&mapradius);
+
+               SetUpLighting();
+               if(environment!=oldenvironment)Setenvironment(environment);
+               oldenvironment=environment;
+
+               if(!stealthloading)
+               {
+                       j=objects.numobjects;
+                       objects.numobjects=0;
+                       for(i=0;i<j;i++)
+                       {
+                               //if(objects.type[i]!=spiketype)
+                               objects.MakeObject(objects.type[i],objects.position[i],objects.rotation[i],objects.rotation2[i],objects.scale[i]);
+                               if(visibleloading){loadscreencolor=4; LoadingScreen();}
+                       }
+
+                       //if(skyboxtexture){
+                       terrain.DoShadows();
+                       if(visibleloading){loadscreencolor=4; LoadingScreen();}
+                       objects.DoShadows();
+                       if(visibleloading){loadscreencolor=4; LoadingScreen();}
+                       /*}
+                       else terrain.DoLighting();
+                       */
+               }
+
+               fclose(tfile);
+
+               oldlevel=whichlevel;
+
+
+               if(numplayers>maxplayers-1)numplayers=maxplayers-1;
+               for(i=0;i<numplayers;i++)
+               {
+                       if(visibleloading){loadscreencolor=4; LoadingScreen();}
+                       player[i].burnt=0;
+                       player[i].bled=0;
+                       player[i].onfire=0;
+                       if(i==0||player[i].scale<0)player[i].scale=.2;
+                       player[i].skeleton.free=0;
+                       player[i].skeleton.id=i;
+                       //if(Random()%2==0)player[i].creature=wolftype;
+                       //else player[i].creature=rabbittype;
+                       if(i==0&&mapvers<9)player[i].creature=rabbittype;
+                       if(player[i].creature!=wolftype)player[i].skeleton.Load((char *)":Data:Skeleton:Basic Figure",(char *)":Data:Skeleton:Basic Figurelow",(char *)":Data:Skeleton:Rabbitbelt",(char *)":Data:Models:Body.solid",(char *)":Data:Models:Body2.solid",(char *)":Data:Models:Body3.solid",(char *)":Data:Models:Body4.solid",(char *)":Data:Models:Body5.solid",(char *)":Data:Models:Body6.solid",(char *)":Data:Models:Body7.solid",(char *)":Data:Models:Bodylow.solid",(char *)":Data:Models:Belt.solid",0);
+                       else
+                       {
+                               if(player[i].creature!=wolftype){
+                                       player[i].skeleton.Load((char *)":Data:Skeleton:Basic Figure",(char *)":Data:Skeleton:Basic Figurelow",(char *)":Data:Skeleton:Rabbitbelt",(char *)":Data:Models:Body.solid",(char *)":Data:Models:Body2.solid",(char *)":Data:Models:Body3.solid",(char *)":Data:Models:Body4.solid",(char *)":Data:Models:Body5.solid",(char *)":Data:Models:Body6.solid",(char *)":Data:Models:Body7.solid",(char *)":Data:Models:Bodylow.solid",(char *)":Data:Models:Belt.solid",1);
+                                       LoadTexture(":Data:Textures:Belt.png",&player[i].skeleton.drawmodelclothes.textureptr,1,1);
+                               }
+                               if(player[i].creature==wolftype){
+                                       player[i].skeleton.Load((char *)":Data:Skeleton:Basic Figure Wolf",(char *)":Data:Skeleton:Basic Figure Wolf Low",(char *)":Data:Skeleton:Rabbitbelt",(char *)":Data:Models:Wolf.solid",(char *)":Data:Models:Wolf2.solid",(char *)":Data:Models:Wolf3.solid",(char *)":Data:Models:Wolf4.solid",(char *)":Data:Models:Wolf5.solid",(char *)":Data:Models:Wolf6.solid",(char *)":Data:Models:Wolf7.solid",(char *)":Data:Models:Wolflow.solid",(char *)":Data:Models:Belt.solid",0);
+                               }
+                       }
+
+
+                       int texsize;
+                       texsize=512*512*3/texdetail/texdetail;
+                       //if(!player[i].loaded)player[i].skeleton.skinText = new GLubyte[texsize];
+                       //player[i].skeleton.skinText.resize(texsize);
+
+                       if(player[i].creature==rabbittype)
+                       {
+                               if(player[i].whichskin==0){
+                                       LoadTextureSave(":Data:Textures:Fur3.jpg",&player[i].skeleton.drawmodel.textureptr,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                               }
+                               else if(player[i].whichskin==1){
+                                       LoadTextureSave(":Data:Textures:Fur.jpg",&player[i].skeleton.drawmodel.textureptr,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                               }
+                               else if(player[i].whichskin==2){
+                                       LoadTextureSave(":Data:Textures:Fur2.jpg",&player[i].skeleton.drawmodel.textureptr,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                               }
+                               else if(player[i].whichskin==3){
+                                       LoadTextureSave(":Data:Textures:Lynx.jpg",&player[i].skeleton.drawmodel.textureptr,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                               }
+                               else if(player[i].whichskin==4){
+                                       LoadTextureSave(":Data:Textures:Otter.jpg",&player[i].skeleton.drawmodel.textureptr,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                               }
+                               else if(player[i].whichskin==5){
+                                       LoadTextureSave(":Data:Textures:Opal.jpg",&player[i].skeleton.drawmodel.textureptr,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                               }
+                               else if(player[i].whichskin==6){
+                                       LoadTextureSave(":Data:Textures:Sable.jpg",&player[i].skeleton.drawmodel.textureptr,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                               }
+                               else if(player[i].whichskin==7){
+                                       LoadTextureSave(":Data:Textures:Chocolate.jpg",&player[i].skeleton.drawmodel.textureptr,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                               }
+                               else if(player[i].whichskin==8){
+                                       LoadTextureSave(":Data:Textures:BW2.jpg",&player[i].skeleton.drawmodel.textureptr,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                               }
+                               else if(player[i].whichskin==9){
+                                       LoadTextureSave(":Data:Textures:WB2.jpg",&player[i].skeleton.drawmodel.textureptr,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                               }
+                       }
+                       if(player[i].creature==wolftype)
+                       {
+                               //k=abs(Random()%3);
+                               if(player[i].whichskin==0){
+                                       LoadTextureSave(":Data:Textures:Wolf.jpg",&player[i].skeleton.drawmodel.textureptr,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                               }
+                               else if(player[i].whichskin==1){
+                                       LoadTextureSave(":Data:Textures:Darkwolf.jpg",&player[i].skeleton.drawmodel.textureptr,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                               }
+                               else if(player[i].whichskin==2){
+                                       LoadTextureSave(":Data:Textures:Snowwolf.jpg",&player[i].skeleton.drawmodel.textureptr,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                               }
+                       }
+
+                       if(player[i].numclothes)
+                       {
+                               for(j=0;j<player[i].numclothes;j++)
+                               {
+                                       tintr=player[i].clothestintr[j];
+                                       tintg=player[i].clothestintg[j];
+                                       tintb=player[i].clothestintb[j];
+                                       AddClothes((char *)player[i].clothes[j],0,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                               }
+                               player[i].DoMipmaps(5,0,0,player[i].skeleton.skinsize,player[i].skeleton.skinsize);
+                       }
+
+                       player[i].currentanimation=bounceidleanim;
+                       player[i].targetanimation=bounceidleanim;
+                       player[i].currentframe=0;
+                       player[i].targetframe=1;
+                       player[i].target=0;
+                       player[i].speed=1+(float)(Random()%100)/1000;
+                       if(difficulty==0)player[i].speed-=.2;
+                       if(difficulty==1)player[i].speed-=.1;
+
+                       player[i].velocity=0;
+                       player[i].oldcoords=player[i].coords;
+                       player[i].realoldcoords=player[i].coords;
+
+                       player[i].id=i;
+                       player[i].skeleton.id=i;
+                       player[i].updatedelay=0;
+                       player[i].normalsupdatedelay=0;
+
+                       player[i].aitype=passivetype;
+                       player[i].aitarget=0;
+                       player[i].madskills=0;
+
+                       if(i==0)
+                       {
+                               player[i].proportionhead=1.2;
+                               player[i].proportionbody=1.05;
+                               player[i].proportionarms=1.00;
+                               player[i].proportionlegs=1.1;
+                               player[i].proportionlegs.y=1.05;
+                       }
+                       player[i].headless=0;
+                       player[i].currentoffset=0;
+                       player[i].targetoffset=0;
+                       /*player[i].armorhead=1;
+                       player[i].armorhigh=1;
+                       player[i].armorlow=1;
+                       player[i].protectionhead=1;
+                       player[i].protectionhigh=1;
+                       player[i].protectionlow=1;
+                       player[i].metalhead=1;
+                       player[i].metalhigh=1;
+                       player[i].metallow=1;
+                       player[i].power=1;
+                       player[i].speedmult=1;*/
+
+                       player[i].damagetolerance=200;
+
+                       if(player[i].creature==wolftype)
+                       {
+                               /*player[i].proportionhead=1.1;
+                               player[i].proportionbody=1.1;
+                               player[i].proportionarms=1.1;
+                               player[i].proportionlegs=1.1;
+                               player[i].proportionlegs.y=1.1;*/
+                               if(i==0||player[i].scale<0)player[i].scale=.23;
+
+                               player[i].damagetolerance=300;
+                       }                               
+
+                       if(visibleloading){loadscreencolor=4; LoadingScreen();}
+                       if(cellophane)
+                       {
+                               player[i].proportionhead.z=0;
+                               player[i].proportionbody.z=0;
+                               player[i].proportionarms.z=0;
+                               player[i].proportionlegs.z=0;
+                       }
+
+                       player[i].tempanimation.Load((char *)":Data:Animations:Tempanim",0,0);
+
+                       player[i].headmorphness=0;
+                       player[i].targetheadmorphness=1;
+                       player[i].headmorphstart=0;
+                       player[i].headmorphend=0;
+
+                       player[i].pausetime=0;
+
+                       player[i].dead=0;
+                       player[i].jumppower=5;
+                       player[i].damage=0;
+                       player[i].permanentdamage=0;
+                       player[i].superpermanentdamage=0;
+
+                       player[i].forwardkeydown=0;
+                       player[i].leftkeydown=0;
+                       player[i].backkeydown=0;
+                       player[i].rightkeydown=0;
+                       player[i].jumpkeydown=0;
+                       player[i].crouchkeydown=0;
+                       player[i].throwkeydown=0;
+
+                       player[i].collided=-10;
+                       player[i].loaded=1;
+                       player[i].bloodloss=0;
+                       player[i].weaponactive=-1;
+                       player[i].weaponstuck=-1;
+                       player[i].bleeding=0;
+                       player[i].deathbleeding=0;
+                       player[i].stunned=0;
+                       player[i].hasvictim=0;
+                       player[i].wentforweapon=0;
+               }
+
+               player[0].aitype=playercontrolled;
+               player[0].weaponactive=-1;
+
+               if(difficulty==1)
+               {
+                       //player[0].speedmult=1/.9;
+                       player[0].power=1/.9;
+               }
+
+               if(difficulty==0)
+               {
+                       //player[0].speedmult=1/.8;
+                       player[0].power=1/.8;
+               }
+
+               //player[0].weaponstuck=1;
+
+               if(difficulty==1)player[0].damagetolerance=250;
+               if(difficulty==0)player[0].damagetolerance=300;
+               if(difficulty==0)player[0].armorhead*=1.5;
+               if(difficulty==0)player[0].armorhigh*=1.5;
+               if(difficulty==0)player[0].armorlow*=1.5;
+               cameraloc=player[0].coords;
+               cameraloc.y+=5;
+               rotation=player[0].rotation;
+
+               hawkcoords=player[0].coords;
+               hawkcoords.y+=30;
+
+               if(visibleloading){loadscreencolor=4; LoadingScreen();}
+               //weapons.numweapons=numplayers;
+               for(i=0;i<weapons.numweapons;i++)
+               {
+                       weapons.bloody[i]=0;
+                       weapons.blooddrip[i]=0;
+                       weapons.blooddripdelay[i]=0;
+                       weapons.onfire[i]=0;
+                       weapons.flamedelay[i]=0;
+                       weapons.damage[i]=0;
+                       //weapons.type[i]=sword;
+                       if(weapons.type[i]==sword){
+                               weapons.mass[i]=1.5;
+                               weapons.tipmass[i]=1;
+                               weapons.length[i]=.8;
+                       }
+                       if(weapons.type[i]==staff){
+                               weapons.mass[i]=2;
+                               weapons.tipmass[i]=1;
+                               weapons.length[i]=1.5;
+                       }
+                       if(weapons.type[i]==knife){
+                               weapons.mass[i]=1;
+                               weapons.tipmass[i]=1.2;
+                               weapons.length[i]=.25;
+                       }
+                       weapons.position[i]=-1000;
+                       weapons.tippoint[i]=-1000;
+               }
+
+/*             for(i=0;i<32;i++){
+                       //if(i<16||i>20)                                
+                       FSOUND_StopSound(i);
+               }
+*/
+               LOG("Starting background music...");
+
+               FSOUND_StopSound(FSOUND_ALL);
+               if(environment==snowyenvironment)
+               {
+                       if(ambientsound)
+                       {
+                               PlayStreamEx(stream_wind, strm[stream_wind], NULL, TRUE);
+                               FSOUND_SetPaused(channels[stream_wind], FALSE);
+                               FSOUND_SetVolume(channels[stream_wind], 256);
+                       }
+               }
+               else if(environment==desertenvironment)
+               {
+                       if(ambientsound)
+                       {
+                               //PlaySoundEx(desertambient,
+                               //      samp[desertambient], NULL, TRUE);
+                               PlayStreamEx(stream_desertambient,
+                                       strm[stream_desertambient], NULL, TRUE);
+                               FSOUND_SetPaused(channels[stream_desertambient], FALSE);
+                               FSOUND_SetVolume(channels[stream_desertambient], 256);
+                       }
+               }
+               else if(environment==grassyenvironment)
+               {
+                       if(ambientsound)
+                       {
+                               //PlaySoundEx(wind, samp[wind], NULL, TRUE);
+                               PlayStreamEx(stream_wind, strm[stream_wind], NULL, TRUE);
+                               FSOUND_SetPaused(channels[stream_wind], FALSE);
+                               FSOUND_SetVolume(channels[stream_wind], 100);
+                       }
+               }
+               oldmusicvolume[0]=0;
+               oldmusicvolume[1]=0;
+               oldmusicvolume[2]=0;
+               oldmusicvolume[3]=0;
+
+
+               /*LoadTexture(":Data:Textures:cloud.png",&sprites.cloudtexture,1,1);
+               LoadTexture(":Data:Textures:cloudimpact.png",&sprites.cloudimpacttexture,1,1);
+               LoadTexture(":Data:Textures:bloodparticle.png",&sprites.bloodtexture,1,1);
+               LoadTexture(":Data:Textures:snowflake.png",&sprites.snowflaketexture,1,1);
+               LoadTexture(":Data:Textures:flame.png",&sprites.flametexture,1,1);
+               LoadTexture(":Data:Textures:bloodflame.png",&sprites.bloodflametexture,1,1);
+               LoadTexture(":Data:Textures:smoke.png",&sprites.smoketexture,1,1);
+               LoadTexture(":Data:Textures:shine.png",&sprites.shinetexture,1,0);
+               */
+
+               if(!firstload)
+               {
+                       firstload=1;
+               }
+       }
+       leveltime=0;
+       loadingstuff=0;
+       visibleloading=0;
+}
+
+void   Game::Tick()
+{
+       static int i,k,j,l,m;
+       static XYZ facing,flatfacing,absflatfacing;
+       static XYZ rotatetarget;
+       static bool oldkey;
+       static float oldtargetrotation;
+       static int target, numgood;
+       static XYZ tempcoords1,tempcoords2;
+       static XYZ test;
+       static XYZ test2;
+       static XYZ lowpoint,lowpointtarget,lowpoint2,lowpointtarget2,lowpoint3,lowpointtarget3,lowpoint4,lowpointtarget4,lowpoint5,lowpointtarget5,lowpoint6,lowpointtarget6,lowpoint7,lowpointtarget7,colpoint,colpoint2;
+       static int whichhit;
+       static bool donesomething;
+       static bool oldjumpkeydown;
+
+       int templength;
+
+       float headprop,bodyprop,armprop,legprop;
+
+       if(newnetmessages){
+               newnetmessages=0;
+               PlaySoundEx( consolesuccesssound, samp[consolesuccesssound], NULL, TRUE);
+               FSOUND_SetVolume(channels[consolesuccesssound], 256);
+               FSOUND_SetPaused(channels[consolesuccesssound], FALSE);
+
+               for(k=14;k>=2;k--){
+                       for(j=0;j<255;j++){
+                               consoletext[k][j]=consoletext[k-1][j];
+                       }
+                       consolechars[k]=consolechars[k-1];
+               }
+               for(k=14;k>=2;k--){
+                       for(j=0;j<255;j++){
+                               displaytext[k][j]=displaytext[k-1][j];
+                       }
+                       displaychars[k]=displaychars[k-1];
+                       displaytime[k]=displaytime[k-1];
+               }
+               for(j=0;j<255;j++){
+                       consoletext[1][j]=' ';
+                       displaytext[1][j]=' ';
+               }
+               sprintf (consoletext[1], netmessages);
+               sprintf (displaytext[1], netmessages);
+               consolechars[1]=255;
+               displaychars[1]=255;
+               displaytime[1]=0;
+       }
+
+       for(i=0;i<15;i++){
+               displaytime[i]+=multiplier;
+       }
+
+       static unsigned char    theKeyMap[16];
+       GetKeys( theKeyMap );
+
+       keyboardfrozen=0;
+
+
+       static bool mainmenutogglekeydown;
+       if(!console){
+               if(mainmenu&&endgame==1)mainmenu=10;
+               if(IsKeyDown(theKeyMap, MAC_ESCAPE_KEY)&&!mainmenutogglekeydown&&(mainmenu==7&&entername)){
+                       for(j=0;j<255;j++){
+                               displaytext[0][j]=' ';
+                       }
+                       displaychars[0]=0;
+                       displayselected=0;
+                       entername=0;
+                       mainmenutogglekeydown=1;
+               }
+               if((IsKeyDown(theKeyMap, MAC_ESCAPE_KEY)||(mainmenu==0&&((IsKeyDown(theKeyMap, jumpkey)||IsKeyDown(theKeyMap, MAC_SPACE_KEY)||(campaign)))&&!oldjumpkeydown&&campaign&&winfreeze))&&!mainmenutogglekeydown&&(!mainmenu||gameon||mainmenu==3||mainmenu==4||mainmenu==5||mainmenu==6||(mainmenu==7&&!entername)||mainmenu==9||mainmenu==11||(mainmenu==12&&!tryquit)||mainmenu==13||mainmenu==14||mainmenu==15||mainmenu==16||mainmenu==17||mainmenu==10)){
+                       selected=-1;
+                       if(mainmenu==1||mainmenu==2||mainmenu==0){
+                               if(mainmenu==0&&!winfreeze)mainmenu=2;
+                               else if(mainmenu==0&&winfreeze&&(campaignchoosenext[campaignchoicewhich[whichchoice]])==1)mainmenu=100;
+                               else if(mainmenu==0&&winfreeze){
+                                       /*      if(campaignchoosenext[campaignchoicewhich[whichchoice]]==2)
+                                       stealthloading=1;
+                                       else stealthloading=0;
+
+                                       if(!stealthloading){
+                                       float gLoc[3]={0,0,0};
+                                       float vel[3]={0,0,0};
+                                       FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                                       PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                                       FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                                       FSOUND_SetVolume(channels[firestartsound], 256);
+                                       FSOUND_SetPaused(channels[firestartsound], FALSE);
+                                       FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                                       flashr=1;
+                                       flashg=0;
+                                       flashb=0;
+                                       flashamount=1;
+                                       flashdelay=1;
+                                       }
+
+                                       startbonustotal=0;
+
+                                       for(i=0;i<campaignnumlevels;i++){
+                                       levelvisible[i]=0;
+                                       levelhighlight[i]=0;
+                                       }
+
+                                       levelorder[0]=0;
+                                       levelvisible[0]=1;
+                                       if(accountcampaignchoicesmade[accountactive])
+                                       for(i=0;i<accountcampaignchoicesmade[accountactive];i++){
+                                       levelorder[i+1]=campaignnextlevel[levelorder[i]][accountcampaignchoices[accountactive][i]];
+                                       levelvisible[levelorder[i+1]]=1;
+                                       }
+                                       int whichlevelstart;
+                                       whichlevelstart=accountcampaignchoicesmade[accountactive]-1;
+                                       if(whichlevelstart<0){
+                                       campaignchoicenum=1;
+                                       campaignchoicewhich[0]=0;
+                                       }
+                                       else
+                                       {
+                                       campaignchoicenum=campaignnumnext[levelorder[whichlevelstart]];
+                                       if(campaignchoicenum)
+                                       for(i=0;i<campaignchoicenum;i++){
+                                       campaignchoicewhich[i]=campaignnextlevel[levelorder[whichlevelstart]][i];
+                                       levelvisible[campaignnextlevel[levelorder[whichlevelstart]][i]]=1;
+                                       levelhighlight[campaignnextlevel[levelorder[whichlevelstart]][i]]=1;
+                                       }
+                                       }
+
+                                       loading=2;
+                                       loadtime=0;
+                                       targetlevel=7;
+                                       if(firstload)TickOnceAfter();
+                                       if(!firstload)LoadStuff();
+                                       //else {
+                                       for(i=0;i<255;i++){
+                                       mapname[i]='\0';
+                                       }
+                                       mapname[0]=':';
+                                       mapname[1]='D';
+                                       mapname[2]='a';
+                                       mapname[3]='t';
+                                       mapname[4]='a';
+                                       mapname[5]=':';
+                                       mapname[6]='M';
+                                       mapname[7]='a';
+                                       mapname[8]='p';
+                                       mapname[9]='s';
+                                       mapname[10]=':';
+
+                                       //accountcampaignchoices[accountactive][accountcampaignchoicesmade[accountactive]]=whichchoice;
+                                       //accountcampaignchoicesmade[accountactive]++;
+
+
+                                       strcat(mapname,campaignmapname[campaignchoicewhich[0]]);
+                                       whichchoice=0;
+                                       visibleloading=1;
+                                       stillloading=1;
+                                       Loadlevel(mapname);
+                                       campaign=1;
+                                       mainmenu=0;
+                                       gameon=1;
+                                       FSOUND_SetPaused(channels[music3], TRUE);
+
+                                       stealthloading=0;*/
+                               }
+                               else if(mainmenu==1||mainmenu==2)mainmenu=0;
+                               if(mainmenu&&musictoggle){
+                                       if(mainmenu==1||mainmenu==2||mainmenu==100){
+                                               FSOUND_SetFrequency(FSOUND_ALL, 0.001);
+                                               PlayStreamEx( stream_music3, strm[stream_music3], NULL, TRUE);
+                                               FSOUND_SetPaused(channels[stream_music3], FALSE);
+                                               FSOUND_SetVolume(channels[stream_music3], 256);
+                                               FSOUND_SetPaused(channels[music1], TRUE);
+                                       }
+                               }
+                               if(!mainmenu){
+                                       FSOUND_SetPaused(channels[stream_music3], TRUE);
+                                       FSOUND_SetPaused(channels[music1], FALSE);
+                               }
+                       }
+                       if(mainmenu==3){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               if(newdetail>2)newdetail=detail;
+                               if(newdetail<0)newdetail=detail;
+                               if(newscreenwidth>3000)newscreenwidth=screenwidth;
+                               if(newscreenwidth<0)newscreenwidth=screenwidth;
+                               if(newscreenheight>3000)newscreenheight=screenheight;
+                               if(newscreenheight<0)newscreenheight=screenheight;
+
+                               //ofstream opstream(":Data:config.txt"); 
+                               ofstream opstream("./Data/config.txt"); 
+                               opstream << "Screenwidth:\n";
+                               opstream << newscreenwidth;
+                               opstream << "\nScreenheight:\n";
+                               opstream << newscreenheight;
+                               opstream << "\nMouse sensitivity:\n";
+                               opstream << usermousesensitivity;
+                               opstream << "\nBlur(0,1):\n";
+                               opstream << ismotionblur;
+                               opstream << "\nOverall Detail(0,1,2) higher=better:\n";
+                               opstream << newdetail;
+                               opstream << "\nFloating jump:\n";
+                               opstream << floatjump;
+                               opstream << "\nMouse jump:\n";
+                               opstream << mousejump;
+                               opstream << "\nAmbient sound:\n";
+                               opstream << ambientsound;
+                               opstream << "\nBlood (0,1,2):\n";
+                               opstream << bloodtoggle;
+                               opstream << "\nAuto slomo:\n";
+                               opstream << autoslomo;
+                               opstream << "\nFoliage:\n";
+                               opstream << foliage;
+                               opstream << "\nMusic:\n";
+                               opstream << musictoggle;
+                               opstream << "\nTrilinear:\n";
+                               opstream << trilinear;
+                               opstream << "\nDecals(shadows,blood puddles,etc):\n";
+                               opstream << decals;
+                               opstream << "\nInvert mouse:\n";
+                               opstream << invertmouse;
+                               opstream << "\nGamespeed:\n";
+                               if(oldgamespeed==0)oldgamespeed=1;
+                               opstream << oldgamespeed;
+                               opstream << "\nDifficulty(0,1,2) higher=harder:\n";
+                               opstream << difficulty;
+                               opstream << "\nDamage effects(blackout, doublevision):\n";
+                               opstream << damageeffects;
+                               opstream << "\nText:\n";
+                               opstream << texttoggle;
+                               opstream << "\nDebug:\n";
+                               opstream << debugmode;
+                               opstream << "\nVBL Sync:\n";
+                               opstream << vblsync;
+                               opstream << "\nShow Points:\n";
+                               opstream << showpoints;
+                               opstream << "\nAlways Blur:\n";
+                               opstream << alwaysblur;
+                               opstream << "\nImmediate mode (turn on on G5):\n";
+                               opstream << immediate;
+                               opstream << "\nVelocity blur:\n";
+                               opstream << velocityblur;
+                           opstream << "\nVolume:\n";
+                       opstream << volume;
+                               opstream << "\nForward key:\n";
+                               opstream << KeyToChar(forwardkey);
+                               opstream << "\nBack key:\n";
+                               opstream << KeyToChar(backkey);
+                               opstream << "\nLeft key:\n";
+                               opstream << KeyToChar(leftkey);
+                               opstream << "\nRight key:\n";
+                               opstream << KeyToChar(rightkey);
+                               opstream << "\nJump key:\n";
+                               opstream << KeyToChar(jumpkey);
+                               opstream << "\nCrouch key:\n";
+                               opstream << KeyToChar(crouchkey);
+                               opstream << "\nDraw key:\n";
+                               opstream << KeyToChar(drawkey);
+                               opstream << "\nThrow key:\n";
+                               opstream << KeyToChar(throwkey);
+                               opstream << "\nAttack key:\n";
+                               opstream << KeyToChar(attackkey);
+                               opstream << "\nChat key:\n";
+                               opstream << KeyToChar(chatkey);
+                               opstream.close();
+                       }       
+                       if(mainmenu==4||mainmenu==5||mainmenu==6||mainmenu==7||mainmenu==9||mainmenu==12||mainmenu==13||mainmenu==14||mainmenu==10||mainmenu==11||mainmenu==100){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+                       }       
+                       if(mainmenu==3&&gameon)mainmenu=2;
+                       if(mainmenu==3&&!gameon)mainmenu=1;
+                       if(mainmenu==5&&gameon)mainmenu=2;
+                       if(mainmenu==5&&!gameon)mainmenu=1;
+                       if(mainmenu==4)mainmenu=3;
+                       if(mainmenu==6)mainmenu=5;
+                       if(mainmenu==7)mainmenu=1;
+                       if(mainmenu==9)mainmenu=5;
+                       if(mainmenu==11)mainmenu=5;
+                       if(mainmenu==12)mainmenu=5;
+                       if(mainmenu==13)mainmenu=12;
+                       if(mainmenu==14)mainmenu=13;
+                       if(mainmenu==10)mainmenu=5;
+                       if(mainmenu==100){
+                               mainmenu=5;
+                               gameon=0;
+                               winfreeze=0;
+                       }
+                       mainmenutogglekeydown=1;
+               }
+               if(!IsKeyDown(theKeyMap, MAC_ESCAPE_KEY)){
+                       mainmenutogglekeydown=0;
+               }
+       }
+
+       /*static bool minimaptogglekeydown;
+       if(IsKeyDown(theKeyMap, MAC_TAB_KEY)&&!minimaptogglekeydown){
+       minimap=1-minimap;
+       minimaptogglekeydown=1;
+       }
+       if(!IsKeyDown(theKeyMap, MAC_TAB_KEY)){
+       minimaptogglekeydown=0;
+       }
+       */
+
+       static bool minimaptogglekeydown;
+       if(IsKeyDown(theKeyMap, MAC_TAB_KEY)&&!minimaptogglekeydown&&tutoriallevel){
+               if(tutorialstage!=51)
+                       tutorialstagetime=tutorialmaxtime;
+               PlaySoundEx( consolefailsound, samp[consolefailsound], NULL, TRUE);
+               FSOUND_SetVolume(channels[consolefailsound], 128);
+               FSOUND_SetPaused(channels[consolefailsound], FALSE);
+               minimaptogglekeydown=1;
+       }
+       if(!IsKeyDown(theKeyMap, MAC_TAB_KEY)){
+               minimaptogglekeydown=0;
+       }
+
+       if(mainmenu){
+               //menu buttons
+               if(mainmenu==1||mainmenu==2){
+                       if(Button()&&!oldbutton&&selected==1){
+                               if(!gameon){
+                                       float gLoc[3]={0,0,0};
+                                       float vel[3]={0,0,0};
+                                       FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                                       PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                                       FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                                       FSOUND_SetVolume(channels[firestartsound], 256);
+                                       FSOUND_SetPaused(channels[firestartsound], FALSE);
+                                       FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                                       flashr=1;
+                                       flashg=0;
+                                       flashb=0;
+                                       flashamount=1;
+                                       flashdelay=1;
+
+                                       //new game
+                                       if(accountactive!=-1)mainmenu=5;
+                                       else mainmenu=7;
+                                       /*
+                                       startbonustotal=0;
+
+                                       loading=2;
+                                       loadtime=0;
+                                       if(firstload)TickOnceAfter();
+                                       if(!firstload)LoadStuff();
+                                       else {
+                                       Loadlevel(0);
+                                       }
+                                       mainmenu=0;
+                                       gameon=1;
+                                       FSOUND_SetPaused(channels[music3], TRUE);       */                      
+                               }
+                               else
+                               {
+                                       //resume
+                                       mainmenu=0;
+                                       FSOUND_SetPaused(channels[stream_music3], TRUE);
+                                       FSOUND_SetPaused(channels[music1], FALSE);
+                               }
+                       }
+
+                       if(Button()&&!oldbutton&&selected==2){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[firestartsound], 256);
+                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               //options
+
+                               mainmenu=3;                     
+
+                               if(newdetail>2)newdetail=detail;
+                               if(newdetail<0)newdetail=detail;
+                               if(newscreenwidth>3000)newscreenwidth=screenwidth;
+                               if(newscreenwidth<0)newscreenwidth=screenwidth;
+                               if(newscreenheight>3000)newscreenheight=screenheight;
+                               if(newscreenheight<0)newscreenheight=screenheight;      
+                       }
+
+                       if(Button()&&!oldbutton&&selected==3){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               if(!gameon){
+                                       //quit
+                                       tryquit=1;
+                                       if(registered)FSOUND_SetPaused(channels[stream_music3], TRUE);
+                               }
+                               else{
+                                       //end game
+                                       gameon=0;
+                                       mainmenu=1;
+                               }
+                       }
+                       if(Button())oldbutton=1;
+                       else oldbutton=0;
+               }
+
+               if(mainmenu==3){
+                       if(Button()&&!oldbutton&&selected!=-1){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[firestartsound], 256);
+                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+                       }
+                       if(Button()&&!oldbutton&&selected==0){
+                               int whichres;
+                               whichres=-1;
+                               if(newscreenwidth==640&&newscreenheight==480)whichres=0;
+                               if(newscreenwidth==800&&newscreenheight==600)whichres=1;
+                               if(newscreenwidth==1024&&newscreenheight==768)whichres=2;
+                               if(newscreenwidth==1280&&newscreenheight==1024)whichres=3;
+                               if(newscreenwidth==1600&&newscreenheight==1200)whichres=4;
+                               if(newscreenwidth==840&&newscreenheight==524)whichres=5;
+                               if(newscreenwidth==1024&&newscreenheight==640)whichres=6;
+                               if(newscreenwidth==1344&&newscreenheight==840)whichres=7;
+
+                               if(whichres==-1||whichres==7){
+                                       newscreenwidth=640;
+                                       newscreenheight=480;
+                               }
+                               if(whichres==0){
+                                       newscreenwidth=800;
+                                       newscreenheight=600;
+                               }
+                               if(whichres==1){
+                                       newscreenwidth=1024;
+                                       newscreenheight=768;
+                               }
+                               if(whichres==2){
+                                       newscreenwidth=1280;
+                                       newscreenheight=1024;
+                               }
+                               if(whichres==3){
+                                       newscreenwidth=1600;
+                                       newscreenheight=1200;
+                               }
+                               if(whichres==4){
+                                       newscreenwidth=840;
+                                       newscreenheight=524;
+                               }
+                               if(whichres==5){
+                                       newscreenwidth=1024;
+                                       newscreenheight=640;
+                               }
+                               if(whichres==6){
+                                       newscreenwidth=1344;
+                                       newscreenheight=840;
+                               }
+                       }
+                       if(Button()&&!oldbutton&&selected==1){
+                               newdetail++;
+                               if(newdetail>2)newdetail=0;
+                       }
+                       if(Button()&&!oldbutton&&selected==2){
+                               bloodtoggle++;
+                               if(bloodtoggle>2)bloodtoggle=0;
+                       }
+                       if(Button()&&!oldbutton&&selected==3){
+                               difficulty++;
+                               if(difficulty>2)difficulty=0;
+                       }
+                       if(Button()&&!oldbutton&&selected==4){
+                               ismotionblur=1-ismotionblur;
+                       }
+                       if(Button()&&!oldbutton&&selected==5){
+                               decals=1-decals;
+                       }
+                       if(Button()&&!oldbutton&&selected==6){
+                               musictoggle=1-musictoggle;
+
+                               if(!musictoggle){
+                                       FSOUND_SetPaused(channels[music1], TRUE);
+                                       FSOUND_SetPaused(channels[stream_music2], TRUE);
+                                       FSOUND_SetPaused(channels[stream_music3], TRUE);
+
+                                       for(i=0;i<4;i++){
+                                               oldmusicvolume[i]=0;
+                                               musicvolume[i]=0;
+                                       }
+                               }
+
+                               if(musictoggle){
+                                       PlayStreamEx( stream_music3, strm[stream_music3], NULL, TRUE);
+                                       FSOUND_SetPaused(channels[stream_music3], FALSE);
+                                       FSOUND_SetVolume(channels[stream_music3], 256);                         
+                               }
+                       }
+                       if(Button()&&!oldbutton&&selected==9){
+                               invertmouse=1-invertmouse;
+                       }
+                       if(Button()&&!oldbutton&&selected==10){
+                               usermousesensitivity+=.2;
+                               if(usermousesensitivity>2)usermousesensitivity=.2;
+                       }
+                       if(Button()&&!oldbutton&&selected==11){
+                               volume+=.1f;
+                               if(volume>1.0001f)volume=0;
+                               FSOUND_SetSFXMasterVolume((int)(volume*255));
+                       }
+                       if(Button()&&!oldbutton&&selected==7){
+                               /*float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[firestartsound], 256);
+                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+                               */
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               //options
+
+                               mainmenu=4;             
+                               keyselect=-1;
+                       }
+                       if(Button()&&!oldbutton&&selected==8){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               if(newdetail>2)newdetail=detail;
+                               if(newdetail<0)newdetail=detail;
+                               if(newscreenwidth>3000)newscreenwidth=screenwidth;
+                               if(newscreenwidth<0)newscreenwidth=screenwidth;
+                               if(newscreenheight>3000)newscreenheight=screenheight;
+                               if(newscreenheight<0)newscreenheight=screenheight;
+
+
+                               //ofstream opstream(":Data:config.txt"); 
+                               ofstream opstream("./Data/config.txt"); 
+                               opstream << "Screenwidth:\n";
+                               opstream << newscreenwidth;
+                               opstream << "\nScreenheight:\n";
+                               opstream << newscreenheight;
+                               opstream << "\nMouse sensitivity:\n";
+                               opstream << usermousesensitivity;
+                               opstream << "\nBlur(0,1):\n";
+                               opstream << ismotionblur;
+                               opstream << "\nOverall Detail(0,1,2) higher=better:\n";
+                               opstream << newdetail;
+                               opstream << "\nFloating jump:\n";
+                               opstream << floatjump;
+                               opstream << "\nMouse jump:\n";
+                               opstream << mousejump;
+                               opstream << "\nAmbient sound:\n";
+                               opstream << ambientsound;
+                               opstream << "\nBlood (0,1,2):\n";
+                               opstream << bloodtoggle;
+                               opstream << "\nAuto slomo:\n";
+                               opstream << autoslomo;
+                               opstream << "\nFoliage:\n";
+                               opstream << foliage;
+                               opstream << "\nMusic:\n";
+                               opstream << musictoggle;
+                               opstream << "\nTrilinear:\n";
+                               opstream << trilinear;
+                               opstream << "\nDecals(shadows,blood puddles,etc):\n";
+                               opstream << decals;
+                               opstream << "\nInvert mouse:\n";
+                               opstream << invertmouse;
+                               opstream << "\nGamespeed:\n";
+                               if(oldgamespeed==0)oldgamespeed=1;
+                               opstream << oldgamespeed;
+                               opstream << "\nDifficulty(0,1,2) higher=harder:\n";
+                               opstream << difficulty;
+                               opstream << "\nDamage effects(blackout, doublevision):\n";
+                               opstream << damageeffects;
+                               opstream << "\nText:\n";
+                               opstream << texttoggle;
+                               opstream << "\nDebug:\n";
+                               opstream << debugmode;
+                               opstream << "\nVBL Sync:\n";
+                               opstream << vblsync;
+                               opstream << "\nShow Points:\n";
+                               opstream << showpoints;
+                               opstream << "\nAlways Blur:\n";
+                               opstream << alwaysblur;
+                               opstream << "\nImmediate mode (turn on on G5):\n";
+                               opstream << immediate;
+                               opstream << "\nVelocity blur:\n";
+                               opstream << velocityblur;
+                           opstream << "\nVolume:\n";
+                       opstream << volume;
+                               opstream << "\nForward key:\n";
+                               opstream << KeyToChar(forwardkey);
+                               opstream << "\nBack key:\n";
+                               opstream << KeyToChar(backkey);
+                               opstream << "\nLeft key:\n";
+                               opstream << KeyToChar(leftkey);
+                               opstream << "\nRight key:\n";
+                               opstream << KeyToChar(rightkey);
+                               opstream << "\nJump key:\n";
+                               opstream << KeyToChar(jumpkey);
+                               opstream << "\nCrouch key:\n";
+                               opstream << KeyToChar(crouchkey);
+                               opstream << "\nDraw key:\n";
+                               opstream << KeyToChar(drawkey);
+                               opstream << "\nThrow key:\n";
+                               opstream << KeyToChar(throwkey);
+                               opstream << "\nAttack key:\n";
+                               opstream << KeyToChar(attackkey);
+                               opstream << "\nChat key:\n";
+                               opstream << KeyToChar(chatkey);
+                               opstream.close();
+
+                               if(mainmenu==3&&gameon)mainmenu=2;
+                               if(mainmenu==3&&!gameon)mainmenu=1;
+                       }
+                       if(Button())oldbutton=1;
+                       else oldbutton=0;
+               }
+               if(mainmenu==4){
+                       if(Button()&&!oldbutton&&selected!=-1&&keyselect==-1){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[firestartsound], 256);
+                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+                       }
+                       if(Button()&&!oldbutton&&selected<9&&keyselect==-1){
+                               keyselect=selected;
+                               oldbuttons[0]=1;
+                               oldbuttons[1]=1;
+                               oldbuttons[2]=1;
+                       }
+                       if(keyselect!=-1){
+                               for(i=0;i<3;i++)
+                                       if(!buttons[i]&&!oldbutton&&!Button())oldbuttons[i]=0;
+                               for(i=0;i<140;i++){
+                                       if((IsKeyDown(theKeyMap, i)||(buttons[0]&&!oldbuttons[0]&&!oldbutton)||(buttons[1]&&!oldbuttons[1]&&!oldbutton))&&keyselect!=-1){
+                                               if(i!=MAC_ESCAPE_KEY&&(strcmp(KeyToChar(i),"unknown")||(buttons[0]&&!oldbuttons[0]&&!oldbutton)||(buttons[1]&&!oldbuttons[1]&&!oldbutton))){
+                                                       float gLoc[3]={0,0,0};
+                                                       float vel[3]={0,0,0};
+                                                       FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                                                       PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[fireendsound], 256);
+                                                       FSOUND_SetPaused(channels[fireendsound], FALSE);
+                                                       FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                                                       int keynum;
+                                                       keynum=i;
+                                                       if(buttons[0]&&!oldbuttons[0])keynum=MAC_MOUSEBUTTON1;
+                                                       if(buttons[1]&&!oldbuttons[1])keynum=MAC_MOUSEBUTTON2;
+
+
+
+                                                       if(keyselect==0)forwardkey=keynum;
+                                                       if(keyselect==1)backkey=keynum;
+                                                       if(keyselect==2)leftkey=keynum;
+                                                       if(keyselect==3)rightkey=keynum;
+                                                       if(keyselect==4)crouchkey=keynum;
+                                                       if(keyselect==5)jumpkey=keynum;
+                                                       if(keyselect==6)drawkey=keynum;
+                                                       if(keyselect==7)throwkey=keynum;
+                                                       if(keyselect==8)attackkey=keynum;
+                                                       keyselect=-1;
+                                               }
+                                       }
+                               }}
+                       if(Button()&&!oldbutton&&selected==9){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               mainmenu=3;
+
+                               if(newdetail>2)newdetail=detail;
+                               if(newdetail<0)newdetail=detail;
+                               if(newscreenwidth>3000)newscreenwidth=screenwidth;
+                               if(newscreenwidth<0)newscreenwidth=screenwidth;
+                               if(newscreenheight>3000)newscreenheight=screenheight;
+                               if(newscreenheight<0)newscreenheight=screenheight;
+                       }
+               }
+
+               if(mainmenu==5){
+                       if(accountcampaignchoicesmade[accountactive]>8&&!registered){
+                               FSOUND_SetFrequency(FSOUND_ALL, 0.001);         
+                               PlayStreamEx( stream_music3, strm[stream_music3], NULL, TRUE);
+                               FSOUND_SetPaused(channels[stream_music3], FALSE);
+                               FSOUND_SetVolume(channels[stream_music3], 256);
+
+                               gameon=0;
+                               mainmenu=12;
+                               accountcampaignchoicesmade[accountactive]=0;
+                               accountcampaignscore[accountactive]=0;
+                               accountcampaigntime[accountactive]=0;
+
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+                       }
+
+                       if(endgame==2){
+                               accountcampaignchoicesmade[accountactive]=0;
+                               accountcampaignscore[accountactive]=0;
+                               accountcampaigntime[accountactive]=0;
+                               endgame=0;
+                       }
+
+                       if(Button()&&!oldbutton&&selected==1){                  
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[firestartsound], 256);
+                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               startbonustotal=0;
+
+                               loading=2;
+                               loadtime=0;
+                               targetlevel=-1;
+                               if(firstload)TickOnceAfter();
+                               if(!firstload)LoadStuff();
+                               else {
+                                       Loadlevel(-1);
+                               }
+
+                               mainmenu=0;
+                               gameon=1;
+                               FSOUND_SetPaused(channels[stream_music3], TRUE);
+                       }
+                       if(Button()&&!oldbutton&&selected-7>=accountcampaignchoicesmade[accountactive]){//selected>=7&&(selected-7<=campaignnumchoices)){                       
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[firestartsound], 256);
+                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               startbonustotal=0;
+
+                               loading=2;
+                               loadtime=0;
+                               targetlevel=7;
+                               if(firstload)TickOnceAfter();
+                               if(!firstload)LoadStuff();
+                               //else {
+                               for(i=0;i<255;i++){
+                                       mapname[i]='\0';
+                               }
+                               mapname[0]=':';
+                               mapname[1]='D';
+                               mapname[2]='a';
+                               mapname[3]='t';
+                               mapname[4]='a';
+                               mapname[5]=':';
+                               mapname[6]='M';
+                               mapname[7]='a';
+                               mapname[8]='p';
+                               mapname[9]='s';
+                               mapname[10]=':';
+                               strcat(mapname,campaignmapname[campaignchoicewhich[selected-7-accountcampaignchoicesmade[accountactive]]]);
+                               whichchoice=selected-7-accountcampaignchoicesmade[accountactive];
+                               visibleloading=1;
+                               stillloading=1;
+                               Loadlevel(mapname);
+                               //Loadlevel(campaignmapname[levelorder[selected-7]]);
+                               //}
+                               campaign=1;
+                               mainmenu=0;
+                               gameon=1;
+                               FSOUND_SetPaused(channels[stream_music3], TRUE);
+                       }
+                       if(Button()&&!oldbutton&&selected==4){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               if(mainmenu==5&&gameon)mainmenu=2;
+                               if(mainmenu==5&&!gameon)mainmenu=1;
+                       }
+                       if(Button()&&!oldbutton&&selected==5){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               mainmenu=7;
+                       }
+                       if(Button()&&!oldbutton&&selected==3){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[firestartsound], 256);
+                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               mainmenu=6;
+                       }
+                       if(Button()&&!oldbutton&&selected==2){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[firestartsound], 256);
+                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               mainmenu=9;
+                       }
+                       if(Button())oldbutton=1;
+                       else oldbutton=0;
+               }
+               if(mainmenu==9){
+                       if(Button()&&!oldbutton&&selected<numchallengelevels&&selected>=0&&selected<=accountprogress[accountactive]){                   
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[firestartsound], 256);
+                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               startbonustotal=0;
+
+                               loading=2;
+                               loadtime=0;
+                               targetlevel=selected;
+                               if(firstload)TickOnceAfter();
+                               if(!firstload)LoadStuff();
+                               else {
+                                       Loadlevel(selected);
+                               }
+                               campaign=0;
+
+                               mainmenu=0;
+                               gameon=1;
+                               FSOUND_SetPaused(channels[stream_music3], TRUE);
+                       }
+                       if(Button()&&!oldbutton&&selected==numchallengelevels){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               mainmenu=5;
+                       }
+                       if(Button())oldbutton=1;
+                       else oldbutton=0;
+               }
+               if(mainmenu==11){
+                       if(Button()&&!oldbutton&&selected<numchallengelevels&&selected>=0&&selected<=accountprogress[accountactive]){                   
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[firestartsound], 256);
+                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               startbonustotal=0;
+
+                               loading=2;
+                               loadtime=0;
+                               targetlevel=selected;
+                               if(firstload)TickOnceAfter();
+                               if(!firstload)LoadStuff();
+                               else {
+                                       Loadlevel(selected);
+                               }
+                               campaign=0;
+
+                               mainmenu=0;
+                               gameon=1;
+                               FSOUND_SetPaused(channels[stream_music3], TRUE);
+                       }
+                       if(Button()&&!oldbutton&&selected==numchallengelevels){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               mainmenu=5;
+                       }
+                       if(Button())oldbutton=1;
+                       else oldbutton=0;
+               }
+               if(mainmenu==10){
+                       endgame=2;
+                       if(Button()&&!oldbutton&&selected==3){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               mainmenu=5;
+                       }
+                       if(Button())oldbutton=1;
+                       else oldbutton=0;
+               }
+
+               if(mainmenu==15||mainmenu==16){
+                       if(Button()&&!oldbutton&&selected==1){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               if(mainmenu==15)mainmenu=5;
+                               else mainmenu=12;
+                       }
+                       if(Button())oldbutton=1;
+                       else oldbutton=0;
+               }
+
+               if(mainmenu==12){
+                       endgame=2;
+                       if(Button()&&!oldbutton&&selected==3){
+                               if(tryquit)quit=1;
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               mainmenu=5;
+                       }
+
+                       if(Button()&&!oldbutton&&selected==4){
+                               registernow=1;
+                               quit=1;
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+                       }
+
+
+                       if(Button()&&!oldbutton&&selected==5){
+                               tryquit=0;
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               mainmenu=13;
+                       }
+                       if(Button())oldbutton=1;
+                       else oldbutton=0;
+               }
+               if(mainmenu==6){
+                       if(Button()&&!oldbutton&&selected!=-1){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[firestartsound], 256);
+                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+                       }
+                       if(Button()&&!oldbutton&&selected==1){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               for(i=accountactive;i<numaccounts-1;i++){
+                                       accountdifficulty[i]=accountdifficulty[i+1];
+                                       accountcampaignchoicesmade[i]=accountcampaignchoicesmade[i+1];
+                                       for(j=0;j<accountcampaignchoicesmade[i+1];j++){
+                                               accountcampaignchoices[i][j]=accountcampaignchoices[i+1][j];
+                                       }
+                                       accountpoints[i]=accountpoints[i+1];
+                                       for(j=0;j<50;j++){
+                                               accounthighscore[i][j]=accounthighscore[i+1][j];
+                                               accountfasttime[i][j]=accountfasttime[i+1][j];
+                                       }
+                                       for(j=0;j<60;j++){
+                                               accountunlocked[i][j]=accountunlocked[i+1][j];
+                                       }
+                                       for(j=0;j<256;j++){
+                                               accountname[i][j]=accountname[i+1][j];
+                                       }
+                                       accountcampaignhighscore[i]=accountcampaignhighscore[i+1];
+                                       accountprogress[i]=accountprogress[i+1];
+                                       accountcampaignfasttime[i]=accountcampaignfasttime[i+1];
+                                       accountcampaignscore[i]=accountcampaignscore[i+1];
+                                       accountcampaigntime[i]=accountcampaigntime[i+1];
+                               }
+
+                               numaccounts--;
+                               accountactive=-1;
+
+
+                               mainmenu=7;
+                       }
+                       if(Button()&&!oldbutton&&selected==2){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               mainmenu=5;
+                       }
+                       if(Button())oldbutton=1;
+                       else oldbutton=0;
+               }
+               if(mainmenu==7){
+                       if(Button()&&!oldbutton&&selected!=-1){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[firestartsound], 256);
+                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+                       }
+                       if(Button()&&!oldbutton&&selected==0&&numaccounts<8){
+                               entername=1;
+                       }
+                       if(Button()&&!oldbutton&&selected>0&&selected<numaccounts+1){
+                               accountactive=selected-1;
+                               mainmenu=5;
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+                       }
+                       if(Button()&&!oldbutton&&selected==numaccounts+1){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                               mainmenu=1;
+
+                               for(j=0;j<255;j++){
+                                       displaytext[0][j]=' ';
+                               }
+                               displaychars[0]=0;
+                               displayselected=0;
+                               entername=0;
+                       }
+                       if(Button())oldbutton=1;
+                       else oldbutton=0;
+               }
+               if(mainmenu==8){
+                       if(Button()&&!oldbutton&&selected!=-1){
+                               float gLoc[3]={0,0,0};
+                               float vel[3]={0,0,0};
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[firestartsound], 256);
+                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                               if(selected==0)accountdifficulty[accountactive]=0;
+                               if(selected==1)accountdifficulty[accountactive]=1;
+                               if(selected==2)accountdifficulty[accountactive]=2;
+
+                               mainmenu=5;     
+
+                               flashr=1;
+                               flashg=0;
+                               flashb=0;
+                               flashamount=1;
+                               flashdelay=1;
+
+                       }
+                       if(Button())oldbutton=1;
+                       else oldbutton=0;
+               }
+
+
+               if(Button())oldbutton=1;
+               else oldbutton=0;
+
+               if(IsKeyDown(theKeyMap, MAC_Q_KEY)&&IsKeyDown(theKeyMap, MAC_COMMAND_KEY)){
+                       tryquit=1;
+                       if(mainmenu==3){
+                               if(newdetail>2)newdetail=detail;
+                               if(newdetail<0)newdetail=detail;
+                               if(newscreenwidth>3000)newscreenwidth=screenwidth;
+                               if(newscreenwidth<0)newscreenwidth=screenwidth;
+                               if(newscreenheight>3000)newscreenheight=screenheight;
+                               if(newscreenheight<0)newscreenheight=screenheight;
+
+                               //ofstream opstream(":Data:config.txt"); 
+                               ofstream opstream("./Data/config.txt"); 
+                               opstream << "Screenwidth:\n";
+                               opstream << newscreenwidth;
+                               opstream << "\nScreenheight:\n";
+                               opstream << newscreenheight;
+                               opstream << "\nMouse sensitivity:\n";
+                               opstream << usermousesensitivity;
+                               opstream << "\nBlur(0,1):\n";
+                               opstream << ismotionblur;
+                               opstream << "\nOverall Detail(0,1,2) higher=better:\n";
+                               opstream << newdetail;
+                               opstream << "\nFloating jump:\n";
+                               opstream << floatjump;
+                               opstream << "\nMouse jump:\n";
+                               opstream << mousejump;
+                               opstream << "\nAmbient sound:\n";
+                               opstream << ambientsound;
+                               opstream << "\nBlood (0,1,2):\n";
+                               opstream << bloodtoggle;
+                               opstream << "\nAuto slomo:\n";
+                               opstream << autoslomo;
+                               opstream << "\nFoliage:\n";
+                               opstream << foliage;
+                               opstream << "\nMusic:\n";
+                               opstream << musictoggle;
+                               opstream << "\nTrilinear:\n";
+                               opstream << trilinear;
+                               opstream << "\nDecals(shadows,blood puddles,etc):\n";
+                               opstream << decals;
+                               opstream << "\nInvert mouse:\n";
+                               opstream << invertmouse;
+                               opstream << "\nGamespeed:\n";
+                               if(oldgamespeed==0)oldgamespeed=1;
+                               opstream << oldgamespeed;
+                               opstream << "\nDifficulty(0,1,2) higher=harder:\n";
+                               opstream << difficulty;
+                               opstream << "\nDamage effects(blackout, doublevision):\n";
+                               opstream << damageeffects;
+                               opstream << "\nText:\n";
+                               opstream << texttoggle;
+                               opstream << "\nDebug:\n";
+                               opstream << debugmode;
+                               opstream << "\nVBL Sync:\n";
+                               opstream << vblsync;
+                               opstream << "\nShow Points:\n";
+                               opstream << showpoints;
+                               opstream << "\nAlways Blur:\n";
+                               opstream << alwaysblur;
+                               opstream << "\nImmediate mode (turn on on G5):\n";
+                               opstream << immediate;
+                               opstream << "\nVelocity blur:\n";
+                               opstream << velocityblur;
+                           opstream << "\nVolume:\n";
+                       opstream << volume;
+                               opstream << "\nForward key:\n";
+                               opstream << KeyToChar(forwardkey);
+                               opstream << "\nBack key:\n";
+                               opstream << KeyToChar(backkey);
+                               opstream << "\nLeft key:\n";
+                               opstream << KeyToChar(leftkey);
+                               opstream << "\nRight key:\n";
+                               opstream << KeyToChar(rightkey);
+                               opstream << "\nJump key:\n";
+                               opstream << KeyToChar(jumpkey);
+                               opstream << "\nCrouch key:\n";
+                               opstream << KeyToChar(crouchkey);
+                               opstream << "\nDraw key:\n";
+                               opstream << KeyToChar(drawkey);
+                               opstream << "\nThrow key:\n";
+                               opstream << KeyToChar(throwkey);
+                               opstream << "\nAttack key:\n";
+                               opstream << KeyToChar(attackkey);
+                               opstream << "\nChat key:\n";
+                               opstream << KeyToChar(chatkey);
+                               opstream.close();
+                       }
+               }
+
+               if(mainmenu==1||mainmenu==2){
+                       if(loaddistrib>4)transition+=multiplier/8;
+                       if(transition>1){
+                               transition=0;
+                               anim++;
+                               if(anim>4)anim=0;
+                               loaddistrib=0;
+                       }
+               }
+               FSOUND_SetFrequency(channels[stream_music3], 22050);            
+
+               if(entername||mainmenu==13||mainmenu==14){
+                       for(i=0;i<140;i++){
+                               if(IsKeyDown(theKeyMap, i)){
+                                       togglekeydelay[i]+=multiplier;
+                                       if(togglekeydelay[i]>.4){
+                                               togglekey[i]=0;
+                                               togglekeydelay[i]=.36;
+                                       }
+                                       if(!togglekey[i]){
+                                               if(KeyToSingleChar(i)!='\0'&&displaychars[0]<60){
+                                                       for(j=255;j>=displayselected+1;j--){
+                                                               displaytext[0][j]=displaytext[0][j-1];
+                                                       }
+                                                       displaytext[0][displayselected]=KeyToSingleChar(i);
+                                                       if(IsKeyDown(theKeyMap, MAC_SHIFT_KEY))displaytext[0][displayselected]=Shift(displaytext[0][displayselected]);
+                                                       displayselected++;
+                                                       displaychars[0]++;
+                                               }
+                                               if(i==MAC_DELETE_KEY&&displayselected!=0){
+                                                       for(j=displayselected-1;j<255;j++){
+                                                               displaytext[0][j]=displaytext[0][j+1];
+                                                       }
+                                                       displaytext[0][255]=' ';
+                                                       displayselected--;
+                                                       displaychars[0]--;
+                                               }
+                                               if(i==MAC_ARROW_LEFT_KEY&&displayselected!=0){
+                                                       displayselected--;
+                                               }
+                                               if(i==MAC_ARROW_RIGHT_KEY&&displayselected<displaychars[0]){
+                                                       displayselected++;
+                                               }
+                                               if(i==MAC_RETURN_KEY&&entername){
+                                                       if(displaychars[0]){
+                                                               numaccounts++;
+                                                               strcpy(accountname[numaccounts-1],displaytext[0]);
+                                                               accountactive=numaccounts-1;
+                                                               accountdifficulty[accountactive]=1;
+                                                               accountprogress[accountactive]=0;
+                                                               accountpoints[accountactive]=0;
+                                                               accountcampaigntime[accountactive]=0;
+                                                               accountcampaignscore[accountactive]=0;
+                                                               accountcampaignfasttime[accountactive]=0;
+                                                               accountcampaignhighscore[accountactive]=0;
+                                                               for(j=0;j<50;j++){
+                                                                       accounthighscore[accountactive][j]=0;
+                                                                       accountfasttime[accountactive][j]=0;
+                                                               }
+                                                               for(j=0;j<60;j++){
+                                                                       accountunlocked[accountactive][j]=0;
+                                                               }
+                                                               accountcampaignchoicesmade[accountactive]=0;
+
+                                                               for(j=0;j<255;j++){
+                                                                       displaytext[0][j]=' ';
+                                                               }
+                                                               displaychars[0]=0;
+                                                               displayselected=0;
+                                                               entername=0;
+
+                                                               mainmenu=8;
+
+                                                               flashr=1;
+                                                               flashg=0;
+                                                               flashb=0;
+                                                               flashamount=1;
+                                                               flashdelay=1;
+
+                                                               float gLoc[3]={0,0,0};
+                                                               float vel[3]={0,0,0};
+                                                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                                                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[firestartsound], 256);
+                                                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                                                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                                                               for(j=0;j<255;j++){
+                                                                       displaytext[0][j]=' ';
+                                                               }
+                                                               displaychars[0]=0;
+
+
+                                                               displayselected=0;
+                                                       }}
+
+                                               if(i==MAC_RETURN_KEY&&mainmenu==14){
+                                                       if(displaychars[0]){
+                                                               char serialstring[256];
+                                                               char tempstring[256];
+                                                               sprintf (tempstring, "%s-windows", registrationname);
+                                                               long num1;
+                                                               long num2;
+                                                               long num3;
+                                                               long num4;
+                                                               long long longnum;
+                                                               longnum = MD5_string ( tempstring);
+                                                               //longnum = 1111111111111111;
+                                                               num1 = longnum/100000000;
+                                                               num2 = longnum%100000000;
+                                                               sprintf (tempstring, "%d-%d-%d-%d\0\0\0\0\0", num1/10000, num1%10000, num2/10000, num2%10000);
+
+                                                               int goodcode=3;
+                                                               int numchars=3;
+                                                               if(num1/10000>999)numchars+=4;
+                                                               else if(num1/10000>99)numchars+=3;
+                                                               else if(num1/10000>9)numchars+=2;
+                                                               else numchars+=1;
+                                                               if(num1%10000>999)numchars+=4;
+                                                               else if(num1%10000>99)numchars+=3;
+                                                               else if(num1%10000>9)numchars+=2;
+                                                               else numchars+=1;
+                                                               if(num2/10000>999)numchars+=4;
+                                                               else if(num2/10000>99)numchars+=3;
+                                                               else if(num2/10000>9)numchars+=2;
+                                                               else numchars+=1;
+                                                               if(num2%10000>999)numchars+=4;
+                                                               else if(num2%10000>99)numchars+=3;
+                                                               else if(num2%10000>9)numchars+=2;
+                                                               else numchars+=1;
+
+                                                               //numchars=12;
+
+                                                               for(j=0;j<numchars;j++){
+                                                                       if(displaytext[0][j]!=tempstring[j]&&tempstring[j]!=' '&&tempstring[j]!='\0')goodcode--;
+                                                               }
+
+                                                               if(longnum==5077041556214789)goodcode=-1;
+
+                                                               if(goodcode<0)goodcode=0;
+
+                                                               if(goodcode){
+                                                                       registered=1;
+                                                                       mainmenu=15;
+
+                                                                       FILE                    *tfile;
+                                                                       tfile=fopen( ":Data:Sounds:flame.ogg", "wb" );
+                                                                       if (tfile)
+                                                                       {
+                                                                               int numchars;
+                                                                               numchars=strlen(registrationname);
+                                                                               fpackf(tfile, "Bb", registered);
+                                                                               fpackf(tfile, "Bi", numchars);
+                                                                               if(numchars>0)
+                                                                               {
+                                                                                       for(j=0;j<numchars;j++)
+                                                                                       {
+                                                                                               fpackf(tfile, "Bb",  registrationname[j]);
+                                                                                       }
+                                                                               }
+                                                                               fpackf(tfile, "Bi", num1);
+                                                                               fpackf(tfile, "Bi", num2);
+                                                                               fclose(tfile);
+                                                                       }
+                                                               }
+                                                               else
+                                                               {
+                                                                       mainmenu=16;
+                                                               }
+                                                               flashr=1;
+                                                               flashg=0;
+                                                               flashb=0;
+                                                               flashamount=1;
+                                                               flashdelay=1;
+
+                                                               float gLoc[3]={0,0,0};
+                                                               float vel[3]={0,0,0};
+                                                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                                                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[firestartsound], 256);
+                                                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                                                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                                                               for(j=0;j<255;j++){
+                                                                       displaytext[0][j]=' ';
+                                                               }
+                                                               displaychars[0]=0;
+                                                               displayselected=0;
+                                                       }}
+
+                                               if(i==MAC_RETURN_KEY&&mainmenu==13){
+                                                       if(displaychars[0]){
+                                                               sprintf (registrationname, "%s", displaytext[0]);
+                                                               if(displaychars[0]<254)registrationname[displaychars[0]]='\0';
+
+                                                               mainmenu=14;
+
+                                                               flashr=1;
+                                                               flashg=0;
+                                                               flashb=0;
+                                                               flashamount=1;
+                                                               flashdelay=1;
+
+                                                               float gLoc[3]={0,0,0};
+                                                               float vel[3]={0,0,0};
+                                                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                                                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[firestartsound], 256);
+                                                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                                                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                                                               for(j=0;j<255;j++){
+                                                                       displaytext[0][j]=' ';
+                                                               }
+                                                               displaychars[0]=0;
+
+                                                               /*char tempstring[50];
+                                                               sprintf (tempstring, registrationname);
+                                                               long num1;
+                                                               long num2;
+                                                               long num3;
+                                                               long num4;
+                                                               long long longnum;
+                                                               longnum = MD5_string ( tempstring);
+                                                               num1 = longnum/100000000;
+                                                               num2 = longnum%100000000;
+                                                               sprintf (displaytext[0], "%d-%d-%d-%d", num1/10000, num1%10000, num2/10000, num2%10000);
+
+                                                               displaychars[0]=strlen(displaytext[0]);
+                                                               */
+                                                               displayselected=0;
+                                                       }}
+                                       }
+                                       togglekey[i]=1;
+                               }
+                               else {
+                                       togglekey[i]=0;
+                                       togglekeydelay[i]=0;
+                               }
+                       }
+
+                       displayblinkdelay-=multiplier;
+                       if(displayblinkdelay<=0){
+                               displayblinkdelay=.3;
+                               displayblink=1-displayblink;
+                       }
+               }
+       }
+
+       if(!mainmenu){  
+               if(hostile==1)hostiletime+=multiplier;
+               else hostiletime=0;
+               if(!winfreeze)leveltime+=multiplier;
+               if(IsKeyDown(theKeyMap, MAC_ESCAPE_KEY)){
+                       chatting=0;
+                       console=0;
+                       freeze=0;
+                       displaychars[0]=0;
+               }
+
+               if(IsKeyDown(theKeyMap, chatkey)&&!chattogglekeydown&&!console&&!chatting&&debugmode){
+                       chatting=1;
+                       chattogglekeydown=1;
+                       togglekey[chatkey]=1;
+                       togglekeydelay[chatkey]=-20;
+               }
+
+               if(!IsKeyDown(theKeyMap, chatkey)){
+                       chattogglekeydown=0;
+               }
+
+               if(chatting){
+                       for(i=0;i<140;i++){
+                               if(IsKeyDown(theKeyMap, i)){
+                                       togglekeydelay[i]+=multiplier;
+                                       if(togglekeydelay[i]>.4){
+                                               togglekey[i]=0;
+                                               togglekeydelay[i]=.36;
+                                       }
+                                       if(!togglekey[i]){
+                                               if(KeyToSingleChar(i)!='\0'&&displaychars[0]<60){
+                                                       for(j=255;j>=displayselected+1;j--){
+                                                               displaytext[0][j]=displaytext[0][j-1];
+                                                       }
+                                                       displaytext[0][displayselected]=KeyToSingleChar(i);
+                                                       if(IsKeyDown(theKeyMap, MAC_SHIFT_KEY))displaytext[0][displayselected]=Shift(displaytext[0][displayselected]);
+                                                       displayselected++;
+                                                       displaychars[0]++;
+                                               }
+                                               if(i==MAC_DELETE_KEY&&displayselected!=0){
+                                                       for(j=displayselected-1;j<255;j++){
+                                                               displaytext[0][j]=displaytext[0][j+1];
+                                                       }
+                                                       displaytext[0][255]=' ';
+                                                       displayselected--;
+                                                       displaychars[0]--;
+                                               }
+                                               if(i==MAC_ARROW_LEFT_KEY&&displayselected!=0){
+                                                       displayselected--;
+                                               }
+                                               if(i==MAC_ARROW_RIGHT_KEY&&displayselected<displaychars[0]){
+                                                       displayselected++;
+                                               }
+                                               if(i==MAC_RETURN_KEY){
+                                                       if(displaychars[0]){
+                                                               /*for(j=0;j<displaychars[0];j++){
+                                                               talkname[j]=displaytext[0][j];
+                                                               }
+                                                               talkname[displaychars[0]]='\0';
+                                                               sprintf (chatname, "%s: %s",playerName,talkname);
+                                                               //NetworkSendInformation(chatname);
+                                                               */
+                                                               for(j=0;j<255;j++){
+                                                                       displaytext[0][j]=' ';
+                                                               }
+                                                               displaychars[0]=0;
+                                                               displayselected=0;
+                                                               chatting=0;
+                                                       }
+                                               }
+                                       }
+                                       togglekey[i]=1;
+                               }
+                               else {
+                                       togglekey[i]=0;
+                                       togglekeydelay[i]=0;
+                               }
+                       }
+
+                       displayblinkdelay-=multiplier;
+                       if(displayblinkdelay<=0){
+                               displayblinkdelay=.3;
+                               displayblink=1-displayblink;
+                       }
+               }
+
+               if(chatting)keyboardfrozen=1;
+
+               if(IsKeyDown(theKeyMap, MAC_V_KEY)&&!freezetogglekeydown&&debugmode){
+                       freeze=1-freeze;
+                       if(freeze){
+                               FSOUND_SetFrequency(FSOUND_ALL, 0.001);
+                       }
+                       freezetogglekeydown=1;
+               }
+
+               if(!IsKeyDown(theKeyMap, MAC_V_KEY)&&!IsKeyDown(theKeyMap, MAC_F1_KEY)){
+                       freezetogglekeydown=0;
+               }
+
+               if(IsKeyDown(theKeyMap, MAC_TILDE_KEY)&&!consoletogglekeydown&&debugmode){
+                       console=1-console;
+                       if(!console)freeze=0;
+                       if(console){
+                               FSOUND_SetFrequency(FSOUND_ALL, 0.001);
+                       }
+                       consoletogglekeydown=1;
+               }
+
+               if(!IsKeyDown(theKeyMap, MAC_TILDE_KEY)){
+                       consoletogglekeydown=0;
+               }
+
+               if(console)freeze=1;
+
+               if(console&&!IsKeyDown(theKeyMap,MAC_COMMAND_KEY)){
+                       for(i=0;i<140;i++){
+                               if(IsKeyDown(theKeyMap, i)){
+                                       togglekeydelay[i]+=multiplier;
+                                       if(togglekeydelay[i]>.4){
+                                               togglekey[i]=0;
+                                               togglekeydelay[i]=.36;
+                                       }
+                                       if(!togglekey[i]){
+                                               if(KeyToSingleChar(i)!='\0'&&consolechars[0]<255){
+                                                       for(j=255;j>=consoleselected+1;j--){
+                                                               consoletext[0][j]=consoletext[0][j-1];
+                                                       }
+                                                       consoletext[0][consoleselected]=KeyToSingleChar(i);
+                                                       if(IsKeyDown(theKeyMap, MAC_SHIFT_KEY))consoletext[0][consoleselected]=Shift(consoletext[0][consoleselected]);
+                                                       consoleselected++;
+                                                       consolechars[0]++;
+                                               }
+                                               else if(i==MAC_ENTER_KEY){
+                                                       for(j=255;j>=consoleselected+1;j--){
+                                                               consoletext[0][j]=consoletext[0][j-1];
+                                                       }
+                                                       consoletext[0][consoleselected]='\n';
+                                                       consoleselected++;
+                                                       consolechars[0]++;
+                                               }
+                                               if(i==MAC_DELETE_KEY&&consoleselected!=0){
+                                                       for(j=consoleselected-1;j<255;j++){
+                                                               consoletext[0][j]=consoletext[0][j+1];
+                                                       }
+                                                       consoletext[0][255]=' ';
+                                                       consoleselected--;
+                                                       consolechars[0]--;
+                                               }
+                                               if(i==MAC_ARROW_UP_KEY){
+                                                       if(archiveselected<14)archiveselected++;
+                                                       for(j=0;j<255;j++){
+                                                               consolechars[0]=consolechars[archiveselected];
+                                                               consoletext[0][j]=consoletext[archiveselected][j];
+                                                               consoleselected=consolechars[0];
+                                                       }
+                                               }
+                                               if(i==MAC_ARROW_DOWN_KEY){
+                                                       if(archiveselected>0)archiveselected--;
+                                                       for(j=0;j<255;j++){
+                                                               consolechars[0]=consolechars[archiveselected];
+                                                               consoletext[0][j]=consoletext[archiveselected][j];
+                                                               consoleselected=consolechars[0];
+                                                       }
+                                               }
+                                               if(i==MAC_ARROW_LEFT_KEY&&consoleselected!=0){
+                                                       consoleselected--;
+                                               }
+                                               if(i==MAC_ARROW_RIGHT_KEY&&consoleselected<consolechars[0]){
+                                                       consoleselected++;
+                                               }
+                                               if(i==MAC_RETURN_KEY){
+                                                       archiveselected=0;
+                                                       donesomething=0;
+                                                       if(Compare(consoletext[0],"quit ",0,4)||Compare(consoletext[0],"exit ",0,4)){
+                                                               PlaySoundEx( consolesuccesssound, samp[consolesuccesssound], NULL, TRUE);
+                                                               FSOUND_SetVolume(channels[consolesuccesssound], 256);
+                                                               FSOUND_SetPaused(channels[consolesuccesssound], FALSE);
+                                                               donesomething=1;
+                                                               tryquit=1;
+                                                       }
+                                                       /*if(Compare(consoletext[0],"send ",0,4)){
+                                                       for(j=5;j<consolechars[0];j++){
+                                                       talkname[j-5]=consoletext[0][j];
+                                                       }
+                                                       talkname[consolechars[0]-5]='\0';
+                                                       sprintf (chatname, "%s: %s",playerName,talkname);
+                                                       //NetworkSendInformation(chatname);
+                                                       donesomething=1;
+                                                       }
+                                                       if(Compare(consoletext[0],"name ",0,4)){
+                                                       int numchars;
+                                                       numchars=consolechars[0]-5;
+                                                       if(numchars>32)numchars=32;
+                                                       for(j=5;j<numchars+5;j++){
+                                                       talkname[j-5]=consoletext[0][j];
+                                                       }
+                                                       talkname[numchars]='\0';
+                                                       sprintf (chatname, "Player %s is now known as %s.",playerName,talkname);
+                                                       //NetworkSendInformation(chatname);
+                                                       sprintf (playerName, "%s",talkname);
+                                                       //NetworkSendName(playerName);
+                                                       donesomething=1;
+                                                       }*/
+                                                       if(Compare(consoletext[0],"map ",0,3)){
+                                                               mapname[0]=':';
+                                                               mapname[1]='D';
+                                                               mapname[2]='a';
+                                                               mapname[3]='t';
+                                                               mapname[4]='a';
+                                                               mapname[5]=':';
+                                                               mapname[6]='M';
+                                                               mapname[7]='a';
+                                                               mapname[8]='p';
+                                                               mapname[9]='s';
+                                                               mapname[10]=':';
+                                                               for(j=4;j<consolechars[0];j++){
+                                                                       mapname[j-4+11]=consoletext[0][j];
+                                                               }
+                                                               mapname[consolechars[0]-4+11]='\0';
+                                                               Loadlevel(mapname);
+                                                               whichlevel=-2;
+                                                               campaign=0;
+                                                               donesomething=1;
+                                                       }
+                                                       /*if(Compare(consoletext[0],"connect ",0,7)&&!ishost){
+                                                       int v;
+                                                       unsigned char playerNameStr[32];
+                                                       char theIPAddress[256];
+                                                       char thePort[32];
+                                                       NMUInt32 port = 25710;
+
+                                                       strcpy(playerName, "Client");
+                                                       GameC2PStr( playerName, playerNameStr );
+
+                                                       for(j=0;j<consolechars[0]-8;j++){
+                                                       theIPAddress[j]=consoletext[0][j+8];
+                                                       }
+                                                       theIPAddress[consolechars[0]-8]='\0';
+
+                                                       sprintf( thePort, "%li", port );
+                                                       v=NetworkStartClient( theIPAddress, thePort, playerNameStr );
+                                                       if(v)
+                                                       {
+                                                       if(consolechars[0]>0){
+                                                       for(k=14;k>=1;k--){
+                                                       for(j=0;j<255;j++){
+                                                       consoletext[k][j]=consoletext[k-1][j];
+                                                       }
+                                                       consolechars[k]=consolechars[k-1];
+                                                       }
+                                                       for(j=0;j<255;j++){
+                                                       consoletext[0][j]=' ';
+                                                       }
+                                                       if(v!=-4994)sprintf (consoletext[0], "Error #%d!!!",v);
+                                                       else sprintf (consoletext[0], "Could not open connection");
+
+                                                       consolechars[0]=255;
+                                                       consoleselected=0;
+                                                       }
+                                                       }
+                                                       else 
+                                                       {
+                                                       donesomething=1;
+                                                       PlaySoundEx( consolesuccesssound, samp[consolesuccesssound], NULL, TRUE);
+                                                       FSOUND_SetVolume(channels[consolesuccesssound], 256);
+                                                       FSOUND_SetPaused(channels[consolesuccesssound], FALSE);
+
+                                                       if(consolechars[0]>0){
+                                                       for(k=14;k>=1;k--){
+                                                       for(j=0;j<255;j++){
+                                                       consoletext[k][j]=consoletext[k-1][j];
+                                                       }
+                                                       consolechars[k]=consolechars[k-1];
+                                                       }
+                                                       for(j=0;j<255;j++){
+                                                       consoletext[0][j]=' ';
+                                                       }
+                                                       sprintf (consoletext[0], "Connected to %s",theIPAddress);
+
+                                                       consolechars[0]=255;
+                                                       consoleselected=0;
+                                                       }
+                                                       }
+                                                       }
+
+                                                       if(Compare(consoletext[0],"host ",0,4)){
+                                                       unsigned char gameNameStr[32], playerNameStr[32];
+                                                       char gameName[32];//, playerName[32];
+                                                       NMUInt32 port;
+                                                       int players;
+                                                       int v;
+
+                                                       port = 25710;
+                                                       players =4;
+
+                                                       strcpy(gameName, "Host's game");
+                                                       strcpy(playerName, "Host");
+                                                       GameC2PStr( gameName, gameNameStr );
+                                                       GameC2PStr( playerName, playerNameStr );
+
+                                                       v=NetworkStartServer( (NMUInt16)port, players, gameNameStr, playerNameStr );
+                                                       if(v)
+                                                       {
+                                                       if(consolechars[0]>0){
+                                                       for(k=14;k>=1;k--){
+                                                       for(j=0;j<255;j++){
+                                                       consoletext[k][j]=consoletext[k-1][j];
+                                                       }
+                                                       consolechars[k]=consolechars[k-1];
+                                                       }
+                                                       for(j=0;j<255;j++){
+                                                       consoletext[0][j]=' ';
+                                                       }
+                                                       sprintf (consoletext[0], "Error #%d!!!",v);
+
+                                                       consolechars[0]=255;
+                                                       consoleselected=0;
+                                                       }
+                                                       }
+                                                       else
+                                                       {
+                                                       donesomething=1;
+                                                       PlaySoundEx( consolesuccesssound, samp[consolesuccesssound], NULL, TRUE);
+                                                       FSOUND_SetVolume(channels[consolesuccesssound], 256);
+                                                       FSOUND_SetPaused(channels[consolesuccesssound], FALSE);
+
+                                                       if(consolechars[0]>0){
+                                                       for(k=14;k>=1;k--){
+                                                       for(j=0;j<255;j++){
+                                                       consoletext[k][j]=consoletext[k-1][j];
+                                                       }
+                                                       consolechars[k]=consolechars[k-1];
+                                                       }
+                                                       for(j=0;j<255;j++){
+                                                       consoletext[0][j]=' ';
+                                                       }
+                                                       sprintf (consoletext[0], "Game hosted");
+
+                                                       consolechars[0]=255;
+                                                       consoleselected=0;
+                                                       }
+                                                       }
+                                                       }
+                                                       */
+                                                       if(Compare(consoletext[0],"save ",0,4)){
+                                                               mapname[0]=':';
+                                                               mapname[1]='D';
+                                                               mapname[2]='a';
+                                                               mapname[3]='t';
+                                                               mapname[4]='a';
+                                                               mapname[5]=':';
+                                                               mapname[6]='M';
+                                                               mapname[7]='a';
+                                                               mapname[8]='p';
+                                                               mapname[9]='s';
+                                                               mapname[10]=':';
+                                                               for(j=5;j<consolechars[0];j++){
+                                                                       mapname[j-5+11]=consoletext[0][j];
+                                                               }
+                                                               mapname[consolechars[0]-5+11]='\0';
+
+                                                               PlaySoundEx( consolesuccesssound, samp[consolesuccesssound], NULL, TRUE);
+                                                               FSOUND_SetVolume(channels[consolesuccesssound], 256);
+                                                               FSOUND_SetPaused(channels[consolesuccesssound], FALSE);
+
+                                                               int mapvers;
+                                                               mapvers=12;
+
+
+                                                               FILE                    *tfile;
+                                                               tfile=fopen( mapname, "wb" );
+                                                               fpackf(tfile, "Bi", mapvers);
+                                                               //fpackf(tfile, "Bi", indemo);
+                                                               fpackf(tfile, "Bi", maptype);
+                                                               fpackf(tfile, "Bi", hostile);
+                                                               fpackf(tfile, "Bf Bf", viewdistance, fadestart);
+                                                               fpackf(tfile, "Bb Bf Bf Bf", skyboxtexture, skyboxr, skyboxg, skyboxb);
+                                                               fpackf(tfile, "Bf Bf Bf", skyboxlightr, skyboxlightg, skyboxlightb);
+                                                               fpackf(tfile, "Bf Bf Bf Bf Bf Bi", player[0].coords.x, player[0].coords.y, player[0].coords.z, player[0].rotation, player[0].targetrotation, player[0].num_weapons);
+                                                               if(player[0].num_weapons>0&&player[0].num_weapons<5)
+                                                                       for(j=0;j<player[0].num_weapons;j++){
+                                                                               fpackf(tfile, "Bi", weapons.type[player[0].weaponids[j]]);
+                                                                       }
+
+                                                                       fpackf(tfile, "Bf Bf Bf", player[0].armorhead, player[0].armorhigh, player[0].armorlow);
+                                                                       fpackf(tfile, "Bf Bf Bf", player[0].protectionhead, player[0].protectionhigh, player[0].protectionlow);
+                                                                       fpackf(tfile, "Bf Bf Bf", player[0].metalhead, player[0].metalhigh, player[0].metallow);
+                                                                       fpackf(tfile, "Bf Bf", player[0].power, player[0].speedmult);
+
+                                                                       fpackf(tfile, "Bi", player[0].numclothes);
+
+                                                                       fpackf(tfile, "Bi Bi", player[0].whichskin, player[0].creature);
+
+                                                                       fpackf(tfile, "Bi", numdialogues);
+                                                                       if(numdialogues)
+                                                                               for(k=0;k<numdialogues;k++){
+                                                                                       fpackf(tfile, "Bi", numdialogueboxes[k]);
+                                                                                       fpackf(tfile, "Bi", dialoguetype[k]);
+                                                                                       for(l=0;l<10;l++){
+                                                                                               fpackf(tfile, "Bf Bf Bf", participantlocation[k][l].x, participantlocation[k][l].y, participantlocation[k][l].z);
+                                                                                               fpackf(tfile, "Bf", participantrotation[k][l]);
+                                                                                       }
+                                                                                       if(numdialogueboxes)
+                                                                                               for(l=0;l<numdialogueboxes[k];l++){
+                                                                                                       fpackf(tfile, "Bi", dialogueboxlocation[k][l]);
+                                                                                                       fpackf(tfile, "Bf", dialogueboxcolor[k][l][0]);
+                                                                                                       fpackf(tfile, "Bf", dialogueboxcolor[k][l][1]);
+                                                                                                       fpackf(tfile, "Bf", dialogueboxcolor[k][l][2]);
+                                                                                                       fpackf(tfile, "Bi", dialogueboxsound[k][l]);
+
+                                                                                                       templength=strlen(dialoguetext[k][l]);
+                                                                                                       fpackf(tfile, "Bi",(templength));
+                                                                                                       for(m=0;m<templength;m++){
+                                                                                                               fpackf(tfile, "Bb", dialoguetext[k][l][m]);
+                                                                                                               if(dialoguetext[k][l][m]=='\0')break;
+                                                                                                       }
+
+                                                                                                       templength=strlen(dialoguename[k][l]);
+                                                                                                       fpackf(tfile, "Bi",templength);
+                                                                                                       for(m=0;m<templength;m++){
+                                                                                                               fpackf(tfile, "Bb", dialoguename[k][l][m]);
+                                                                                                               if(dialoguename[k][l][m]=='\0')break;   
+                                                                                                       }
+
+                                                                                                       fpackf(tfile, "Bf Bf Bf", dialoguecamera[k][l].x, dialoguecamera[k][l].y, dialoguecamera[k][l].z);
+                                                                                                       fpackf(tfile, "Bi", participantfocus[k][l]);
+                                                                                                       fpackf(tfile, "Bi", participantaction[k][l]);
+
+                                                                                                       for(m=0;m<10;m++)
+                                                                                                               fpackf(tfile, "Bf Bf Bf", participantfacing[k][l][m].x, participantfacing[k][l][m].y, participantfacing[k][l][m].z);
+
+                                                                                                       fpackf(tfile, "Bf Bf",dialoguecamerarotation[k][l],dialoguecamerarotation2[k][l]);
+                                                                                               }
+                                                                               }
+
+                                                                               if(player[0].numclothes)
+                                                                                       for(k=0;k<player[0].numclothes;k++){
+                                                                                               templength=strlen(player[0].clothes[k]);
+                                                                                               fpackf(tfile, "Bi", templength);
+                                                                                               for(l=0;l<templength;l++)
+                                                                                                       fpackf(tfile, "Bb", player[0].clothes[k][l]);
+                                                                                               fpackf(tfile, "Bf Bf Bf", player[0].clothestintr[k], player[0].clothestintg[k], player[0].clothestintb[k]);                                                                                                                                             
+                                                                                       }
+
+                                                                                       fpackf(tfile, "Bi", environment);
+
+                                                                                       fpackf(tfile, "Bi", objects.numobjects);
+
+                                                                                       if(objects.numobjects)
+                                                                                               for(k=0;k<objects.numobjects;k++){
+                                                                                                       fpackf(tfile, "Bi Bf Bf Bf Bf Bf Bf", objects.type[k], objects.rotation[k], objects.rotation2[k], objects.position[k].x, objects.position[k].y, objects.position[k].z, objects.scale[k]);
+                                                                                               }
+
+                                                                                               fpackf(tfile, "Bi", numhotspots);
+                                                                                               if(numhotspots)
+                                                                                                       for(i=0;i<numhotspots;i++){
+                                                                                                               fpackf(tfile, "Bi Bf Bf Bf Bf", hotspottype[i],hotspotsize[i],hotspot[i].x,hotspot[i].y,hotspot[i].z);
+                                                                                                               templength=strlen(hotspottext[i]);
+                                                                                                               fpackf(tfile, "Bi",templength);
+                                                                                                               for(l=0;l<templength;l++)
+                                                                                                                       fpackf(tfile, "Bb", hotspottext[i][l]);
+                                                                                                       }
+
+                                                                                                       fpackf(tfile, "Bi", numplayers);
+                                                                                                       if(numplayers>1&&numplayers<maxplayers)
+                                                                                                               for(j=1;j<numplayers;j++){
+                                                                                                                       fpackf(tfile, "Bi Bi Bf Bf Bf Bi Bi Bf Bb Bf", player[j].whichskin, player[j].creature, player[j].coords.x, player[j].coords.y, player[j].coords.z, player[j].num_weapons, player[j].howactive, player[j].scale, player[j].immobile, player[j].rotation);
+                                                                                                                       if(player[j].num_weapons>0&&player[j].num_weapons<5)
+                                                                                                                               for(k=0;k<player[j].num_weapons;k++){
+                                                                                                                                       fpackf(tfile, "Bi", weapons.type[player[j].weaponids[k]]);
+                                                                                                                               }
+                                                                                                                               if(player[j].numwaypoints<30){
+                                                                                                                                       fpackf(tfile, "Bi", player[j].numwaypoints);
+                                                                                                                                       for(k=0;k<player[j].numwaypoints;k++){
+                                                                                                                                               fpackf(tfile, "Bf", player[j].waypoints[k].x);
+                                                                                                                                               fpackf(tfile, "Bf", player[j].waypoints[k].y);
+                                                                                                                                               fpackf(tfile, "Bf", player[j].waypoints[k].z);
+                                                                                                                                               fpackf(tfile, "Bi", player[j].waypointtype[k]);
+                                                                                                                                       }
+                                                                                                                                       fpackf(tfile, "Bi", player[j].waypoint);
+                                                                                                                               }
+                                                                                                                               else{
+                                                                                                                                       player[j].numwaypoints=0;
+                                                                                                                                       player[j].waypoint=0;
+                                                                                                                                       fpackf(tfile, "Bi Bi Bi", player[j].numwaypoints, player[j].waypoint, player[j].waypoint);
+                                                                                                                               }
+
+                                                                                                                               fpackf(tfile, "Bf Bf Bf", player[j].armorhead, player[j].armorhigh, player[j].armorlow);
+                                                                                                                               fpackf(tfile, "Bf Bf Bf", player[j].protectionhead, player[j].protectionhigh, player[j].protectionlow);
+                                                                                                                               fpackf(tfile, "Bf Bf Bf", player[j].metalhead, player[j].metalhigh, player[j].metallow);
+                                                                                                                               fpackf(tfile, "Bf Bf", player[j].power, player[j].speedmult);
+
+                                                                                                                               if(player[j].creature==wolftype){
+                                                                                                                                       headprop=player[j].proportionhead.x/1.1;
+                                                                                                                                       bodyprop=player[j].proportionbody.x/1.1;
+                                                                                                                                       armprop=player[j].proportionarms.x/1.1;
+                                                                                                                                       legprop=player[j].proportionlegs.x/1.1;
+                                                                                                                               }
+
+                                                                                                                               if(player[j].creature==rabbittype){
+                                                                                                                                       headprop=player[j].proportionhead.x/1.2;
+                                                                                                                                       bodyprop=player[j].proportionbody.x/1.05;
+                                                                                                                                       armprop=player[j].proportionarms.x/1.00;
+                                                                                                                                       legprop=player[j].proportionlegs.x/1.1;
+                                                                                                                               }
+
+                                                                                                                               fpackf(tfile, "Bf Bf Bf Bf", headprop, bodyprop, armprop, legprop);
+
+
+
+                                                                                                                               fpackf(tfile, "Bi", player[j].numclothes);
+                                                                                                                               if(player[j].numclothes)
+                                                                                                                                       for(k=0;k<player[j].numclothes;k++){
+                                                                                                                                               int templength;
+                                                                                                                                               templength=strlen(player[j].clothes[k]);
+                                                                                                                                               fpackf(tfile, "Bi", templength);
+                                                                                                                                               for(l=0;l<templength;l++)
+                                                                                                                                                       fpackf(tfile, "Bb", player[j].clothes[k][l]);
+                                                                                                                                               fpackf(tfile, "Bf Bf Bf", player[j].clothestintr[k], player[j].clothestintg[k], player[j].clothestintb[k]);                                                                                                                             
+                                                                                                                                       }
+                                                                                                               }
+
+                                                                                                               fpackf(tfile, "Bi", numpathpoints);
+                                                                                                               if(numpathpoints)
+                                                                                                                       for(j=0;j<numpathpoints;j++){
+                                                                                                                               fpackf(tfile, "Bf Bf Bf Bi", pathpoint[j].x, pathpoint[j].y, pathpoint[j].z, numpathpointconnect[j]);
+                                                                                                                               for(k=0;k<numpathpointconnect[j];k++){
+                                                                                                                                       fpackf(tfile, "Bi", pathpointconnect[j][k]);
+                                                                                                                               }
+                                                                                                                       }
+
+                                                                                                                       fpackf(tfile, "Bf Bf Bf Bf", mapcenter.x, mapcenter.y, mapcenter.z, mapradius);
+
+
+                                                                                                                       fclose(tfile);
+                                                                                                                       donesomething=1;
+
+                                                                                                                       /*
+                                                                                                                       FILE                    *tfile;
+                                                                                                                       tfile=fopen( mapname, "wb" );
+                                                                                                                       fwrite( &mapvers, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[0].coords.x, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &player[0].coords.y, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &player[0].coords.z, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &player[0].rotation, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &player[0].targetrotation, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &player[0].num_weapons, 1, sizeof(int), tfile );
+                                                                                                                       if(player[0].num_weapons>0&&player[0].num_weapons<5)
+                                                                                                                       for(j=0;j<player[0].num_weapons;j++){
+                                                                                                                       fwrite( &weapons.type[player[0].weaponids[j]], 1, sizeof(int), tfile );
+                                                                                                                       }
+
+                                                                                                                       fwrite( &player[0].armorhead, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[0].armorhigh, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[0].armorlow, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[0].protectionhead, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[0].protectionhigh, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[0].protectionlow, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[0].metalhead, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[0].metalhigh, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[0].metallow, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[0].power, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[0].speedmult, 1, sizeof(int), tfile );
+
+                                                                                                                       fwrite( &player[0].numclothes, 1, sizeof(int), tfile );
+                                                                                                                       if(player[0].numclothes)
+                                                                                                                       for(k=0;k<player[0].numclothes;k++){
+                                                                                                                       int templength;
+                                                                                                                       templength=strlen(player[0].clothes[k]);
+                                                                                                                       fwrite( &templength,1,sizeof(int),tfile);       
+                                                                                                                       for(l=0;l<templength;l++)
+                                                                                                                       fwrite( &player[0].clothes[k][l],1,sizeof(char),tfile);
+                                                                                                                       fwrite( &player[0].clothestintr[k],1,sizeof(float),tfile);      
+                                                                                                                       fwrite( &player[0].clothestintg[k],1,sizeof(float),tfile);      
+                                                                                                                       fwrite( &player[0].clothestintb[k],1,sizeof(float),tfile);                                                                              
+                                                                                                                       }
+
+                                                                                                                       fwrite( &environment, 1, sizeof(int), tfile );
+
+                                                                                                                       fwrite( &objects.numobjects, 1, sizeof(int), tfile );
+
+                                                                                                                       for(k=0;k<objects.numobjects;k++){
+                                                                                                                       fwrite( &objects.type[k], 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &objects.rotation[k], 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &objects.rotation2[k], 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &objects.position[k].x, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &objects.position[k].y, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &objects.position[k].z, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &objects.scale[k], 1, sizeof(float), tfile );
+                                                                                                                       }
+
+                                                                                                                       fwrite( &numplayers, 1, sizeof(int), tfile );
+                                                                                                                       if(numplayers>1&&numplayers<maxplayers)
+                                                                                                                       for(j=1;j<numplayers;j++){
+                                                                                                                       fwrite( &player[j].whichskin, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[j].creature, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[j].coords.x, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &player[j].coords.y, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &player[j].coords.z, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &player[j].num_weapons, 1, sizeof(int), tfile );
+                                                                                                                       if(player[j].num_weapons>0&&player[j].num_weapons<5)
+                                                                                                                       for(k=0;k<player[j].num_weapons;k++){
+                                                                                                                       fwrite( &weapons.type[player[j].weaponids[k]], 1, sizeof(int), tfile );
+                                                                                                                       }
+                                                                                                                       if(player[j].numwaypoints<30){
+                                                                                                                       fwrite( &player[j].numwaypoints, 1, sizeof(int), tfile );
+                                                                                                                       for(k=0;k<player[j].numwaypoints;k++){
+                                                                                                                       fwrite( &player[j].waypoints[k].x, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &player[j].waypoints[k].y, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &player[j].waypoints[k].z, 1, sizeof(float), tfile );
+                                                                                                                       }
+                                                                                                                       fwrite( &player[j].waypoint, 1, sizeof(int), tfile );
+                                                                                                                       //fwrite( &player[j].jumppath, 1, sizeof(bool), tfile );
+                                                                                                                       }
+                                                                                                                       else{
+                                                                                                                       player[j].numwaypoints=0;
+                                                                                                                       player[j].waypoint=0;
+                                                                                                                       fwrite( &player[j].numwaypoints, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[j].waypoint, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[j].waypoint, 1, sizeof(int), tfile );
+                                                                                                                       }
+                                                                                                                       fwrite( &player[j].armorhead, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[j].armorhigh, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[j].armorlow, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[j].protectionhead, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[j].protectionhigh, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[j].protectionlow, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[j].metalhead, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[j].metalhigh, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[j].metallow, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[j].power, 1, sizeof(int), tfile );
+                                                                                                                       fwrite( &player[j].speedmult, 1, sizeof(int), tfile );
+
+                                                                                                                       fwrite( &player[j].numclothes, 1, sizeof(int), tfile );
+                                                                                                                       if(player[j].numclothes)
+                                                                                                                       for(k=0;k<player[j].numclothes;k++){
+                                                                                                                       int templength;
+                                                                                                                       templength=strlen(player[j].clothes[k]);
+                                                                                                                       fwrite( &templength,1,sizeof(int),tfile);       
+                                                                                                                       for(l=0;l<templength;l++)
+                                                                                                                       fwrite( &player[j].clothes[k][l],1,sizeof(char),tfile);
+                                                                                                                       fwrite( &player[j].clothestintr[k],1,sizeof(float),tfile);      
+                                                                                                                       fwrite( &player[j].clothestintg[k],1,sizeof(float),tfile);      
+                                                                                                                       fwrite( &player[j].clothestintb[k],1,sizeof(float),tfile);                                                                              
+                                                                                                                       }
+                                                                                                                       }
+                                                                                                                       fwrite( &numpathpoints, 1, sizeof(int), tfile );
+                                                                                                                       if(numpathpoints)
+                                                                                                                       for(j=0;j<numpathpoints;j++){
+                                                                                                                       fwrite( &pathpoint[j].x, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &pathpoint[j].y, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &pathpoint[j].z, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &numpathpointconnect[j], 1, sizeof(int), tfile );
+                                                                                                                       for(k=0;k<numpathpointconnect[j];k++){
+                                                                                                                       fwrite( &pathpointconnect[j][k], 1, sizeof(int), tfile );
+                                                                                                                       }
+                                                                                                                       }
+
+                                                                                                                       fwrite( &mapcenter.x, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &mapcenter.y, 1, sizeof(float), tfile );
+                                                                                                                       fwrite( &mapcenter.z, 1, sizeof(float), tfile );
+
+                                                                                                                       fwrite( &mapradius, 1, sizeof(float), tfile );
+
+                                                                                                                       fclose(tfile);
+                                                                                                                       donesomething=1;*/
+                                                       }
+                                                       /*
+                                                       if(Compare(consoletext[0],"save ",0,4)){
+                                                       mapname[0]=':';
+                                                       mapname[1]='D';
+                                                       mapname[2]='a';
+                                                       mapname[3]='t';
+                                                       mapname[4]='a';
+                                                       mapname[5]=':';
+                                                       mapname[6]='M';
+                                                       mapname[7]='a';
+                                                       mapname[8]='p';
+                                                       mapname[9]='s';
+                                                       mapname[10]=':';
+                                                       for(j=5;j<consolechars[0];j++){
+                                                       mapname[j-5+11]=consoletext[0][j];
+                                                       }
+                                                       mapname[consolechars[0]-5+11]='\0';
+
+                                                       PlaySoundEx( consolesuccesssound, samp[consolesuccesssound], NULL, TRUE);
+                                                       FSOUND_SetVolume(channels[consolesuccesssound], 256);
+                                                       FSOUND_SetPaused(channels[consolesuccesssound], FALSE);
+
+                                                       FILE                    *tfile;
+                                                       tfile=fopen( mapname, "wb" );
+                                                       fwrite( &player[0].coords, 1, sizeof(XYZ), tfile );
+                                                       fwrite( &player[0].rotation, 1, sizeof(float), tfile );
+                                                       fwrite( &player[0].targetrotation, 1, sizeof(float), tfile );
+                                                       fwrite( &player[0].num_weapons, 1, sizeof(int), tfile );
+                                                       if(player[0].num_weapons>0&&player[0].num_weapons<5)
+                                                       for(j=0;j<player[0].num_weapons;j++){
+                                                       fwrite( &weapons.type[player[0].weaponids[j]], 1, sizeof(int), tfile );
+                                                       }
+                                                       fwrite( &environment, 1, sizeof(int), tfile );
+
+                                                       fwrite( &objects.numobjects, 1, sizeof(int), tfile );
+                                                       fwrite( &objects.type, 1, sizeof(int)*objects.numobjects, tfile );
+                                                       fwrite( &objects.rotation, 1, sizeof(float)*objects.numobjects, tfile );
+                                                       fwrite( &objects.position, 1, sizeof(XYZ)*objects.numobjects, tfile );
+                                                       fwrite( &objects.scale, 1, sizeof(float)*objects.numobjects, tfile );
+
+                                                       fwrite( &numplayers, 1, sizeof(int), tfile );
+                                                       if(numplayers>1&&numplayers<maxplayers)
+                                                       for(j=1;j<numplayers;j++){
+                                                       fwrite( &player[j].coords, 1, sizeof(XYZ), tfile );
+                                                       fwrite( &player[j].num_weapons, 1, sizeof(int), tfile );
+                                                       if(player[j].num_weapons>0&&player[j].num_weapons<5)
+                                                       for(k=0;k<player[j].num_weapons;k++){
+                                                       fwrite( &weapons.type[player[j].weaponids[k]], 1, sizeof(int), tfile );
+                                                       }
+                                                       if(player[j].numwaypoints<30){
+                                                       fwrite( &player[j].numwaypoints, 1, sizeof(int), tfile );
+                                                       fwrite( &player[j].waypoints, 1, sizeof(XYZ)*player[j].numwaypoints, tfile );
+                                                       fwrite( &player[j].waypoint, 1, sizeof(int), tfile );
+                                                       //fwrite( &player[j].jumppath, 1, sizeof(bool), tfile );
+                                                       }
+                                                       else{
+                                                       player[j].numwaypoints=0;
+                                                       player[j].waypoint=0;
+                                                       fwrite( &player[j].numwaypoints, 1, sizeof(int), tfile );
+                                                       fwrite( &player[j].waypoint, 1, sizeof(int), tfile );
+                                                       fwrite( &player[j].waypoint, 1, sizeof(int), tfile );
+                                                       }
+                                                       }
+                                                       fwrite( &numpathpoints, 1, sizeof(int), tfile );
+                                                       if(numpathpoints)
+                                                       for(j=0;j<numpathpoints;j++){
+                                                       fwrite( &pathpoint[j], 1, sizeof(XYZ), tfile );
+                                                       fwrite( &numpathpointconnect[j], 1, sizeof(int), tfile );
+                                                       for(k=0;k<numpathpointconnect[j];k++){
+                                                       fwrite( &pathpointconnect[j][k], 1, sizeof(int), tfile );
+                                                       }
+                                                       }
+                                                       fclose(tfile);
+                                                       donesomething=1;
+                                                       }*/
+                                                       if(Compare(consoletext[0],"cellar door ",0,11)||Compare(consoletext[0],"cellardoor ",0,10)){
+                                                               LoadTextureSave(":Data:Textures:Furdarko.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               donesomething=1;
+                                                       }
+                                                       /*if(Compare(consoletext[0],"Pants ",0,5)){
+                                                       AddClothes(":Data:Textures:Pants.png",0,1,&player[i].skeleton.skinText[0],&player[i].skeleton.skinsize);
+                                                       player[i].DoMipmaps(5,0,0,player[i].skeleton.skinsize,player[i].skeleton.skinsize);
+                                                       donesomething=1;
+                                                       }*/
+
+                                                       if(Compare(consoletext[0],"tintr ",0,5)||Compare(consoletext[0],"Tintr ",0,5)){
+                                                               for(j=6;j<consolechars[0];j++){
+                                                                       mapname[j-6]=consoletext[0][j];
+                                                               }
+
+                                                               tintr=atof(mapname);
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"speed ",0,5)||Compare(consoletext[0],"Speed ",0,5)){
+                                                               for(j=6;j<consolechars[0];j++){
+                                                                       mapname[j-6]=consoletext[0][j];
+                                                               }
+
+                                                               player[0].speedmult=atof(mapname);
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"strength ",0,8)||Compare(consoletext[0],"Strength ",0,8)){
+                                                               for(j=9;j<consolechars[0];j++){
+                                                                       mapname[j-9]=consoletext[0][j];
+                                                               }
+
+                                                               player[0].power=atof(mapname);
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"viewdistance ",0,12)||Compare(consoletext[0],"Viewdistance ",0,12)){
+                                                               for(j=13;j<consolechars[0];j++){
+                                                                       mapname[j-13]=consoletext[0][j];
+                                                               }
+
+                                                               viewdistance=atof(mapname)*100;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"fadestart ",0,9)||Compare(consoletext[0],"Fadestart ",0,9)){
+                                                               for(j=10;j<consolechars[0];j++){
+                                                                       mapname[j-10]=consoletext[0][j];
+                                                               }
+
+                                                               fadestart=atof(mapname);
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"power ",0,5)||Compare(consoletext[0],"Power ",0,5)){
+                                                               for(j=6;j<consolechars[0];j++){
+                                                                       mapname[j-6]=consoletext[0][j];
+                                                               }
+
+                                                               player[0].power=atof(mapname);
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"slomo ",0,5)||Compare(consoletext[0],"Slomo ",0,5)){
+                                                               for(j=6;j<consolechars[0];j++){
+                                                                       mapname[j-6]=consoletext[0][j];
+                                                               }
+
+                                                               slomospeed=atof(mapname);
+                                                               slomo=1-slomo;
+                                                               slomodelay=1000;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"slofreq ",0,7)||Compare(consoletext[0],"Slofreq ",0,7)){
+                                                               for(j=8;j<consolechars[0];j++){
+                                                                       mapname[j-8]=consoletext[0][j];
+                                                               }
+
+                                                               slomofreq=atoi(mapname);
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"size ",0,4)||Compare(consoletext[0],"Size ",0,4)){
+                                                               for(j=5;j<consolechars[0];j++){
+                                                                       mapname[j-5]=consoletext[0][j];
+                                                               }
+
+                                                               player[0].scale=atof(mapname)*.2;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"sizenear ",0,8)||Compare(consoletext[0],"Sizenear ",0,8)){
+                                                               int closest=-1;
+                                                               float closestdist=-1;
+                                                               float distance;
+                                                               if(numplayers>1)
+                                                                       for(i=1;i<numplayers;i++){
+                                                                               distance=findDistancefast(&player[i].coords,&player[0].coords);
+                                                                               if(closestdist==-1||distance<closestdist){
+                                                                                       closestdist=distance;
+                                                                                       closest=i;
+                                                                               }
+                                                                       }
+
+                                                                       for(j=9;j<consolechars[0];j++){
+                                                                               mapname[j-9]=consoletext[0][j];
+                                                                       }
+
+                                                                       player[closest].scale=atof(mapname)*.2;
+
+                                                                       donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"proportionnear ",0,14)||Compare(consoletext[0],"Proportionnear ",0,14)){
+                                                               int startpoint;
+                                                               int alldone;
+
+                                                               int closest=-1;
+                                                               float closestdist=-1;
+                                                               float distance;
+                                                               if(numplayers>1)
+                                                                       for(i=1;i<numplayers;i++){
+                                                                               distance=findDistancefast(&player[i].coords,&player[0].coords);
+                                                                               if(closestdist==-1||distance<closestdist){
+                                                                                       closestdist=distance;
+                                                                                       closest=i;
+                                                                               }
+                                                                       }
+
+                                                                       alldone=0;
+                                                                       startpoint=15;
+                                                                       j=startpoint;
+                                                                       while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                               mapname[j-startpoint]=consoletext[0][j];
+                                                                               j++;
+                                                                               if(consoletext[0][j]=='\0')alldone=1;
+                                                                       }
+                                                                       mapname[j-startpoint]='\0';
+
+                                                                       headprop=atof(mapname);
+
+                                                                       j++;
+                                                                       startpoint=j;
+                                                                       while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                               mapname[j-startpoint]=consoletext[0][j];
+                                                                               j++;
+                                                                               if(consoletext[0][j]=='\0')alldone=1;
+                                                                       }
+                                                                       mapname[j-startpoint]='\0';
+
+                                                                       bodyprop=atof(mapname);
+
+                                                                       j++;
+                                                                       startpoint=j;
+                                                                       while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                               mapname[j-startpoint]=consoletext[0][j];
+                                                                               j++;
+                                                                               if(consoletext[0][j]=='\0')alldone=1;
+                                                                       }
+                                                                       mapname[j-startpoint]='\0';
+
+                                                                       armprop=atof(mapname);
+
+                                                                       j++;
+                                                                       startpoint=j;
+                                                                       while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                               mapname[j-startpoint]=consoletext[0][j];
+                                                                               j++;
+                                                                               if(consoletext[0][j]=='\0')alldone=1;
+                                                                       }
+                                                                       mapname[j-startpoint]='\0';
+
+                                                                       legprop=atof(mapname);
+
+                                                                       if(player[closest].creature==wolftype){
+                                                                               player[closest].proportionhead=1.1*headprop;
+                                                                               player[closest].proportionbody=1.1*bodyprop;
+                                                                               player[closest].proportionarms=1.1*armprop;
+                                                                               player[closest].proportionlegs=1.1*legprop;
+                                                                       }
+
+                                                                       if(player[closest].creature==rabbittype){
+                                                                               player[closest].proportionhead=1.2*headprop;
+                                                                               player[closest].proportionbody=1.05*bodyprop;
+                                                                               player[closest].proportionarms=1.00*armprop;
+                                                                               player[closest].proportionlegs=1.1*legprop;
+                                                                               player[closest].proportionlegs.y=1.05*legprop;
+                                                                       }
+
+                                                                       donesomething=1;
+                                                       }
+
+
+                                                       if(Compare(consoletext[0],"sizemin ",0,7)||Compare(consoletext[0],"Sizemin ",0,7)){
+                                                               for(i=1;i<numplayers;i++){
+                                                                       if(player[i].scale<0.8*0.2)player[i].scale=0.8*0.2;
+                                                               }
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"tutorial ",0,8)||Compare(consoletext[0],"Tutorial ",0,8)){
+                                                               for(j=9;j<consolechars[0];j++){
+                                                                       mapname[j-9]=consoletext[0][j];
+                                                               }
+
+                                                               tutoriallevel=atoi(mapname);
+
+                                                               donesomething=1;
+                                                       }
+
+
+                                                       if(Compare(consoletext[0],"tintg ",0,5)||Compare(consoletext[0],"Tintg ",0,5)){
+                                                               for(j=6;j<consolechars[0];j++){
+                                                                       mapname[j-6]=consoletext[0][j];
+                                                               }
+
+                                                               tintg=atof(mapname);
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"tintb ",0,5)||Compare(consoletext[0],"Tintb ",0,5)){
+                                                               for(j=6;j<consolechars[0];j++){
+                                                                       mapname[j-6]=consoletext[0][j];
+                                                               }
+
+                                                               tintb=atof(mapname);
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"hostile ",0,7)){
+                                                               for(j=8;j<consolechars[0];j++){
+                                                                       mapname[j-8]=consoletext[0][j];
+                                                               }
+
+                                                               hostile=atoi(mapname);
+
+                                                               donesomething=1;
+                                                       }
+
+
+                                                       if(Compare(consoletext[0],"type active ",0,11)){
+                                                               editoractive=typeactive;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"indemo ",0,6)){
+                                                               indemo=1;
+                                                               hotspot[numhotspots]=player[0].coords;
+                                                               hotspotsize[numhotspots]=0;
+                                                               hotspottype[numhotspots]=-111;
+                                                               mapname[0]='\0';
+                                                               strcpy(hotspottext[numhotspots],"mapname");
+                                                               numhotspots++;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"notindemo ",0,9)){
+                                                               indemo=0;
+                                                               numhotspots--;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"type sitting ",0,12)){
+                                                               editoractive=typesitting;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"type sitting wall ",0,17)){
+                                                               editoractive=typesittingwall;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"type sleeping ",0,13)){
+                                                               editoractive=typesleeping;
+
+                                                               donesomething=1;
+                                                       }
+                                                       if(Compare(consoletext[0],"type dead1 ",0,10)){
+                                                               editoractive=typedead1;
+
+                                                               donesomething=1;
+                                                       }
+                                                       if(Compare(consoletext[0],"type dead2 ",0,10)){
+                                                               editoractive=typedead2;
+
+                                                               donesomething=1;
+                                                       }
+                                                       if(Compare(consoletext[0],"type dead3 ",0,10)){
+                                                               editoractive=typedead3;
+                                                               donesomething=1;
+                                                       }
+                                                       if(Compare(consoletext[0],"type dead4 ",0,10)){
+                                                               editoractive=typedead4;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"path keepwalking ",0,16)){
+                                                               editorpathtype=wpkeepwalking;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"path pause ",0,10)){
+                                                               editorpathtype=wppause;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"mapkilleveryone ",0,15)){
+                                                               maptype=mapkilleveryone;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"mapgosomewhere ",0,14)){
+                                                               maptype=mapgosomewhere;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"mapkillsomeone ",0,14)){
+                                                               maptype=mapkillsomeone;
+
+                                                               donesomething=1;
+
+                                                       }
+
+                                                       if(Compare(consoletext[0],"mapkillmost ",0,11)){
+                                                               maptype=mapkillmost;
+
+                                                               donesomething=1;
+
+                                                       }
+
+                                                       if(Compare(consoletext[0],"hs ",0,2)){
+                                                               int startpoint;
+                                                               int alldone;
+
+                                                               hotspot[numhotspots]=player[0].coords;
+
+                                                               alldone=0;
+                                                               startpoint=3;
+                                                               j=startpoint;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               hotspotsize[numhotspots]=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               hotspottype[numhotspots]=atoi(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\n';
+                                                               mapname[j-startpoint+1]='\0';
+
+                                                               strcpy(hotspottext[numhotspots],mapname);
+
+                                                               numhotspots++;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"dialogue ",0,8)){
+                                                               int startpoint;
+                                                               int alldone;
+
+                                                               alldone=0;
+                                                               startpoint=9;
+                                                               j=startpoint;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+                                                               startpoint=j+1;
+
+                                                               dialoguetype[numdialogues]=atoi(mapname);
+
+                                                               mapname[0]=':';
+                                                               mapname[1]='D';
+                                                               mapname[2]='a';
+                                                               mapname[3]='t';
+                                                               mapname[4]='a';
+                                                               mapname[5]=':';
+                                                               mapname[6]='D';
+                                                               mapname[7]='i';
+                                                               mapname[8]='a';
+                                                               mapname[9]='l';
+                                                               mapname[10]='o';
+                                                               mapname[11]='g';
+                                                               mapname[12]='u';
+                                                               mapname[13]='e';
+                                                               mapname[14]='s';
+                                                               mapname[15]=':';
+                                                               for(j=startpoint;j<consolechars[0];j++){
+                                                                       mapname[j-startpoint+16]=consoletext[0][j];
+                                                               }
+                                                               mapname[consolechars[0]-startpoint+16]='.';
+                                                               mapname[consolechars[0]-startpoint+17]='t';
+                                                               mapname[consolechars[0]-startpoint+18]='x';
+                                                               mapname[consolechars[0]-startpoint+19]='t';
+                                                               mapname[consolechars[0]-startpoint+20]='\0';
+
+                                                               for(j=0;j<max_dialoguelength;j++){
+                                                                       for(k=0;k<128;k++){
+                                                                               dialoguetext[numdialogues][j][k]='\0';
+                                                                       }
+                                                                       for(k=0;k<64;k++){
+                                                                               dialoguename[numdialogues][j][k]='\0';
+                                                                       }
+                                                               }
+
+                                                               ifstream ipstream(mapname);
+                                                               ipstream.ignore(256,':');
+                                                               ipstream >> numdialogueboxes[numdialogues];
+                                                               for(i=0;i<numdialogueboxes[numdialogues];i++){
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream.ignore(256,' ');
+                                                                       ipstream >> dialogueboxlocation[numdialogues][i];
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream >> dialogueboxcolor[numdialogues][i][0];
+                                                                       ipstream >> dialogueboxcolor[numdialogues][i][1];
+                                                                       ipstream >> dialogueboxcolor[numdialogues][i][2];
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream.getline(dialoguename[numdialogues][i],64);
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream.ignore(256,' ');
+                                                                       ipstream.getline(dialoguetext[numdialogues][i],128);
+                                                                       for(j=0;j<128;j++){
+                                                                               if(dialoguetext[numdialogues][i][j]=='\\')dialoguetext[numdialogues][i][j]='\n';
+                                                                       }
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream >> dialogueboxsound[numdialogues][i];
+                                                               }
+
+                                                               for(i=0;i<numdialogueboxes[numdialogues];i++){
+                                                                       for(j=0;j<numplayers;j++){
+                                                                               participantfacing[numdialogues][i][j]=player[j].facing;
+                                                                       }
+                                                               }
+                                                               ipstream.close();
+
+                                                               directing=1;
+                                                               indialogue=0;
+                                                               whichdialogue=numdialogues;
+
+
+                                                               numdialogues++;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"fixdialogue ",0,11)){
+                                                               int startpoint;
+                                                               int alldone;
+                                                               int whichdi;
+
+                                                               alldone=0;
+                                                               startpoint=12;
+                                                               j=startpoint;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+                                                               startpoint=j+1;
+
+                                                               whichdi=atoi(mapname);
+
+                                                               mapname[0]=':';
+                                                               mapname[1]='D';
+                                                               mapname[2]='a';
+                                                               mapname[3]='t';
+                                                               mapname[4]='a';
+                                                               mapname[5]=':';
+                                                               mapname[6]='D';
+                                                               mapname[7]='i';
+                                                               mapname[8]='a';
+                                                               mapname[9]='l';
+                                                               mapname[10]='o';
+                                                               mapname[11]='g';
+                                                               mapname[12]='u';
+                                                               mapname[13]='e';
+                                                               mapname[14]='s';
+                                                               mapname[15]=':';
+                                                               for(j=startpoint;j<consolechars[0];j++){
+                                                                       mapname[j-startpoint+16]=consoletext[0][j];
+                                                               }
+                                                               mapname[consolechars[0]-startpoint+16]='.';
+                                                               mapname[consolechars[0]-startpoint+17]='t';
+                                                               mapname[consolechars[0]-startpoint+18]='x';
+                                                               mapname[consolechars[0]-startpoint+19]='t';
+                                                               mapname[consolechars[0]-startpoint+20]='\0';
+
+                                                               for(j=0;j<max_dialoguelength;j++){
+                                                                       for(k=0;k<128;k++){
+                                                                               dialoguetext[whichdi][j][k]='\0';
+                                                                       }
+                                                                       for(k=0;k<64;k++){
+                                                                               dialoguename[whichdi][j][k]='\0';
+                                                                       }
+                                                               }
+
+                                                               ifstream ipstream(mapname);
+                                                               ipstream.ignore(256,':');
+                                                               ipstream >> numdialogueboxes[whichdi];
+                                                               for(i=0;i<numdialogueboxes[whichdi];i++){
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream.ignore(256,' ');
+                                                                       ipstream >> dialogueboxlocation[whichdi][i];
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream >> dialogueboxcolor[whichdi][i][0];
+                                                                       ipstream >> dialogueboxcolor[whichdi][i][1];
+                                                                       ipstream >> dialogueboxcolor[whichdi][i][2];
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream.getline(dialoguename[whichdi][i],64);
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream.ignore(256,' ');
+                                                                       ipstream.getline(dialoguetext[whichdi][i],128);
+                                                                       for(j=0;j<128;j++){
+                                                                               if(dialoguetext[whichdi][i][j]=='\\')dialoguetext[whichdi][i][j]='\n';
+                                                                       }
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream >> dialogueboxsound[whichdi][i];
+                                                               }
+
+                                                               ipstream.close();
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"fixtype ",0,7)){
+                                                               int startpoint;
+                                                               int alldone;
+                                                               int whichdi;
+
+                                                               alldone=0;
+                                                               startpoint=8;
+                                                               j=startpoint;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+                                                               dialoguetype[0]=atoi(mapname);
+
+                                                               startpoint=j+1;
+
+                                                               donesomething=1;
+                                                       }
+
+
+                                                       if(Compare(consoletext[0],"fixrotation ",0,11)){
+                                                               participantrotation[whichdialogue][participantfocus[whichdialogue][indialogue]]=player[participantfocus[whichdialogue][indialogue]].rotation;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"ddialogue ",0,9)){
+                                                               numdialogues--;
+                                                               if(numdialogues<0)numdialogues=0;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"immobile ",0,8)){
+                                                               player[0].immobile=1;
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"mobile ",0,6)){
+                                                               player[0].immobile=0;
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"play ",0,4)){
+                                                               int startpoint;
+                                                               int alldone;
+
+                                                               alldone=0;
+                                                               startpoint=5;
+                                                               j=startpoint;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+                                                               startpoint=j+1;
+
+                                                               whichdialogue=atoi(mapname);
+
+                                                               if(numdialogues>whichdialogue){
+                                                                       for(i=0;i<numdialogueboxes[whichdialogue];i++){
+                                                                               player[participantfocus[whichdialogue][i]].coords=participantlocation[whichdialogue][participantfocus[whichdialogue][i]];
+                                                                               player[participantfocus[whichdialogue][i]].rotation=participantrotation[whichdialogue][participantfocus[whichdialogue][i]];
+                                                                               player[participantfocus[whichdialogue][i]].targetrotation=participantrotation[whichdialogue][participantfocus[whichdialogue][i]];
+                                                                               player[participantfocus[whichdialogue][i]].velocity=0;
+                                                                               player[participantfocus[whichdialogue][i]].targetanimation=player[participantfocus[whichdialogue][i]].getIdle();
+                                                                               player[participantfocus[whichdialogue][i]].targetframe=0;
+                                                                       }
+
+                                                                       directing=0;
+                                                                       indialogue=0;
+
+                                                                       donesomething=1;
+
+                                                                       //if(dialogueboxsound[whichdialogue][indialogue]!=0){
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       XYZ temppos;
+                                                                       temppos=player[participantfocus[whichdialogue][indialogue]].coords;
+                                                                       temppos=temppos-viewer;
+                                                                       Normalise(&temppos);
+                                                                       temppos+=viewer;
+
+                                                                       gLoc[0]=temppos.x;
+                                                                       gLoc[1]=temppos.y;
+                                                                       gLoc[2]=temppos.z;
+                                                                       vel[0]=0;
+                                                                       vel[1]=0;
+                                                                       vel[2]=0;
+                                                                       int whichsoundplay;
+                                                                       whichsoundplay=rabbitchitter;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==2)whichsoundplay=rabbitchitter2;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==3)whichsoundplay=rabbitpainsound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==4)whichsoundplay=rabbitpain1sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==5)whichsoundplay=rabbitattacksound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==6)whichsoundplay=rabbitattack2sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==7)whichsoundplay=rabbitattack3sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==8)whichsoundplay=rabbitattack4sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==9)whichsoundplay=growlsound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==10)whichsoundplay=growl2sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==11)whichsoundplay=snarlsound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==12)whichsoundplay=snarl2sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==13)whichsoundplay=barksound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==14)whichsoundplay=bark2sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==15)whichsoundplay=bark3sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==16)whichsoundplay=barkgrowlsound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-1)whichsoundplay=fireendsound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-2)whichsoundplay=firestartsound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-3)whichsoundplay=consolesuccesssound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-4)whichsoundplay=consolefailsound;
+                                                                       PlaySoundEx( whichsoundplay, samp[whichsoundplay], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[whichsoundplay], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[whichsoundplay], 256);
+                                                                       FSOUND_SetPaused(channels[whichsoundplay], FALSE);
+                                                                       //}
+                                                               }
+                                                       }
+
+
+
+
+                                                       if(Compare(consoletext[0],"dhs ",0,3)){
+                                                               numhotspots--;
+                                                               if(numhotspots<0)numhotspots=0;
+                                                               donesomething=1;
+                                                       }
+
+
+                                                       if(Compare(consoletext[0],"proportion ",0,10)||Compare(consoletext[0],"Proportion ",0,4)){
+                                                               int startpoint;
+                                                               int alldone;
+
+                                                               alldone=0;
+                                                               startpoint=11;
+                                                               j=startpoint;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               headprop=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               bodyprop=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               armprop=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               legprop=atof(mapname);
+
+                                                               if(player[0].creature==wolftype){
+                                                                       player[0].proportionhead=1.1*headprop;
+                                                                       player[0].proportionbody=1.1*bodyprop;
+                                                                       player[0].proportionarms=1.1*armprop;
+                                                                       player[0].proportionlegs=1.1*legprop;
+                                                               }
+
+                                                               if(player[0].creature==rabbittype){
+                                                                       player[0].proportionhead=1.2*headprop;
+                                                                       player[0].proportionbody=1.05*bodyprop;
+                                                                       player[0].proportionarms=1.00*armprop;
+                                                                       player[0].proportionlegs=1.1*legprop;
+                                                                       player[0].proportionlegs.y=1.05*legprop;
+                                                               }
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"allimmobile ",0,11)||Compare(consoletext[0],"Allimmobile ",0,11)){
+                                                               for(i=0;i<numplayers;i++){
+                                                                       if(i>0)player[i].immobile=1;
+                                                               }
+                                                               donesomething=1;
+                                                       }
+
+
+                                                       if(Compare(consoletext[0],"default ",0,7)||Compare(consoletext[0],"Default ",0,7)){
+                                                               player[0].armorhead=1;
+                                                               player[0].armorhigh=1;
+                                                               player[0].armorlow=1;
+                                                               player[0].protectionhead=1;
+                                                               player[0].protectionhigh=1;
+                                                               player[0].protectionlow=1;
+                                                               player[0].metalhead=1;
+                                                               player[0].metalhigh=1;
+                                                               player[0].metallow=1;
+                                                               player[0].power=1;
+                                                               player[0].speedmult=1;
+                                                               player[0].scale=1;
+
+                                                               if(player[0].creature==wolftype){
+                                                                       player[0].proportionhead=1.1;
+                                                                       player[0].proportionbody=1.1;
+                                                                       player[0].proportionarms=1.1;
+                                                                       player[0].proportionlegs=1.1;
+                                                               }
+
+                                                               if(player[0].creature==rabbittype){
+                                                                       player[0].proportionhead=1.2;
+                                                                       player[0].proportionbody=1.05;
+                                                                       player[0].proportionarms=1.00;
+                                                                       player[0].proportionlegs=1.1;
+                                                                       player[0].proportionlegs.y=1.05;
+                                                               }
+
+                                                               player[0].numclothes=0;
+                                                               if(player[0].whichskin==0){
+                                                                       LoadTextureSave(":Data:Textures:Fur3.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               }
+                                                               else if(player[0].whichskin==1){
+                                                                       LoadTextureSave(":Data:Textures:Fur.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               }
+                                                               else if(player[0].whichskin==2){
+                                                                       LoadTextureSave(":Data:Textures:Fur2.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               }
+                                                               else if(player[0].whichskin==3){
+                                                                       LoadTextureSave(":Data:Textures:Lynx.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               }
+                                                               else if(player[0].whichskin==4){
+                                                                       LoadTextureSave(":Data:Textures:Otter.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               }
+                                                               else if(player[0].whichskin==5){
+                                                                       LoadTextureSave(":Data:Textures:Opal.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               }
+                                                               else if(player[0].whichskin==6){
+                                                                       LoadTextureSave(":Data:Textures:Sable.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               }
+                                                               else if(player[0].whichskin==7){
+                                                                       LoadTextureSave(":Data:Textures:Chocolate.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               }
+                                                               else if(player[0].whichskin==8){
+                                                                       LoadTextureSave(":Data:Textures:BW2.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               }
+                                                               else if(player[0].whichskin==9){
+                                                                       LoadTextureSave(":Data:Textures:WB2.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               }
+
+                                                               editoractive=typeactive;
+                                                               player[0].immobile=0;
+
+
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"tint ",0,4)||Compare(consoletext[0],"Tint ",0,4)){
+                                                               int startpoint;
+                                                               int alldone;
+                                                               alldone=0;
+                                                               startpoint=5;
+                                                               j=startpoint;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               tintr=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               tintg=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               tintb=atof(mapname);
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"sky tint ",0,8)||Compare(consoletext[0],"Sky Tint ",0,8)){
+                                                               int startpoint;
+                                                               int alldone;
+                                                               alldone=0;
+                                                               startpoint=9;
+                                                               j=startpoint;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               skyboxr=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               skyboxg=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               skyboxb=atof(mapname);
+
+                                                               skyboxlightr=skyboxr;
+                                                               skyboxlightg=skyboxg;
+                                                               skyboxlightb=skyboxb;
+
+                                                               SetUpLighting();
+
+                                                               //if(skyboxtexture){
+                                                               terrain.DoShadows();
+                                                               objects.DoShadows();
+                                                               /*}
+                                                               else terrain.DoLighting();
+                                                               */
+                                                               donesomething=1;
+                                                       } 
+
+                                                       if(Compare(consoletext[0],"sky light ",0,9)||Compare(consoletext[0],"Sky Light ",0,9)){
+                                                               int startpoint;
+                                                               int alldone;
+                                                               alldone=0;
+                                                               startpoint=10;
+                                                               j=startpoint;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               skyboxlightr=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               skyboxlightg=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               skyboxlightb=atof(mapname);
+
+                                                               SetUpLighting();
+
+                                                               //if(skyboxtexture){
+                                                               terrain.DoShadows();
+                                                               objects.DoShadows();
+                                                               /*}
+                                                               else terrain.DoLighting();
+                                                               */
+                                                               donesomething=1;
+                                                       } 
+
+                                                       if(Compare(consoletext[0],"skybox ",0,6)||Compare(consoletext[0],"Skybox ",0,6)){
+                                                               skyboxtexture=1-skyboxtexture;
+
+                                                               SetUpLighting();
+                                                               //if(skyboxtexture){
+                                                               terrain.DoShadows();
+                                                               objects.DoShadows();
+                                                               /*}
+                                                               else terrain.DoLighting();
+                                                               */
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"protection ",0,10)||Compare(consoletext[0],"Protection ",0,10)){
+                                                               int startpoint;
+                                                               int alldone;
+                                                               alldone=0;
+                                                               startpoint=11;
+                                                               j=startpoint;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               player[0].protectionhead=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               player[0].protectionhigh=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               player[0].protectionlow=atof(mapname);
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"armor ",0,5)||Compare(consoletext[0],"Armor ",0,5)){
+                                                               int startpoint;
+                                                               int alldone;
+                                                               alldone=0;
+                                                               startpoint=6;
+                                                               j=startpoint;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               player[0].armorhead=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               player[0].armorhigh=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               player[0].armorlow=atof(mapname);
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"protectionreset ",0,15)||Compare(consoletext[0],"Protectionreset ",0,15)){
+                                                               for(i=0;i<numplayers;i++){
+                                                                       player[i].protectionhead=1.0;
+                                                                       player[i].protectionhigh=1.0;
+                                                                       player[i].protectionlow=1.0;
+                                                                       player[i].armorhead=1.0;
+                                                                       player[i].armorhigh=1.0;
+                                                                       player[i].armorlow=1.0;
+                                                               }
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"protectionnear ",0,14)||Compare(consoletext[0],"Protectionnear ",0,14)){
+                                                               int closest=-1;
+                                                               float closestdist=-1;
+                                                               float distance;
+                                                               if(numplayers>1)
+                                                                       for(i=1;i<numplayers;i++){
+                                                                               distance=findDistancefast(&player[i].coords,&player[0].coords);
+                                                                               if(closestdist==-1||distance<closestdist){
+                                                                                       closestdist=distance;
+                                                                                       closest=i;
+                                                                               }
+                                                                       }
+
+                                                                       int startpoint;
+                                                                       int alldone;
+                                                                       alldone=0;
+                                                                       startpoint=15;
+                                                                       j=startpoint;
+                                                                       while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                               mapname[j-startpoint]=consoletext[0][j];
+                                                                               j++;
+                                                                               if(consoletext[0][j]=='\0')alldone=1;
+                                                                       }
+                                                                       mapname[j-startpoint]='\0';
+
+                                                                       player[closest].protectionhead=atof(mapname);
+
+                                                                       j++;
+                                                                       startpoint=j;
+                                                                       while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                               mapname[j-startpoint]=consoletext[0][j];
+                                                                               j++;
+                                                                               if(consoletext[0][j]=='\0')alldone=1;
+                                                                       }
+                                                                       mapname[j-startpoint]='\0';
+
+                                                                       player[closest].protectionhigh=atof(mapname);
+
+                                                                       j++;
+                                                                       startpoint=j;
+                                                                       while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                               mapname[j-startpoint]=consoletext[0][j];
+                                                                               j++;
+                                                                               if(consoletext[0][j]=='\0')alldone=1;
+                                                                       }
+                                                                       mapname[j-startpoint]='\0';
+
+                                                                       player[closest].protectionlow=atof(mapname);
+
+                                                                       donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"armornear ",0,9)||Compare(consoletext[0],"Armornear ",0,9)){
+                                                               int closest=-1;
+                                                               float closestdist=-1;
+                                                               float distance;
+                                                               if(numplayers>1)
+                                                                       for(i=1;i<numplayers;i++){
+                                                                               distance=findDistancefast(&player[i].coords,&player[0].coords);
+                                                                               if(closestdist==-1||distance<closestdist){
+                                                                                       closestdist=distance;
+                                                                                       closest=i;
+                                                                               }
+                                                                       }
+                                                                       int startpoint;
+                                                                       int alldone;
+                                                                       alldone=0;
+                                                                       startpoint=10;
+                                                                       j=startpoint;
+                                                                       while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                               mapname[j-startpoint]=consoletext[0][j];
+                                                                               j++;
+                                                                               if(consoletext[0][j]=='\0')alldone=1;
+                                                                       }
+                                                                       mapname[j-startpoint]='\0';
+
+                                                                       player[closest].armorhead=atof(mapname);
+
+                                                                       j++;
+                                                                       startpoint=j;
+                                                                       while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                               mapname[j-startpoint]=consoletext[0][j];
+                                                                               j++;
+                                                                               if(consoletext[0][j]=='\0')alldone=1;
+                                                                       }
+                                                                       mapname[j-startpoint]='\0';
+
+                                                                       player[closest].armorhigh=atof(mapname);
+
+                                                                       j++;
+                                                                       startpoint=j;
+                                                                       while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                               mapname[j-startpoint]=consoletext[0][j];
+                                                                               j++;
+                                                                               if(consoletext[0][j]=='\0')alldone=1;
+                                                                       }
+                                                                       mapname[j-startpoint]='\0';
+
+                                                                       player[closest].armorlow=atof(mapname);
+
+                                                                       donesomething=1;
+                                                       }
+
+
+                                                       if(Compare(consoletext[0],"metal ",0,5)||Compare(consoletext[0],"Metal ",0,5)){
+                                                               int startpoint;
+                                                               int alldone;
+                                                               alldone=0;
+                                                               startpoint=6;
+                                                               j=startpoint;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               player[0].metalhead=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+                                                               mapname[j-startpoint]='\0';
+
+                                                               player[0].metalhigh=atof(mapname);
+
+                                                               j++;
+                                                               startpoint=j;
+                                                               while(consoletext[0][j]!='\0'&&consoletext[0][j]!=' '&&!alldone&&j<255){
+                                                                       mapname[j-startpoint]=consoletext[0][j];
+                                                                       j++;
+                                                                       if(consoletext[0][j]=='\0')alldone=1;
+                                                               }
+
+                                                               mapname[j-startpoint]='\0';
+
+                                                               player[0].metallow=atof(mapname);
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"noclothesnear ",0,13)||Compare(consoletext[0],"Noclothesnear ",0,13)){
+                                                               int closest=-1;
+                                                               float closestdist=-1;
+                                                               float distance;
+                                                               if(numplayers>1)
+                                                                       for(i=1;i<numplayers;i++){
+                                                                               distance=findDistancefast(&player[i].coords,&player[0].coords);
+                                                                               if(closestdist==-1||distance<closestdist){
+                                                                                       closestdist=distance;
+                                                                                       closest=i;
+                                                                               }
+                                                                       }
+                                                                       player[closest].numclothes=0;
+                                                                       if(player[closest].whichskin==0){
+                                                                               LoadTextureSave(":Data:Textures:Fur3.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                       }
+                                                                       else if(player[closest].whichskin==1){
+                                                                               LoadTextureSave(":Data:Textures:Fur.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                       }
+                                                                       else if(player[closest].whichskin==2){
+                                                                               LoadTextureSave(":Data:Textures:Fur2.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                       }
+                                                                       else if(player[closest].whichskin==3){
+                                                                               LoadTextureSave(":Data:Textures:Lynx.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                       }
+                                                                       else if(player[closest].whichskin==4){
+                                                                               LoadTextureSave(":Data:Textures:Otter.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                       }
+                                                                       else if(player[closest].whichskin==5){
+                                                                               LoadTextureSave(":Data:Textures:Opal.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                       }
+                                                                       else if(player[closest].whichskin==6){
+                                                                               LoadTextureSave(":Data:Textures:Sable.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                       }
+                                                                       else if(player[closest].whichskin==7){
+                                                                               LoadTextureSave(":Data:Textures:Chocolate.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                       }
+                                                                       else if(player[closest].whichskin==8){
+                                                                               LoadTextureSave(":Data:Textures:BW2.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                       }
+                                                                       else if(player[closest].whichskin==9){
+                                                                               LoadTextureSave(":Data:Textures:WB2.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                       }
+
+                                                                       donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"noclothes ",0,9)||Compare(consoletext[0],"Noclothes ",0,9)){
+                                                               int closest=0;
+
+                                                               player[closest].numclothes=0;
+                                                               if(player[closest].whichskin==0){
+                                                                       LoadTextureSave(":Data:Textures:Fur3.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                               }
+                                                               else if(player[closest].whichskin==1){
+                                                                       LoadTextureSave(":Data:Textures:Fur.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                               }
+                                                               else if(player[closest].whichskin==2){
+                                                                       LoadTextureSave(":Data:Textures:Fur2.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                               }
+                                                               else if(player[closest].whichskin==3){
+                                                                       LoadTextureSave(":Data:Textures:Lynx.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                               }
+                                                               else if(player[closest].whichskin==4){
+                                                                       LoadTextureSave(":Data:Textures:Otter.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                               }
+                                                               else if(player[closest].whichskin==5){
+                                                                       LoadTextureSave(":Data:Textures:Opal.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                               }
+                                                               else if(player[closest].whichskin==6){
+                                                                       LoadTextureSave(":Data:Textures:Sable.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                               }
+                                                               else if(player[closest].whichskin==7){
+                                                                       LoadTextureSave(":Data:Textures:Chocolate.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                               }
+                                                               else if(player[closest].whichskin==8){
+                                                                       LoadTextureSave(":Data:Textures:BW2.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                               }
+                                                               else if(player[closest].whichskin==9){
+                                                                       LoadTextureSave(":Data:Textures:WB2.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                               }
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if((Compare(consoletext[0],"Clothes ",0,7)||Compare(consoletext[0],"clothes ",0,7))){
+                                                               mapname[0]=':';
+                                                               mapname[1]='D';
+                                                               mapname[2]='a';
+                                                               mapname[3]='t';
+                                                               mapname[4]='a';
+                                                               mapname[5]=':';
+                                                               mapname[6]='T';
+                                                               mapname[7]='e';
+                                                               mapname[8]='x';
+                                                               mapname[9]='t';
+                                                               mapname[10]='u';
+                                                               mapname[11]='r';
+                                                               mapname[12]='e';
+                                                               mapname[13]='s';
+                                                               mapname[14]=':';
+                                                               for(j=8;j<consolechars[0];j++){
+                                                                       mapname[j-8+15]=consoletext[0][j];
+                                                               }
+                                                               mapname[consolechars[0]-8+15]='.';
+                                                               mapname[consolechars[0]-8+16]='p';
+                                                               mapname[consolechars[0]-8+17]='n';
+                                                               mapname[consolechars[0]-8+18]='g';
+                                                               mapname[consolechars[0]-8+19]='\0';
+
+                                                               //:Data:Textures:Pants.png
+
+                                                               if(AddClothes((char *)mapname,0,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize)){
+                                                                       player[0].DoMipmaps(5,0,0,player[0].skeleton.skinsize,player[0].skeleton.skinsize);
+                                                                       strcpy(player[0].clothes[player[0].numclothes],mapname);
+                                                                       player[0].clothestintr[player[0].numclothes]=tintr;
+                                                                       player[0].clothestintg[player[0].numclothes]=tintg;
+                                                                       player[0].clothestintb[player[0].numclothes]=tintb;
+                                                                       player[0].numclothes++;
+                                                               }
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"belt ",0,4)||Compare(consoletext[0],"belt ",0,4)){
+                                                               player[0].skeleton.clothes = 1-player[0].skeleton.clothes;
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"Cellophane ",0,10)||Compare(consoletext[0],"cellophane ",0,10)){
+                                                               cellophane=1-cellophane;
+
+                                                               if(cellophane){
+                                                                       for(i=0;i<numplayers;i++){
+                                                                               player[i].proportionhead.z=0;
+                                                                               player[i].proportionbody.z=0;
+                                                                               player[i].proportionarms.z=0;
+                                                                               player[i].proportionlegs.z=0;
+                                                                       }
+                                                               }
+
+                                                               if(!cellophane){
+                                                                       for(i=0;i<numplayers;i++){
+                                                                               player[i].proportionhead.z=player[i].proportionhead.x;
+                                                                               player[i].proportionbody.z=player[i].proportionbody.x;
+                                                                               player[i].proportionarms.z=player[i].proportionarms.x;
+                                                                               player[i].proportionlegs.z=player[i].proportionlegs.x;
+                                                                       }
+                                                               }
+
+                                                               donesomething=1;
+                                                       }
+
+                                                       if((Compare(consoletext[0],"Clothesnear ",0,11)||Compare(consoletext[0],"clothesnear ",0,11))){
+                                                               mapname[0]=':';
+                                                               mapname[1]='D';
+                                                               mapname[2]='a';
+                                                               mapname[3]='t';
+                                                               mapname[4]='a';
+                                                               mapname[5]=':';
+                                                               mapname[6]='T';
+                                                               mapname[7]='e';
+                                                               mapname[8]='x';
+                                                               mapname[9]='t';
+                                                               mapname[10]='u';
+                                                               mapname[11]='r';
+                                                               mapname[12]='e';
+                                                               mapname[13]='s';
+                                                               mapname[14]=':';
+                                                               for(j=12;j<consolechars[0];j++){
+                                                                       mapname[j-12+15]=consoletext[0][j];
+                                                               }
+                                                               mapname[consolechars[0]-12+15]='.';
+                                                               mapname[consolechars[0]-12+16]='p';
+                                                               mapname[consolechars[0]-12+17]='n';
+                                                               mapname[consolechars[0]-12+18]='g';
+                                                               mapname[consolechars[0]-12+19]='\0';
+
+                                                               //:Data:Textures:Pants.png
+                                                               int closest=-1;
+                                                               float closestdist=-1;
+                                                               float distance;
+                                                               if(numplayers>1)
+                                                                       for(i=1;i<numplayers;i++){
+                                                                               distance=findDistancefast(&player[i].coords,&player[0].coords);
+                                                                               if(closestdist==-1||distance<closestdist){
+                                                                                       closestdist=distance;
+                                                                                       closest=i;
+                                                                               }
+                                                                       }
+
+                                                                       if(AddClothes((char *)mapname,0,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize)){
+                                                                               player[closest].DoMipmaps(5,0,0,player[closest].skeleton.skinsize,player[closest].skeleton.skinsize);
+                                                                               strcpy(player[closest].clothes[player[closest].numclothes],mapname);
+                                                                               player[closest].clothestintr[player[closest].numclothes]=tintr;
+                                                                               player[closest].clothestintg[player[closest].numclothes]=tintg;
+                                                                               player[closest].clothestintb[player[closest].numclothes]=tintb;
+                                                                               player[closest].numclothes++;
+                                                                       }
+
+                                                                       donesomething=1;
+                                                       }
+
+                                                       if(Compare(consoletext[0],"funnybunny ",0,10)||Compare(consoletext[0],"funny bunny ",0,11)){
+                                                               player[0].skeleton.id=0;
+                                                               player[0].skeleton.Load((char *)":Data:Skeleton:Basic Figure",(char *)":Data:Skeleton:Basic Figurelow",(char *)":Data:Skeleton:Rabbitbelt",(char *)":Data:Models:Body.solid",(char *)":Data:Models:Body2.solid",(char *)":Data:Models:Body3.solid",(char *)":Data:Models:Body4.solid",(char *)":Data:Models:Body5.solid",(char *)":Data:Models:Body6.solid",(char *)":Data:Models:Body7.solid",(char *)":Data:Models:Bodylow.solid",(char *)":Data:Models:Belt.solid",1);
+                                                               LoadTextureSave(":Data:Textures:fur3.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               player[0].creature=rabbittype;
+                                                               player[0].scale=.2;
+
+                                                               player[0].proportionhead=1.2;
+                                                               player[0].proportionbody=1.05;
+                                                               player[0].proportionarms=1.00;
+                                                               player[0].proportionlegs=1.1;
+                                                               player[0].proportionlegs.y=1.05;
+                                                               player[0].headless=0;
+
+                                                               player[0].damagetolerance=200;
+
+                                                               donesomething=1;
+                                                       }
+                                                       if(Compare(consoletext[0],"wolfieisgod ",0,11)||Compare(consoletext[0],"wolfie is god ",0,12)){
+                                                               player[0].skeleton.id=0;
+                                                               player[0].skeleton.Load((char *)":Data:Skeleton:Basic Figure Wolf",(char *)":Data:Skeleton:Basic Figure Wolf Low",(char *)":Data:Skeleton:Rabbitbelt",(char *)":Data:Models:Wolf.solid",(char *)":Data:Models:Wolf2.solid",(char *)":Data:Models:Wolf3.solid",(char *)":Data:Models:Wolf4.solid",(char *)":Data:Models:Wolf5.solid",(char *)":Data:Models:Wolf6.solid",(char *)":Data:Models:Wolf7.solid",(char *)":Data:Models:Wolflow.solid",(char *)":Data:Models:Belt.solid",0);
+                                                               LoadTextureSave(":Data:Textures:Wolf.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               player[0].creature=wolftype;
+
+                                                               player[0].proportionhead=1.1;
+                                                               player[0].proportionbody=1.1;
+                                                               player[0].proportionarms=1.1;
+                                                               player[0].proportionlegs=1.1;
+                                                               player[0].proportionlegs.y=1.1;
+                                                               player[0].scale=.23;
+
+                                                               player[0].damagetolerance=300;
+
+                                                               donesomething=1;
+                                                       }
+                                                       /*if(Compare(consoletext[0],"kungfu ",0,6)||Compare(consoletext[0],"kung fu ",0,7)){
+                                                       LoadTextureSave(":Data:Textures:Kungfu.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                       donesomething=1;
+                                                       }
+                                                       if(Compare(consoletext[0],"rambo ",0,5)){
+                                                       LoadTextureSave(":Data:Textures:Leather.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                       donesomething=1;
+                                                       }
+                                                       if(Compare(consoletext[0],"david ",0,5)){
+                                                       LoadTextureSave(":Data:Textures:David.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                       donesomething=1;
+                                                       }*/
+                                                       if(Compare(consoletext[0],"wolf ",0,4)){
+                                                               LoadTextureSave(":Data:Textures:Wolf.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               donesomething=1;
+                                                       }
+                                                       if(Compare(consoletext[0],"darkwolf ",0,8)){
+                                                               LoadTextureSave(":Data:Textures:DarkWolf.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               donesomething=1;
+                                                       }
+                                                       if(Compare(consoletext[0],"snowwolf ",0,8)){
+                                                               LoadTextureSave(":Data:Textures:Snowwolf.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               donesomething=1;
+                                                       }/*
+                                                        if(Compare(consoletext[0],"lizardwolf ",0,10)){
+                                                        LoadTextureSave(":Data:Textures:Lizardwolf.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                        donesomething=1;
+                                                        }*/
+                                                       if(Compare(consoletext[0],"white ",0,5)){
+                                                               LoadTextureSave(":Data:Textures:fur.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               donesomething=1;
+                                                       }
+                                                       if(Compare(consoletext[0],"brown ",0,5)){
+                                                               LoadTextureSave(":Data:Textures:fur3.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               donesomething=1;
+                                                       }
+                                                       if(Compare(consoletext[0],"black ",0,5)){
+                                                               LoadTextureSave(":Data:Textures:fur2.jpg",&player[0].skeleton.drawmodel.textureptr,1,&player[0].skeleton.skinText[0],&player[0].skeleton.skinsize);
+                                                               donesomething=1;
+                                                       }
+                                                       if(consolechars[0]>0){
+                                                               for(k=14;k>=1;k--){
+                                                                       for(j=0;j<255;j++){
+                                                                               consoletext[k][j]=consoletext[k-1][j];
+                                                                       }
+                                                                       consolechars[k]=consolechars[k-1];
+                                                               }
+                                                               for(j=0;j<255;j++){
+                                                                       consoletext[0][j]=' ';
+                                                               }
+                                                               consolechars[0]=0;
+                                                               consoleselected=0;
+
+                                                               if(!donesomething){
+                                                                       PlaySoundEx( consolefailsound, samp[consolefailsound], NULL, TRUE);
+                                                                       FSOUND_SetVolume(channels[consolefailsound], 256);
+                                                                       FSOUND_SetPaused(channels[consolefailsound], FALSE);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       togglekey[i]=1;
+                               }
+                               else {
+                                       togglekey[i]=0;
+                                       togglekeydelay[i]=0;
+                               }
+                       }
+
+                       consoleblinkdelay-=multiplier;
+                       if(consoleblinkdelay<=0){
+                               consoleblinkdelay=.3;
+                               consoleblink=1-consoleblink;
+                       }
+               }
+
+               if(IsKeyDown(theKeyMap, MAC_Q_KEY)&&IsKeyDown(theKeyMap, MAC_COMMAND_KEY)){
+                       tryquit=1;
+                       if(mainmenu==3){
+                               if(newdetail>2)newdetail=detail;
+                               if(newdetail<0)newdetail=detail;
+                               if(newscreenwidth>3000)newscreenwidth=screenwidth;
+                               if(newscreenwidth<0)newscreenwidth=screenwidth;
+                               if(newscreenheight>3000)newscreenheight=screenheight;
+                               if(newscreenheight<0)newscreenheight=screenheight;
+
+                               //ofstream opstream(":Data:config.txt"); 
+                               ofstream opstream("./Data/config.txt"); 
+                               opstream << "Screenwidth:\n";
+                               opstream << newscreenwidth;
+                               opstream << "\nScreenheight:\n";
+                               opstream << newscreenheight;
+                               opstream << "\nMouse sensitivity:\n";
+                               opstream << usermousesensitivity;
+                               opstream << "\nBlur(0,1):\n";
+                               opstream << ismotionblur;
+                               opstream << "\nOverall Detail(0,1,2) higher=better:\n";
+                               opstream << newdetail;
+                               opstream << "\nFloating jump:\n";
+                               opstream << floatjump;
+                               opstream << "\nMouse jump:\n";
+                               opstream << mousejump;
+                               opstream << "\nAmbient sound:\n";
+                               opstream << ambientsound;
+                               opstream << "\nBlood (0,1,2):\n";
+                               opstream << bloodtoggle;
+                               opstream << "\nAuto slomo:\n";
+                               opstream << autoslomo;
+                               opstream << "\nFoliage:\n";
+                               opstream << foliage;
+                               opstream << "\nMusic:\n";
+                               opstream << musictoggle;
+                               opstream << "\nTrilinear:\n";
+                               opstream << trilinear;
+                               opstream << "\nDecals(shadows,blood puddles,etc):\n";
+                               opstream << decals;
+                               opstream << "\nInvert mouse:\n";
+                               opstream << invertmouse;
+                               opstream << "\nGamespeed:\n";
+                               if(oldgamespeed==0)oldgamespeed=1;
+                               opstream << oldgamespeed;
+                               opstream << "\nDifficulty(0,1,2) higher=harder:\n";
+                               opstream << difficulty;
+                               opstream << "\nDamage effects(blackout, doublevision):\n";
+                               opstream << damageeffects;
+                               opstream << "\nText:\n";
+                               opstream << texttoggle;
+                               opstream << "\nDebug:\n";
+                               opstream << debugmode;
+                               opstream << "\nVBL Sync:\n";
+                               opstream << vblsync;
+                               opstream << "\nShow Points:\n";
+                               opstream << showpoints;
+                               opstream << "\nAlways Blur:\n";
+                               opstream << alwaysblur;
+                               opstream << "\nImmediate mode (turn on on G5):\n";
+                               opstream << immediate;
+                               opstream << "\nVelocity blur:\n";
+                               opstream << velocityblur;
+                           opstream << "\nVolume:\n";
+                       opstream << volume;
+                               opstream << "\nForward key:\n";
+                               opstream << KeyToChar(forwardkey);
+                               opstream << "\nBack key:\n";
+                               opstream << KeyToChar(backkey);
+                               opstream << "\nLeft key:\n";
+                               opstream << KeyToChar(leftkey);
+                               opstream << "\nRight key:\n";
+                               opstream << KeyToChar(rightkey);
+                               opstream << "\nJump key:\n";
+                               opstream << KeyToChar(jumpkey);
+                               opstream << "\nCrouch key:\n";
+                               opstream << KeyToChar(crouchkey);
+                               opstream << "\nDraw key:\n";
+                               opstream << KeyToChar(drawkey);
+                               opstream << "\nThrow key:\n";
+                               opstream << KeyToChar(throwkey);
+                               opstream << "\nAttack key:\n";
+                               opstream << KeyToChar(attackkey);
+                               opstream << "\nChat key:\n";
+                               opstream << KeyToChar(chatkey);
+                               opstream.close();
+                       }
+               }
+
+               static int oldwinfreeze;
+               if(winfreeze&&!oldwinfreeze){
+                       FSOUND_SetFrequency(FSOUND_ALL, 0.001);
+                       PlaySoundEx( consolesuccesssound, samp[consolesuccesssound], NULL, TRUE);
+                       FSOUND_SetVolume(channels[consolesuccesssound], 256);
+                       FSOUND_SetPaused(channels[consolesuccesssound], FALSE);
+               }
+               if(winfreeze==0)oldwinfreeze=winfreeze;
+               else oldwinfreeze++;
+
+               if((IsKeyDown(theKeyMap, jumpkey)||IsKeyDown(theKeyMap, MAC_SPACE_KEY))&&!oldjumpkeydown&&!campaign){
+                       if(winfreeze)winfreeze=0;
+                       oldjumpkeydown=1;
+               }
+               if((IsKeyDown(theKeyMap, MAC_ESCAPE_KEY))&&!campaign&&gameon){
+                       if(winfreeze){
+                               mainmenu=9;
+                               gameon=0;
+                       }
+               }
+               if((IsKeyDown(theKeyMap, jumpkey)||IsKeyDown(theKeyMap, MAC_SPACE_KEY))){
+                       oldjumpkeydown=1;
+               }
+               if(!IsKeyDown(theKeyMap, jumpkey)&&!IsKeyDown(theKeyMap, MAC_SPACE_KEY))oldjumpkeydown=0;
+
+               if(!freeze&&!winfreeze&&!(mainmenu&&gameon)&&(gameon||!gamestarted)){
+
+                       static bool oldbuttondialogue;
+
+                       if(indialogue!=-1)talkdelay=1;
+                       talkdelay-=multiplier;
+
+                       if(talkdelay<=0)
+                               if(indialogue==-1&&(animation[player[0].targetanimation].height!=highheight)/*&&!hostile*/)
+                                       for(i=0;i<numdialogues;i++){
+                                               int realdialoguetype;
+                                               bool special;
+                                               if(dialoguetype[i]>49){
+                                                       realdialoguetype=dialoguetype[i]-50; 
+                                                       special=1;
+                                               }
+                                               else if(dialoguetype[i]>39){
+                                                       realdialoguetype=dialoguetype[i]-40; 
+                                                       special=1;
+                                               }
+                                               else if(dialoguetype[i]>29){
+                                                       realdialoguetype=dialoguetype[i]-30; 
+                                                       special=1;
+                                               }
+                                               else if(dialoguetype[i]>19){
+                                                       realdialoguetype=dialoguetype[i]-20; 
+                                                       special=1;
+                                               }
+                                               else if(dialoguetype[i]>9){
+                                                       realdialoguetype=dialoguetype[i]-10; 
+                                                       special=1;
+                                               }
+                                               else {
+                                                       realdialoguetype=dialoguetype[i];
+                                                       special=0;
+                                               }
+                                               if((!hostile||(dialoguetype[i]>40&&dialoguetype[i]<50))&&realdialoguetype<numplayers&&realdialoguetype>0&&(dialoguegonethrough[i]==0||!special)&&(special||(IsKeyDown(theKeyMap, attackkey)&&!oldbuttondialogue))){
+                                                       if(findDistancefast(&player[0].coords,&player[realdialoguetype].coords)<6||player[realdialoguetype].howactive>=typedead1||(dialoguetype[i]>40&&dialoguetype[i]<50)){
+                                                               whichdialogue=i;
+                                                               for(j=0;j<numdialogueboxes[whichdialogue];j++){
+                                                                       player[participantfocus[whichdialogue][j]].coords=participantlocation[whichdialogue][participantfocus[whichdialogue][j]];
+                                                                       player[participantfocus[whichdialogue][j]].rotation=participantrotation[whichdialogue][participantfocus[whichdialogue][j]];
+                                                                       player[participantfocus[whichdialogue][j]].targetrotation=participantrotation[whichdialogue][participantfocus[whichdialogue][j]];
+                                                                       player[participantfocus[whichdialogue][j]].velocity=0;
+                                                                       player[participantfocus[whichdialogue][j]].targetanimation=player[participantfocus[whichdialogue][j]].getIdle();
+                                                                       player[participantfocus[whichdialogue][j]].targetframe=0;
+                                                               }
+                                                               directing=0;
+                                                               indialogue=0;
+                                                               dialoguetime=0;
+                                                               dialoguegonethrough[i]++;
+                                                               if(dialogueboxsound[whichdialogue][indialogue]!=0){
+                                                                       static float gLoc[3];
+                                                                       static float vel[3];
+                                                                       XYZ temppos;
+                                                                       temppos=player[participantfocus[whichdialogue][indialogue]].coords;
+                                                                       temppos=temppos-viewer;
+                                                                       Normalise(&temppos);
+                                                                       temppos+=viewer;
+
+                                                                       gLoc[0]=temppos.x;
+                                                                       gLoc[1]=temppos.y;
+                                                                       gLoc[2]=temppos.z;vel[0]=0;
+                                                                       vel[1]=0;
+                                                                       vel[2]=0;
+                                                                       int whichsoundplay;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==1)whichsoundplay=rabbitchitter;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==2)whichsoundplay=rabbitchitter2;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==3)whichsoundplay=rabbitpainsound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==4)whichsoundplay=rabbitpain1sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==5)whichsoundplay=rabbitattacksound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==6)whichsoundplay=rabbitattack2sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==7)whichsoundplay=rabbitattack3sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==8)whichsoundplay=rabbitattack4sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==9)whichsoundplay=growlsound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==10)whichsoundplay=growl2sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==11)whichsoundplay=snarlsound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==12)whichsoundplay=snarl2sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==13)whichsoundplay=barksound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==14)whichsoundplay=bark2sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==15)whichsoundplay=bark3sound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==16)whichsoundplay=barkgrowlsound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-1)whichsoundplay=fireendsound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-2)whichsoundplay=firestartsound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-3)whichsoundplay=consolesuccesssound;
+                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-4)whichsoundplay=consolefailsound;
+                                                                       PlaySoundEx( whichsoundplay, samp[whichsoundplay], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[whichsoundplay], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[whichsoundplay], 256);
+                                                                       FSOUND_SetPaused(channels[whichsoundplay], FALSE);
+                                                               }
+                                                               if(IsKeyDown(theKeyMap, attackkey))oldbuttondialogue=1;
+                                                       }
+                                               }
+                                       }
+
+                                       windvar+=multiplier;
+                                       smoketex+=multiplier;
+                                       tutorialstagetime+=multiplier;
+
+                                       static float hotspotvisual[40];
+                                       if(numhotspots){
+                                               XYZ hotspotsprite;
+                                               if(editorenabled)
+                                                       for(i=0;i<numhotspots;i++)
+                                                               hotspotvisual[i]-=multiplier/320;
+
+                                               for(i=0;i<numhotspots;i++){
+                                                       //if(hotspottype[i]<=10)
+                                                       while(hotspotvisual[i]<0){
+                                                               hotspotsprite=0;
+                                                               hotspotsprite.x=float(abs(Random()%100000))/100000*hotspotsize[i];
+                                                               hotspotsprite=DoRotation(hotspotsprite,0,0,Random()%360);
+                                                               hotspotsprite=DoRotation(hotspotsprite,0,Random()%360,0);
+                                                               hotspotsprite+=hotspot[i];
+                                                               sprites.MakeSprite(breathsprite, hotspotsprite, hotspotsprite*0, 1,0.5,0, 7, 0.4);
+                                                               hotspotvisual[i]+=0.1/hotspotsize[i]/hotspotsize[i]/hotspotsize[i];
+                                                       }                               
+                                               }
+
+                                               for(i=0;i<numhotspots;i++){
+                                                       if(hotspottype[i]<=10&&hotspottype[i]>0){
+                                                               hotspot[i]=player[hotspottype[i]].coords;
+                                                       }
+                                               }
+                                       }
+
+                                       //Tutorial
+                                       if(tutoriallevel&&tutorialstagetime>tutorialmaxtime){
+                                               tutorialstage++;
+                                               tutorialsuccess=0;
+                                               if(tutorialstage<=1){
+                                                       canattack=0;
+                                                       cananger=0;
+                                                       reversaltrain=0;
+                                               }
+                                               if(tutorialstage==1){
+                                                       tutorialmaxtime=5;
+                                               }
+                                               if(tutorialstage==2){
+                                                       tutorialmaxtime=2;
+                                               }
+                                               if(tutorialstage==3){
+                                                       tutorialmaxtime=600;
+                                               }
+                                               if(tutorialstage==4){
+                                                       tutorialmaxtime=1000;
+                                               }
+                                               if(tutorialstage==5){
+                                                       tutorialmaxtime=600;
+                                               }
+                                               if(tutorialstage==6){
+                                                       tutorialmaxtime=600;
+                                               }
+                                               if(tutorialstage==7){
+                                                       tutorialmaxtime=600;
+                                               }
+                                               if(tutorialstage==8){
+                                                       tutorialmaxtime=600;
+                                               }
+                                               if(tutorialstage==9){
+                                                       tutorialmaxtime=600;
+                                               }
+                                               if(tutorialstage==10){
+                                                       tutorialmaxtime=2;
+                                               }
+                                               if(tutorialstage==11){
+                                                       tutorialmaxtime=1000;
+                                               }
+                                               if(tutorialstage==12){
+                                                       tutorialmaxtime=1000;
+                                               }
+                                               if(tutorialstage==13){
+                                                       tutorialmaxtime=2;
+                                               }
+                                               if(tutorialstage==14){
+                                                       tutorialmaxtime=3;
+
+                                                       XYZ temp,temp2;
+
+                                                       temp.x=1011;
+                                                       temp.y=84;
+                                                       temp.z=491;
+                                                       temp2.x=1025;
+                                                       temp2.y=75;
+                                                       temp2.z=447;
+
+                                                       player[1].coords=(temp+temp2)/2;
+
+                                                       float gLoc[3];
+                                                       float vel[3];
+                                                       gLoc[0]=player[1].coords.x;
+                                                       gLoc[1]=player[1].coords.y;
+                                                       gLoc[2]=player[1].coords.z;
+                                                       vel[0]=0;
+                                                       vel[1]=0;
+                                                       vel[2]=0;
+                                                       PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[fireendsound], 256);
+                                                       FSOUND_SetPaused(channels[fireendsound], FALSE);
+
+                                                       for(i=0;i<player[1].skeleton.num_joints;i++){
+                                                               if(Random()%2==0){
+                                                                       if(!player[1].skeleton.free)temp2=(player[1].coords-player[1].oldcoords)/multiplier/2;//velocity/2;
+                                                                       if(player[1].skeleton.free)temp2=player[1].skeleton.joints[i].velocity*player[1].scale/2;
+                                                                       if(!player[1].skeleton.free)temp=DoRotation(DoRotation(DoRotation(player[1].skeleton.joints[i].position,0,0,player[1].tilt),player[1].tilt2,0,0),0,player[1].rotation,0)*player[1].scale+player[1].coords;
+                                                                       if(player[1].skeleton.free)temp=player[1].skeleton.joints[i].position*player[1].scale+player[1].coords;
+                                                                       sprites.MakeSprite(breathsprite, temp,temp2, 1,1,1, .6+(float)abs(Random()%100)/200-.25, 1);
+                                                               }
+                                                       }
+
+                                               }
+                                               if(tutorialstage==15){
+                                                       tutorialmaxtime=500;
+                                               }
+                                               if(tutorialstage==16){
+                                                       tutorialmaxtime=500;
+                                               }
+                                               if(tutorialstage==17){
+                                                       tutorialmaxtime=500;
+                                               }
+                                               if(tutorialstage==18){
+                                                       tutorialmaxtime=500;
+                                               }
+                                               if(tutorialstage==19){
+                                                       tutorialstage=20;
+                                                       //tutorialmaxtime=500;
+                                               }
+                                               if(tutorialstage==20){
+                                                       tutorialmaxtime=500;
+                                               }
+                                               if(tutorialstage==21){
+                                                       tutorialmaxtime=500;
+                                                       if(bonus==cannon){
+                                                               bonus=Slicebonus;
+                                                               againbonus=1;
+                                                       }
+                                                       else againbonus=0;
+                                               }
+                                               if(tutorialstage==22){
+                                                       tutorialmaxtime=500;
+                                               }
+                                               if(tutorialstage==23){
+                                                       tutorialmaxtime=500;
+                                               }
+                                               if(tutorialstage==24){
+                                                       tutorialmaxtime=500;
+                                               }
+                                               if(tutorialstage==25){
+                                                       tutorialmaxtime=500;
+                                               }
+                                               if(tutorialstage==26){
+                                                       tutorialmaxtime=2;
+                                               }
+                                               if(tutorialstage==27){
+                                                       tutorialmaxtime=4;
+                                                       reversaltrain=1;
+                                                       cananger=1;
+                                                       player[1].aitype=attacktypecutoff;
+                                               }
+                                               if(tutorialstage==28){
+                                                       tutorialmaxtime=400;
+                                               }
+                                               if(tutorialstage==29){
+                                                       tutorialmaxtime=400;
+                                                       player[0].escapednum=0;
+                                               }
+                                               if(tutorialstage==30){
+                                                       tutorialmaxtime=4;
+                                                       reversaltrain=0;
+                                                       cananger=0;
+                                                       player[1].aitype=passivetype;
+                                               }
+                                               if(tutorialstage==31){
+                                                       tutorialmaxtime=13;
+                                               }
+                                               if(tutorialstage==32){
+                                                       tutorialmaxtime=8;
+                                               }
+                                               if(tutorialstage==33){
+                                                       tutorialmaxtime=400;
+                                                       cananger=1;
+                                                       canattack=1;
+                                                       player[1].aitype=attacktypecutoff;
+                                               }
+                                               if(tutorialstage==34){
+                                                       tutorialmaxtime=400;
+                                               }
+                                               if(tutorialstage==35){
+                                                       tutorialmaxtime=400;
+                                               }
+                                               if(tutorialstage==36){
+                                                       tutorialmaxtime=2;
+                                                       reversaltrain=0;
+                                                       cananger=0;
+                                                       player[1].aitype=passivetype;
+                                               }
+                                               if(tutorialstage==37){
+                                                       damagedealt=0;
+                                                       damagetaken=0;
+                                                       tutorialmaxtime=50;
+                                                       cananger=1;
+                                                       canattack=1;
+                                                       player[1].aitype=attacktypecutoff;
+                                               }
+                                               if(tutorialstage==38){
+                                                       tutorialmaxtime=4;
+                                                       canattack=0;
+                                                       cananger=0;
+                                                       player[1].aitype=passivetype;
+                                               }
+                                               if(tutorialstage==39){
+                                                       XYZ temp,temp2;
+
+                                                       temp.x=1011;
+                                                       temp.y=84;
+                                                       temp.z=491;
+                                                       temp2.x=1025;
+                                                       temp2.y=75;
+                                                       temp2.z=447;
+
+
+                                                       weapons.owner[weapons.numweapons]=-1;
+                                                       weapons.type[weapons.numweapons]=knife;
+                                                       weapons.damage[weapons.numweapons]=0;
+                                                       weapons.mass[weapons.numweapons]=1;
+                                                       weapons.tipmass[weapons.numweapons]=1.2;
+                                                       weapons.length[weapons.numweapons]=.25;
+                                                       weapons.position[weapons.numweapons]=(temp+temp2)/2;
+                                                       weapons.tippoint[weapons.numweapons]=(temp+temp2)/2;
+
+                                                       weapons.velocity[weapons.numweapons]=0.1;
+                                                       weapons.tipvelocity[weapons.numweapons]=0.1;
+                                                       weapons.missed[weapons.numweapons]=1;
+                                                       weapons.hitsomething[weapons.numweapons]=0;
+                                                       weapons.freetime[weapons.numweapons]=0;
+                                                       weapons.firstfree[weapons.numweapons]=1;
+                                                       weapons.physics[weapons.numweapons]=1;
+
+                                                       weapons.numweapons++;
+                                               }
+                                               if(tutorialstage==40){
+                                                       tutorialmaxtime=300;
+                                               }
+                                               if(tutorialstage==41){
+                                                       tutorialmaxtime=300;
+                                               }
+                                               if(tutorialstage==42){
+                                                       tutorialmaxtime=8;
+                                               }
+                                               if(tutorialstage==43){
+                                                       tutorialmaxtime=300;
+                                               }
+                                               if(tutorialstage==44){
+                                                       weapons.owner[0]=1;
+                                                       player[0].weaponactive=-1;
+                                                       player[0].num_weapons=0;
+                                                       player[1].weaponactive=0;
+                                                       player[1].num_weapons=1;
+                                                       player[1].weaponids[0]=0;
+
+                                                       cananger=1;
+                                                       canattack=1;
+                                                       player[1].aitype=attacktypecutoff;
+
+                                                       tutorialmaxtime=300;
+                                               }
+                                               if(tutorialstage==45){
+                                                       weapons.owner[0]=1;
+                                                       player[0].weaponactive=-1;
+                                                       player[0].num_weapons=0;
+                                                       player[1].weaponactive=0;
+                                                       player[1].num_weapons=1;
+                                                       player[1].weaponids[0]=0;
+
+                                                       tutorialmaxtime=300;
+                                               }
+                                               if(tutorialstage==46){
+                                                       weapons.owner[0]=1;
+                                                       player[0].weaponactive=-1;
+                                                       player[0].num_weapons=0;
+                                                       player[1].weaponactive=0;
+                                                       player[1].num_weapons=1;
+                                                       player[1].weaponids[0]=0;
+
+                                                       weapons.type[0]=sword;
+
+                                                       tutorialmaxtime=300;
+                                               }
+
+                                               if(tutorialstage==47){
+                                                       tutorialmaxtime=10;
+
+                                                       XYZ temp,temp2;
+
+                                                       temp.x=1011;
+                                                       temp.y=84;
+                                                       temp.z=491;
+                                                       temp2.x=1025;
+                                                       temp2.y=75;
+                                                       temp2.z=447;
+
+                                                       weapons.owner[weapons.numweapons]=-1;
+                                                       weapons.type[weapons.numweapons]=sword;
+                                                       weapons.damage[weapons.numweapons]=0;
+                                                       weapons.mass[weapons.numweapons]=1;
+                                                       weapons.tipmass[weapons.numweapons]=1.2;
+                                                       weapons.length[weapons.numweapons]=.25;
+                                                       weapons.position[weapons.numweapons]=(temp+temp2)/2;
+                                                       weapons.tippoint[weapons.numweapons]=(temp+temp2)/2;
+
+                                                       weapons.velocity[weapons.numweapons]=0.1;
+                                                       weapons.tipvelocity[weapons.numweapons]=0.1;
+                                                       weapons.missed[weapons.numweapons]=1;
+                                                       weapons.hitsomething[weapons.numweapons]=0;
+                                                       weapons.freetime[weapons.numweapons]=0;
+                                                       weapons.firstfree[weapons.numweapons]=1;
+                                                       weapons.physics[weapons.numweapons]=1;
+
+                                                       weapons.owner[0]=1;
+                                                       weapons.owner[1]=0;
+                                                       player[0].weaponactive=0;
+                                                       player[0].num_weapons=1;
+                                                       player[0].weaponids[0]=1;       
+                                                       player[1].weaponactive=0;
+                                                       player[1].num_weapons=1;
+                                                       player[1].weaponids[0]=0;       
+
+                                                       weapons.numweapons++;
+                                               }
+                                               if(tutorialstage==48){
+                                                       canattack=0;
+                                                       cananger=0;
+                                                       player[1].aitype=passivetype;
+
+                                                       tutorialmaxtime=15;
+
+                                                       weapons.owner[0]=1;
+                                                       weapons.owner[1]=0;
+                                                       player[0].weaponactive=0;
+                                                       player[0].num_weapons=1;
+                                                       player[0].weaponids[0]=1;       
+                                                       player[1].weaponactive=0;
+                                                       player[1].num_weapons=1;
+                                                       player[1].weaponids[0]=0;
+
+                                                       if(player[0].weaponactive!=-1)weapons.type[player[0].weaponids[player[0].weaponactive]]=staff;
+                                                       else weapons.type[0]=staff;
+
+                                                       weapons.numweapons++;
+                                               }
+                                               if(tutorialstage==49){
+                                                       canattack=0;
+                                                       cananger=0;
+                                                       player[1].aitype=passivetype;
+
+                                                       tutorialmaxtime=200;
+
+                                                       weapons.position[1]=1000;
+                                                       weapons.tippoint[1]=1000;
+
+                                                       weapons.numweapons=1;
+                                                       weapons.owner[0]=0;
+                                                       player[1].weaponactive=-1;
+                                                       player[1].num_weapons=0;
+                                                       player[0].weaponactive=0;
+                                                       player[0].num_weapons=1;
+                                                       player[0].weaponids[0]=0;       
+
+                                                       weapons.type[0]=knife;
+
+                                                       weapons.numweapons++;
+                                               }
+                                               if(tutorialstage==50){
+                                                       tutorialmaxtime=8;
+
+                                                       XYZ temp,temp2;
+                                                       float gLoc[3];
+                                                       float vel[3];
+                                                       gLoc[0]=player[1].coords.x;
+                                                       gLoc[1]=player[1].coords.y;
+                                                       gLoc[2]=player[1].coords.z;
+                                                       vel[0]=0;
+                                                       vel[1]=0;
+                                                       vel[2]=0;
+                                                       PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[fireendsound], 256);
+                                                       FSOUND_SetPaused(channels[fireendsound], FALSE);
+
+                                                       for(i=0;i<player[1].skeleton.num_joints;i++){
+                                                               if(Random()%2==0){
+                                                                       if(!player[1].skeleton.free)temp2=(player[1].coords-player[1].oldcoords)/multiplier/2;//velocity/2;
+                                                                       if(player[1].skeleton.free)temp2=player[1].skeleton.joints[i].velocity*player[1].scale/2;
+                                                                       if(!player[1].skeleton.free)temp=DoRotation(DoRotation(DoRotation(player[1].skeleton.joints[i].position,0,0,player[1].tilt),player[1].tilt2,0,0),0,player[1].rotation,0)*player[1].scale+player[1].coords;
+                                                                       if(player[1].skeleton.free)temp=player[1].skeleton.joints[i].position*player[1].scale+player[1].coords;
+                                                                       sprites.MakeSprite(breathsprite, temp,temp2, 1,1,1, .6+(float)abs(Random()%100)/200-.25, 1);
+                                                               }
+                                                       }
+
+                                                       player[1].num_weapons=0;
+                                                       player[1].weaponstuck=-1;
+                                                       player[1].weaponactive=-1;
+
+                                                       weapons.numweapons=0;
+
+                                                       weapons.owner[0]=-1;
+                                                       weapons.velocity[0]=0.1;
+                                                       weapons.tipvelocity[0]=-0.1;
+                                                       weapons.missed[0]=1;
+                                                       weapons.hitsomething[0]=0;
+                                                       weapons.freetime[0]=0;
+                                                       weapons.firstfree[0]=1;
+                                                       weapons.physics[0]=1;
+                                               }
+                                               if(tutorialstage==51){
+                                                       tutorialmaxtime=80000;
+                                               }
+                                               if(tutorialstage<=51)tutorialstagetime=0;
+                                       }
+
+                                       //Tutorial success
+                                       if(tutoriallevel&&tutorialstagetime<tutorialmaxtime-3){
+                                               if(tutorialstage==3){
+                                                       if(deltah||deltav)tutorialsuccess+=multiplier;
+                                               }
+                                               if(tutorialstage==4){
+                                                       if(player[0].forwardkeydown||player[0].backkeydown||player[0].leftkeydown||player[0].rightkeydown)tutorialsuccess+=multiplier;
+                                               }
+                                               if(tutorialstage==5){
+                                                       if(player[0].jumpkeydown)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==6){
+                                                       if(player[0].isCrouch())tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==7){
+                                                       if(player[0].targetanimation==rollanim)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==8){
+                                                       if(player[0].targetanimation==sneakanim)tutorialsuccess+=multiplier;
+                                               }
+                                               if(tutorialstage==9){
+                                                       if(player[0].targetanimation==rabbitrunninganim||player[0].targetanimation==wolfrunninganim)tutorialsuccess+=multiplier;
+                                               }
+                                               if(tutorialstage==11){
+                                                       if(player[0].isWallJump())tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==12){
+                                                       if(player[0].targetanimation==flipanim)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==15){
+                                                       if(player[0].targetanimation==upunchanim||player[0].targetanimation==winduppunchanim)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==16){
+                                                       if(player[0].targetanimation==winduppunchanim)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==17){
+                                                       if(player[0].targetanimation==spinkickanim)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==18){
+                                                       if(player[0].targetanimation==sweepanim)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==19){
+                                                       if(player[0].targetanimation==dropkickanim)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==20){
+                                                       if(player[0].targetanimation==rabbitkickanim)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==21){
+                                                       if(bonus==cannon)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==22){
+                                                       if(bonus==spinecrusher)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==23){
+                                                       if(player[0].targetanimation==walljumprightkickanim||player[0].targetanimation==walljumpleftkickanim)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==24){
+                                                       if(player[0].targetanimation==rabbittacklinganim)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==25){
+                                                       if(player[0].targetanimation==backhandspringanim)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==28){
+                                                       if(animation[player[0].targetanimation].attack==reversed&&player[0].feint)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==29){
+                                                       if(player[0].escapednum==2){
+                                                               tutorialsuccess=1;
+                                                               reversaltrain=0;
+                                                               cananger=0;
+                                                               player[1].aitype=passivetype;
+                                                       }
+                                               }
+                                               if(tutorialstage==33){
+                                                       if(animation[player[0].targetanimation].attack==reversal)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==34){
+                                                       if(animation[player[0].targetanimation].attack==reversal)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==35){
+                                                       if(animation[player[0].targetanimation].attack==reversal){
+                                                               tutorialsuccess=1;
+                                                               reversaltrain=0;
+                                                               cananger=0;
+                                                               player[1].aitype=passivetype;
+                                                       }
+                                               }
+                                               if(tutorialstage==40){
+                                                       if(player[0].num_weapons>0)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==41){
+                                                       if(player[0].weaponactive==-1&&player[0].num_weapons>0)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==43){
+                                                       if(player[0].targetanimation==knifeslashstartanim)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==44){
+                                                       if(animation[player[0].targetanimation].attack==reversal)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==45){
+                                                       if(animation[player[0].targetanimation].attack==reversal)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==46){
+                                                       if(animation[player[0].targetanimation].attack==reversal)tutorialsuccess=1;
+                                               }
+                                               if(tutorialstage==49){
+                                                       if(player[1].weaponstuck!=-1)tutorialsuccess=1;
+                                               }
+                                               if(tutorialsuccess>=1)tutorialstagetime=tutorialmaxtime-3;
+
+
+                                               if(tutorialstagetime==tutorialmaxtime-3){
+                                                       PlaySoundEx( consolesuccesssound, samp[consolesuccesssound], NULL, TRUE);
+                                                       FSOUND_SetVolume(channels[consolesuccesssound], 256);
+                                                       FSOUND_SetPaused(channels[consolesuccesssound], FALSE);
+                                               }
+
+                                               if(tutorialsuccess>=1){
+                                                       if(tutorialstage==34||tutorialstage==35)
+                                                               tutorialstagetime=tutorialmaxtime-1;
+                                               }
+                                       }
+
+                                       if(tutoriallevel){
+                                               if(tutorialstage<14||tutorialstage>=50){
+                                                       player[1].coords.y=300;
+                                                       player[1].velocity=0;
+                                               }
+                                       }
+
+                                       if(tutoriallevel!=1){
+                                               if(bonustime==0&&bonus!=solidhit&&bonus!=spinecrusher&&bonus!=tracheotomy&&bonus!=backstab&&bonusvalue>10){
+                                                       PlaySoundEx( consolesuccesssound, samp[consolesuccesssound], NULL, TRUE);
+                                                       FSOUND_SetVolume(channels[consolesuccesssound], 256);
+                                                       FSOUND_SetPaused(channels[consolesuccesssound], FALSE);
+                                               }
+                                       }
+                                       else
+                                               if(bonustime==0){
+                                                       PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                                                       FSOUND_SetVolume(channels[fireendsound], 256);
+                                                       FSOUND_SetPaused(channels[fireendsound], FALSE);
+                                               }
+                                               if(bonustime==0){
+                                                       if(bonus!=solidhit&&bonus!=twoxcombo&&bonus!=threexcombo&&bonus!=fourxcombo&&bonus!=megacombo)bonusnum[bonus]++;
+                                                       else bonusnum[bonus]+=0.15;
+                                                       if(tutoriallevel)bonusvalue=0;
+                                                       bonusvalue/=bonusnum[bonus];
+                                                       bonustotal+=bonusvalue;
+                                               }
+                                               bonustime+=multiplier;
+
+                                               if(environment==snowyenvironment){
+                                                       precipdelay-=multiplier;
+                                                       while(precipdelay<0){
+                                                               precipdelay+=.04;
+                                                               if(!detail)precipdelay+=.04;
+                                                               XYZ footvel,footpoint;
+
+                                                               footvel=0;
+                                                               footpoint=viewer+viewerfacing*6;
+                                                               footpoint.y+=((float)abs(Random()%1200))/100-6;
+                                                               footpoint.x+=((float)abs(Random()%1200))/100-6;
+                                                               footpoint.z+=((float)abs(Random()%1200))/100-6;
+                                                               sprites.MakeSprite(snowsprite, footpoint,footvel, 1,1,1, .1, 1);
+                                                       }
+                                               }
+                                               for(k=0;k<numplayers;k++){
+                                                       if(player[k].aitype==playercontrolled)player[k].turnspeed=500;
+                                                       if(player[k].aitype!=playercontrolled)player[k].turnspeed=500;
+
+                                                       if((player[k].isRun()&&((player[k].targetrotation!=rabbitrunninganim&&player[k].targetrotation!=wolfrunninganim)||player[k].targetframe==4))||player[k].targetanimation==removeknifeanim||player[k].targetanimation==crouchremoveknifeanim||player[k].targetanimation==flipanim||player[k].targetanimation==fightsidestep||player[k].targetanimation==walkanim){
+                                                               if(abs(player[k].rotation-player[k].targetrotation)<multiplier*player[k].turnspeed)player[k].rotation=player[k].targetrotation;
+                                                               else if(player[k].rotation>player[k].targetrotation){
+                                                                       player[k].rotation-=multiplier*player[k].turnspeed;
+                                                               }
+                                                               else if(player[k].rotation<player[k].targetrotation){
+                                                                       player[k].rotation+=multiplier*player[k].turnspeed;
+                                                               }
+                                                       }
+
+
+                                                       if(player[k].isStop()||player[k].isLanding()||player[k].targetanimation==staggerbackhighanim||(player[k].targetanimation==sneakanim&&player[k].currentanimation==sneakanim)||player[k].targetanimation==staggerbackhardanim||player[k].targetanimation==backhandspringanim||player[k].targetanimation==dodgebackanim||player[k].targetanimation==rollanim||(animation[player[k].targetanimation].attack&&player[k].targetanimation!=rabbitkickanim&&(player[k].targetanimation!=crouchstabanim||player[k].hasvictim)&&(player[k].targetanimation!=swordgroundstabanim||player[k].hasvictim))){
+                                                               player[k].turnspeed*=2;
+                                                               if(abs(player[k].rotation-player[k].targetrotation)<multiplier*player[k].turnspeed)player[k].rotation=player[k].targetrotation;
+                                                               else if(player[k].rotation>player[k].targetrotation){
+                                                                       player[k].rotation-=multiplier*player[k].turnspeed;
+                                                               }
+                                                               else if(player[k].rotation<player[k].targetrotation){
+                                                                       player[k].rotation+=multiplier*player[k].turnspeed;
+                                                               }
+                                                               player[k].turnspeed/=2;
+                                                       }
+
+                                                       if(player[k].targetanimation==sneakanim&&player[k].currentanimation!=sneakanim){
+                                                               player[k].turnspeed*=4;
+                                                               if(abs(player[k].rotation-player[k].targetrotation)<multiplier*player[k].turnspeed)player[k].rotation=player[k].targetrotation;
+                                                               else if(player[k].rotation>player[k].targetrotation){
+                                                                       player[k].rotation-=multiplier*player[k].turnspeed;
+                                                               }
+                                                               else if(player[k].rotation<player[k].targetrotation){
+                                                                       player[k].rotation+=multiplier*player[k].turnspeed;
+                                                               }
+                                                               player[k].turnspeed/=4;
+                                                       }
+
+                                                       /*if(player[k].aitype!=passivetype||(findDistancefast(&player[k].coords,&viewer)<viewdistance*viewdistance))*/  player[k].DoStuff();
+                                                       if(player[k].immobile&&k!=0)player[k].coords=player[k].realoldcoords;
+
+                                                       if(findDistancefast(&player[k].coords,&player[k].realoldcoords)>0){
+                                                               if(!player[k].skeleton.free&&player[k].targetanimation!=climbanim&&player[k].targetanimation!=hanganim){
+                                                                       bool tempcollide=0;
+
+                                                                       if(player[k].collide<-.3)player[k].collide=-.3;
+                                                                       if(player[k].collide>1)player[k].collide=1;
+                                                                       player[k].collide-=multiplier*30;
+
+                                                                       if(player[k].coords.y<terrain.getHeight(player[k].coords.x,player[k].coords.z)){
+                                                                               player[k].coords.y=terrain.getHeight(player[k].coords.x,player[k].coords.z);
+                                                                       }
+                                                                       if(terrain.patchobjectnum[player[k].whichpatchx][player[k].whichpatchz])
+                                                                               for(l=0;l<terrain.patchobjectnum[player[k].whichpatchx][player[k].whichpatchz];l++){
+                                                                                       i=terrain.patchobjects[player[k].whichpatchx][player[k].whichpatchz][l];
+                                                                                       if(objects.type[i]!=rocktype||(((objects.scale[i]>.5&&player[k].aitype==playercontrolled)||objects.position[i].y>player[k].coords.y))){
+                                                                                               lowpoint=player[k].coords;
+                                                                                               if(player[k].targetanimation!=jumpupanim&&player[k].targetanimation!=jumpdownanim&&!player[k].isFlip())lowpoint.y+=1.25;
+                                                                                               else lowpoint.y+=1.3;
+                                                                                               if(player[k].coords.y<terrain.getHeight(player[k].coords.x,player[k].coords.z)&&player[k].coords.y>terrain.getHeight(player[k].coords.x,player[k].coords.z)-.1){
+                                                                                                       player[k].coords.y=terrain.getHeight(player[k].coords.x,player[k].coords.z);
+                                                                                               }
+                                                                                               /*while(player[k].coords.y<terrain.getHeight(player[k].coords.x,player[k].coords.z))
+                                                                                               player[k].coords+=terrain.getNormal(player[k].coords.x,player[k].coords.z)/50;
+                                                                                               */
+                                                                                               if(player[k].SphereCheck(&lowpoint, 1.3, &colpoint, &objects.position[i], &objects.rotation[i], &objects.model[i])!=-1){
+                                                                                                       flatfacing=lowpoint-player[k].coords;
+                                                                                                       player[k].coords=lowpoint;
+                                                                                                       player[k].coords.y-=1.3;
+                                                                                                       player[k].collide=1;
+                                                                                                       tempcollide=1;
+                                                                                                       if(player[k].aitype==playercontrolled&&(player[k].targetanimation==jumpupanim||player[k].targetanimation==jumpdownanim||player[k].isFlip())&&!player[k].jumptogglekeydown&&player[k].jumpkeydown){
+                                                                                                               lowpointtarget=lowpoint+DoRotation(player[k].facing,0,-90,0)*1.5;
+                                                                                                               tempcoords1=lowpoint;
+                                                                                                               whichhit=objects.model[i].LineCheck(&lowpoint,&lowpointtarget,&colpoint,&objects.position[i],&objects.rotation[i]);
+                                                                                                               if(whichhit!=-1&&abs(objects.model[i].facenormals[whichhit].y)<.3){
+                                                                                                                       player[k].target=0;
+                                                                                                                       player[k].targetanimation=walljumpleftanim;
+                                                                                                                       player[k].targetframe=0;
+                                                                                                                       float gLoc[3];
+                                                                                                                       float vel[3];
+                                                                                                                       gLoc[0]=player[k].coords.x;
+                                                                                                                       gLoc[1]=player[k].coords.y;
+                                                                                                                       gLoc[2]=player[k].coords.z;
+                                                                                                                       vel[0]=0;
+                                                                                                                       vel[1]=0;
+                                                                                                                       vel[2]=0;
+                                                                                                                       PlaySoundEx( movewhooshsound, samp[movewhooshsound], NULL, TRUE);
+                                                                                                                       FSOUND_3D_SetAttributes(channels[movewhooshsound], gLoc, vel);
+                                                                                                                       FSOUND_SetVolume(channels[movewhooshsound], 256);
+                                                                                                                       FSOUND_SetPaused(channels[movewhooshsound], FALSE);
+                                                                                                                       if(k==0)FSOUND_SetPaused(channels[whooshsound], TRUE);
+
+                                                                                                                       lowpointtarget=DoRotation(objects.model[i].facenormals[whichhit],0,objects.rotation[i],0);
+                                                                                                                       player[k].rotation=-asin(0-lowpointtarget.x);
+                                                                                                                       player[k].rotation*=360/6.28;
+                                                                                                                       if(lowpointtarget.z<0)player[k].rotation=180-player[k].rotation;
+                                                                                                                       player[k].targetrotation=player[k].rotation;
+                                                                                                                       player[k].lowrotation=player[k].rotation;
+                                                                                                                       if(k==0)numwallflipped++;
+                                                                                                               }
+                                                                                                               else
+                                                                                                               {
+                                                                                                                       lowpoint=tempcoords1;
+                                                                                                                       lowpointtarget=lowpoint+DoRotation(player[k].facing,0,90,0)*1.5;
+                                                                                                                       whichhit=objects.model[i].LineCheck(&lowpoint,&lowpointtarget,&colpoint,&objects.position[i],&objects.rotation[i]);
+                                                                                                                       if(whichhit!=-1&&abs(objects.model[i].facenormals[whichhit].y)<.3){
+                                                                                                                               player[k].target=0;
+                                                                                                                               player[k].targetanimation=walljumprightanim;
+                                                                                                                               player[k].targetframe=0;
+                                                                                                                               float gLoc[3];
+                                                                                                                               float vel[3];
+                                                                                                                               gLoc[0]=player[k].coords.x;
+                                                                                                                               gLoc[1]=player[k].coords.y;
+                                                                                                                               gLoc[2]=player[k].coords.z;
+                                                                                                                               vel[0]=0;
+                                                                                                                               vel[1]=0;
+                                                                                                                               vel[2]=0;
+                                                                                                                               PlaySoundEx( movewhooshsound, samp[movewhooshsound], NULL, TRUE);
+                                                                                                                               FSOUND_3D_SetAttributes(channels[movewhooshsound], gLoc, vel);
+                                                                                                                               FSOUND_SetVolume(channels[movewhooshsound], 256);
+                                                                                                                               FSOUND_SetPaused(channels[movewhooshsound], FALSE);
+                                                                                                                               if(k==0)FSOUND_SetPaused(channels[whooshsound], TRUE);
+
+                                                                                                                               lowpointtarget=DoRotation(objects.model[i].facenormals[whichhit],0,objects.rotation[i],0);
+                                                                                                                               player[k].rotation=-asin(0-lowpointtarget.x);
+                                                                                                                               player[k].rotation*=360/6.28;
+                                                                                                                               if(lowpointtarget.z<0)player[k].rotation=180-player[k].rotation;
+                                                                                                                               player[k].targetrotation=player[k].rotation;
+                                                                                                                               player[k].lowrotation=player[k].rotation;
+                                                                                                                               if(k==0)numwallflipped++;
+                                                                                                                       }
+                                                                                                                       else
+                                                                                                                       {
+                                                                                                                               lowpoint=tempcoords1;
+                                                                                                                               lowpointtarget=lowpoint+player[k].facing*2;
+                                                                                                                               whichhit=objects.model[i].LineCheck(&lowpoint,&lowpointtarget,&colpoint,&objects.position[i],&objects.rotation[i]);
+                                                                                                                               if(whichhit!=-1&&abs(objects.model[i].facenormals[whichhit].y)<.3){
+                                                                                                                                       player[k].target=0;
+                                                                                                                                       player[k].targetanimation=walljumpbackanim;
+                                                                                                                                       player[k].targetframe=0;
+                                                                                                                                       float gLoc[3];
+                                                                                                                                       float vel[3];
+                                                                                                                                       gLoc[0]=player[k].coords.x;
+                                                                                                                                       gLoc[1]=player[k].coords.y;
+                                                                                                                                       gLoc[2]=player[k].coords.z;
+                                                                                                                                       vel[0]=0;
+                                                                                                                                       vel[1]=0;
+                                                                                                                                       vel[2]=0;
+                                                                                                                                       PlaySoundEx( movewhooshsound, samp[movewhooshsound], NULL, TRUE);
+                                                                                                                                       FSOUND_3D_SetAttributes(channels[movewhooshsound], gLoc, vel);
+                                                                                                                                       FSOUND_SetVolume(channels[movewhooshsound], 256);
+                                                                                                                                       FSOUND_SetPaused(channels[movewhooshsound], FALSE);
+                                                                                                                                       if(k==0)FSOUND_SetPaused(channels[whooshsound], TRUE);
+
+                                                                                                                                       lowpointtarget=DoRotation(objects.model[i].facenormals[whichhit],0,objects.rotation[i],0);
+                                                                                                                                       player[k].rotation=-asin(0-lowpointtarget.x);
+                                                                                                                                       player[k].rotation*=360/6.28;
+                                                                                                                                       if(lowpointtarget.z<0)player[k].rotation=180-player[k].rotation;
+                                                                                                                                       player[k].targetrotation=player[k].rotation;
+                                                                                                                                       player[k].lowrotation=player[k].rotation;
+                                                                                                                                       if(k==0)numwallflipped++;
+                                                                                                                               }
+                                                                                                                               else
+                                                                                                                               {
+                                                                                                                                       lowpoint=tempcoords1;
+                                                                                                                                       lowpointtarget=lowpoint-player[k].facing*2;
+                                                                                                                                       whichhit=objects.model[i].LineCheck(&lowpoint,&lowpointtarget,&colpoint,&objects.position[i],&objects.rotation[i]);
+                                                                                                                                       if(whichhit!=-1&&abs(objects.model[i].facenormals[whichhit].y)<.3){
+                                                                                                                                               player[k].target=0;
+                                                                                                                                               player[k].targetanimation=walljumpfrontanim;
+                                                                                                                                               player[k].targetframe=0;
+                                                                                                                                               float gLoc[3];
+                                                                                                                                               float vel[3];
+                                                                                                                                               gLoc[0]=player[k].coords.x;
+                                                                                                                                               gLoc[1]=player[k].coords.y;
+                                                                                                                                               gLoc[2]=player[k].coords.z;
+                                                                                                                                               vel[0]=0;
+                                                                                                                                               vel[1]=0;
+                                                                                                                                               vel[2]=0;
+                                                                                                                                               PlaySoundEx( movewhooshsound, samp[movewhooshsound], NULL, TRUE);
+                                                                                                                                               FSOUND_3D_SetAttributes(channels[movewhooshsound], gLoc, vel);
+                                                                                                                                               FSOUND_SetVolume(channels[movewhooshsound], 256);
+                                                                                                                                               FSOUND_SetPaused(channels[movewhooshsound], FALSE);
+                                                                                                                                               if(k==0)FSOUND_SetPaused(channels[whooshsound], TRUE);
+
+                                                                                                                                               lowpointtarget=DoRotation(objects.model[i].facenormals[whichhit],0,objects.rotation[i],0);
+                                                                                                                                               player[k].rotation=-asin(0-lowpointtarget.x);
+                                                                                                                                               player[k].rotation*=360/6.28;
+                                                                                                                                               if(lowpointtarget.z<0)player[k].rotation=180-player[k].rotation;
+                                                                                                                                               player[k].rotation+=180;
+                                                                                                                                               player[k].targetrotation=player[k].rotation;
+                                                                                                                                               player[k].lowrotation=player[k].rotation;
+                                                                                                                                               if(k==0)numwallflipped++;
+                                                                                                                                       }
+                                                                                                                               }
+                                                                                                                       }
+                                                                                                               }
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+                                                                                       else if(objects.type[i]==rocktype){
+                                                                                               lowpoint2=player[k].coords;
+                                                                                               lowpoint=player[k].coords;
+                                                                                               lowpoint.y+=2;
+                                                                                               if(objects.model[i].LineCheck(&lowpoint,&lowpoint2,&colpoint,&objects.position[i],&objects.rotation[i])!=-1){
+                                                                                                       player[k].coords=colpoint;
+                                                                                                       player[k].collide=1;
+                                                                                                       tempcollide=1;
+
+                                                                                                       if((player[k].targetanimation==jumpdownanim||player[k].isFlip())){
+                                                                                                               if(player[k].isFlip()&&animation[player[k].targetanimation].label[player[k].targetframe]==7)player[k].RagDoll(0);
+
+                                                                                                               if(player[k].targetanimation==jumpupanim){player[k].jumppower=-4;player[k].targetanimation=player[k].getIdle();}
+                                                                                                               player[k].target=0;
+                                                                                                               player[k].targetframe=0;        
+                                                                                                               player[k].onterrain=1;
+
+                                                                                                               if(player[k].id==0){
+                                                                                                                       FSOUND_SetPaused(channels[whooshsound], TRUE);
+                                                                                                                       FSOUND_SetVolume(channels[whooshsound], 0);
+                                                                                                               }
+
+                                                                                                               if((player[k].targetanimation==jumpdownanim||player[k].isFlip())&&!player[k].wasLanding()){
+                                                                                                                       if(player[k].isFlip())player[k].jumppower=-4;
+                                                                                                                       player[k].targetanimation=player[k].getLanding();
+                                                                                                                       float gLoc[3];
+                                                                                                                       float vel[3];
+                                                                                                                       gLoc[0]=player[k].coords.x;
+                                                                                                                       gLoc[1]=player[k].coords.y;
+                                                                                                                       gLoc[2]=player[k].coords.z;
+                                                                                                                       vel[0]=player[k].velocity.x;
+                                                                                                                       vel[1]=player[k].velocity.y;
+                                                                                                                       vel[2]=player[k].velocity.z;
+                                                                                                                       PlaySoundEx( landsound, samp[landsound], NULL, TRUE);
+                                                                                                                       FSOUND_3D_SetAttributes(channels[landsound], gLoc, vel);
+                                                                                                                       FSOUND_SetVolume(channels[landsound], 128);
+                                                                                                                       FSOUND_SetPaused(channels[landsound], FALSE);
+                                                                                                                       if(k==0){
+                                                                                                                               envsound[numenvsounds]=player[k].coords;
+                                                                                                                               envsoundvol[numenvsounds]=16;
+                                                                                                                               envsoundlife[numenvsounds]=.4;
+                                                                                                                               numenvsounds++;
+                                                                                                                       }
+
+                                                                                                               }
+                                                                                                       }
+                                                                                               }                               
+                                                                                       }
+                                                                               }
+                                                                               if(tempcollide&&terrain.patchobjectnum[player[k].whichpatchx][player[k].whichpatchz]&&(/*player[k].jumptogglekeydown*/1==1||player[k].aitype!=playercontrolled))
+                                                                                       for(l=0;l<terrain.patchobjectnum[player[k].whichpatchx][player[k].whichpatchz];l++){
+                                                                                               i=terrain.patchobjects[player[k].whichpatchx][player[k].whichpatchz][l];
+                                                                                               lowpoint=player[k].coords;
+                                                                                               lowpoint.y+=1.35;
+                                                                                               if(objects.type[i]!=rocktype)
+                                                                                                       if(player[k].SphereCheck(&lowpoint, 1.33, &colpoint, &objects.position[i], &objects.rotation[i], &objects.model[i])!=-1){
+                                                                                                               if(player[k].targetanimation!=jumpupanim&&player[k].targetanimation!=jumpdownanim&&player[k].onterrain)player[k].avoidcollided=1;               
+                                                                                                               player[k].coords=lowpoint;
+                                                                                                               player[k].coords.y-=1.35;
+                                                                                                               player[k].collide=1;    
+
+                                                                                                               if((player[k].grabdelay<=0||player[k].aitype!=playercontrolled)&&((/*(player[k].isRun()||player[k].targetanimation==sneakanim||player[k].targetanimation==walkanim)&&*/player[k].currentanimation!=climbanim&&player[k].currentanimation!=hanganim&&!player[k].isWallJump())||player[k].targetanimation==jumpupanim||player[k].targetanimation==jumpdownanim)){
+                                                                                                                       lowpoint=player[k].coords;
+                                                                                                                       objects.model[i].SphereCheckPossible(&lowpoint, 1.5, &objects.position[i], &objects.rotation[i]);
+                                                                                                                       lowpoint=player[k].coords;
+                                                                                                                       lowpoint.y+=.05;
+                                                                                                                       facing=0;
+                                                                                                                       facing.z=-1;
+                                                                                                                       facing=DoRotation(facing,0,player[k].targetrotation+180,0);
+                                                                                                                       lowpointtarget=lowpoint+facing*1.4;
+                                                                                                                       whichhit=objects.model[i].LineCheckPossible(&lowpoint,&lowpointtarget,&colpoint,&objects.position[i],&objects.rotation[i]);
+                                                                                                                       if(whichhit!=-1){
+                                                                                                                               lowpoint=player[k].coords;
+                                                                                                                               lowpoint.y+=.1;
+                                                                                                                               lowpointtarget=lowpoint+facing*1.4;
+                                                                                                                               lowpoint2=lowpoint;
+                                                                                                                               lowpointtarget2=lowpointtarget;
+                                                                                                                               lowpoint3=lowpoint;
+                                                                                                                               lowpointtarget3=lowpointtarget;
+                                                                                                                               lowpoint4=lowpoint;
+                                                                                                                               lowpointtarget4=lowpointtarget;
+                                                                                                                               lowpoint5=lowpoint;
+                                                                                                                               lowpointtarget5=lowpointtarget;
+                                                                                                                               lowpoint6=lowpoint;
+                                                                                                                               lowpointtarget6=lowpointtarget;
+                                                                                                                               lowpoint7=lowpoint;
+                                                                                                                               lowpointtarget7=lowpoint;
+                                                                                                                               lowpoint2.x+=.1;
+                                                                                                                               lowpointtarget2.x+=.1;
+                                                                                                                               lowpoint3.z+=.1;
+                                                                                                                               lowpointtarget3.z+=.1;
+                                                                                                                               lowpoint4.x-=.1;
+                                                                                                                               lowpointtarget4.x-=.1;
+                                                                                                                               lowpoint5.z-=.1;
+                                                                                                                               lowpointtarget5.z-=.1;
+                                                                                                                               lowpoint6.y+=45/13;
+                                                                                                                               lowpointtarget6.y+=45/13;
+                                                                                                                               lowpointtarget6+=facing*.6;
+                                                                                                                               lowpointtarget7.y+=90/13;
+                                                                                                                               whichhit=objects.model[i].LineCheckPossible(&lowpoint,&lowpointtarget,&colpoint,&objects.position[i],&objects.rotation[i]);
+                                                                                                                               if(objects.friction[i]>.5)
+                                                                                                                                       if(whichhit!=-1){
+                                                                                                                                               //if(k==0){
+                                                                                                                                               if(whichhit!=-1)if(player[k].targetanimation!=jumpupanim&&player[k].targetanimation!=jumpdownanim)player[k].collided=1;
+                                                                                                                                               if(checkcollide(lowpoint7,lowpointtarget7)==-1)
+                                                                                                                                                       if(checkcollide(lowpoint6,lowpointtarget6)==-1)
+                                                                                                                                                               if(objects.model[i].LineCheckPossible(&lowpoint2,&lowpointtarget2,&colpoint,&objects.position[i],&objects.rotation[i])!=-1&&objects.model[i].LineCheckPossible(&lowpoint3,&lowpointtarget3,&colpoint,&objects.position[i],&objects.rotation[i])!=-1&&objects.model[i].LineCheckPossible(&lowpoint4,&lowpointtarget4,&colpoint,&objects.position[i],&objects.rotation[i])!=-1&&objects.model[i].LineCheckPossible(&lowpoint5,&lowpointtarget5,&colpoint,&objects.position[i],&objects.rotation[i])!=-1)
+                                                                                                                                                                       for(j=0;j<45;j++){
+                                                                                                                                                                               lowpoint=player[k].coords;
+                                                                                                                                                                               lowpoint.y+=(float)j/13;
+                                                                                                                                                                               lowpointtarget=lowpoint+facing*1.4;
+                                                                                                                                                                               if(objects.model[i].LineCheckPossible(&lowpoint,&lowpointtarget,&colpoint2,&objects.position[i],&objects.rotation[i])==-1){
+                                                                                                                                                                                       if(j<=6){
+                                                                                                                                                                                               j=100;
+                                                                                                                                                                                       }
+                                                                                                                                                                                       /*if(j>=25&&(player[k].isRun()||player[k].targetanimation==sneakanim||player[k].targetanimation==walkanim)){
+                                                                                                                                                                                       j=100;
+                                                                                                                                                                                       }*/
+                                                                                                                                                                                       if(j<=25&&player[k].targetanimation==jumpdownanim){
+                                                                                                                                                                                               j=100;
+                                                                                                                                                                                       }
+                                                                                                                                                                                       if(j!=100&&(/*j>25||(player[k].isRun()||player[k].targetanimation==sneakanim||player[k].targetanimation==walkanim)||*/player[k].targetanimation==jumpupanim||player[k].targetanimation==jumpdownanim)){
+                                                                                                                                                                                               lowpoint=DoRotation(objects.model[i].facenormals[whichhit],0,objects.rotation[k],0);
+                                                                                                                                                                                               if(1==1/*dotproduct(&player[k].velocity,&lowpoint)>0||player[k].aitype!=playercontrolled||(player[k].isRun()||player[k].targetanimation==sneakanim||player[k].targetanimation==walkanim||player[k].targetanimation==jumpupanim)*/){
+                                                                                                                                                                                                       lowpoint=player[k].coords;
+                                                                                                                                                                                                       lowpoint.y+=(float)j/13;
+                                                                                                                                                                                                       lowpointtarget=lowpoint+facing*1.3;
+                                                                                                                                                                                                       flatfacing=player[k].coords;
+                                                                                                                                                                                                       player[k].coords=colpoint-DoRotation(objects.model[i].facenormals[whichhit],0,objects.rotation[k],0)*.01;
+                                                                                                                                                                                                       player[k].coords.y=lowpointtarget.y-.07;
+                                                                                                                                                                                                       player[k].currentoffset=(flatfacing-player[k].coords)/player[k].scale;
+
+                                                                                                                                                                                                       if(j>10||!player[k].isRun()){                                                                                                   
+                                                                                                                                                                                                               if(player[k].targetanimation==jumpdownanim||player[k].targetanimation==jumpupanim){
+                                                                                                                                                                                                                       if(k==0)FSOUND_SetPaused(channels[whooshsound], TRUE);
+                                                                                                                                                                                                               }
+                                                                                                                                                                                                               float gLoc[3];
+                                                                                                                                                                                                               float vel[3];
+                                                                                                                                                                                                               gLoc[0]=player[k].coords.x;
+                                                                                                                                                                                                               gLoc[1]=player[k].coords.y;
+                                                                                                                                                                                                               gLoc[2]=player[k].coords.z;
+                                                                                                                                                                                                               vel[0]=player[k].velocity.x;
+                                                                                                                                                                                                               vel[1]=player[k].velocity.y;
+                                                                                                                                                                                                               vel[2]=player[k].velocity.z;
+                                                                                                                                                                                                               PlaySoundEx( jumpsound, samp[jumpsound], NULL, TRUE);
+                                                                                                                                                                                                               FSOUND_3D_SetAttributes(channels[jumpsound], gLoc, vel);
+                                                                                                                                                                                                               FSOUND_SetVolume(channels[jumpsound], 128);
+                                                                                                                                                                                                               FSOUND_SetPaused(channels[jumpsound], FALSE);
+
+                                                                                                                                                                                                               lowpointtarget=DoRotation(objects.model[i].facenormals[whichhit],0,objects.rotation[i],0);
+                                                                                                                                                                                                               player[k].rotation=-asin(0-lowpointtarget.x);
+                                                                                                                                                                                                               player[k].rotation*=360/6.28;
+                                                                                                                                                                                                               if(lowpointtarget.z<0)player[k].rotation=180-player[k].rotation;
+                                                                                                                                                                                                               player[k].targetrotation=player[k].rotation;
+                                                                                                                                                                                                               player[k].lowrotation=player[k].rotation;
+
+                                                                                                                                                                                                               //player[k].velocity=lowpointtarget*.03;
+                                                                                                                                                                                                               player[k].velocity=0;
+
+                                                                                                                                                                                                               if(/*(player[k].isRun()||player[k].targetanimation==sneakanim||player[k].targetanimation==walkanim)||*/player[k].targetanimation==jumpupanim){
+                                                                                                                                                                                                                       //player[k].currentanimation=climbanim;
+                                                                                                                                                                                                                       player[k].targetanimation=climbanim;
+                                                                                                                                                                                                                       player[k].jumppower=0;
+                                                                                                                                                                                                                       player[k].jumpclimb=1;
+                                                                                                                                                                                                               }
+                                                                                                                                                                                                               player[k].transspeed=6;
+                                                                                                                                                                                                               player[k].target=0;
+
+                                                                                                                                                                                                               //player[k].currentframe=1;
+                                                                                                                                                                                                               player[k].targetframe=1;
+                                                                                                                                                                                                               if(j>25){
+                                                                                                                                                                                                                       //player[k].currentframe=0;
+                                                                                                                                                                                                                       player[k].targetframe=0;
+                                                                                                                                                                                                                       //player[k].currentanimation=hanganim;
+                                                                                                                                                                                                                       player[k].targetanimation=hanganim;
+                                                                                                                                                                                                                       player[k].jumppower=0;
+                                                                                                                                                                                                               }       
+                                                                                                                                                                                                       }
+                                                                                                                                                                                                       j=100;
+                                                                                                                                                                                               }
+                                                                                                                                                                                       }
+                                                                                                                                                                               }
+                                                                                                                                                                       }
+                                                                                                                                                                       //}
+                                                                                                                                       }
+                                                                                                                       }
+                                                                                                               }
+                                                                                                       }
+                                                                                       }
+                                                                                       if(player[k].collide<=0){
+                                                                                               if(!player[k].onterrain&&player[k].targetanimation!=jumpupanim&&player[k].targetanimation!=jumpdownanim&&player[k].targetanimation!=climbanim&&player[k].targetanimation!=hanganim&&!player[k].isWallJump()&&!player[k].isFlip()){
+                                                                                                       if(player[k].currentanimation!=climbanim&&player[k].currentanimation!=tempanim&&player[k].targetanimation!=backhandspringanim&&(player[k].targetanimation!=rollanim||player[k].targetframe<2||player[k].targetframe>6)){
+                                                                                                               if(player[k].targetanimation==staggerbackhighanim||player[k].targetanimation==staggerbackhardanim)player[k].RagDoll(0);
+                                                                                                               player[k].targetanimation=jumpdownanim;
+                                                                                                               player[k].targetframe=0;
+                                                                                                               player[k].target=0;
+
+                                                                                                               float gLoc[3];
+                                                                                                               float vel[3];
+                                                                                                               gLoc[0]=player[k].coords.x;
+                                                                                                               gLoc[1]=player[k].coords.y;
+                                                                                                               gLoc[2]=player[k].coords.z;
+                                                                                                               vel[0]=player[k].velocity.x;
+                                                                                                               vel[1]=player[k].velocity.y;
+                                                                                                               vel[2]=player[k].velocity.z;
+                                                                                                               if(k==0){
+                                                                                                                       PlaySoundEx( whooshsound, samp[whooshsound], NULL, TRUE);
+                                                                                                                       FSOUND_3D_SetAttributes(channels[whooshsound], gLoc, vel);
+                                                                                                                       FSOUND_SetVolume(channels[whooshsound], 128);
+                                                                                                                       FSOUND_SetPaused(channels[whooshsound], FALSE);
+                                                                                                               }
+                                                                                                       }
+                                                                                                       player[k].velocity.y+=gravity;
+                                                                                               }
+                                                                                       }
+                                                               }
+                                                       }
+                                                       player[k].realoldcoords=player[k].coords;
+                                               }
+
+                                               static XYZ oldviewer;
+
+                                               if(indialogue==-1){
+                                                       player[0].forwardkeydown=IsKeyDown(theKeyMap, forwardkey);
+                                                       player[0].leftkeydown=IsKeyDown(theKeyMap, leftkey);
+                                                       player[0].backkeydown=IsKeyDown(theKeyMap, backkey);
+                                                       player[0].rightkeydown=IsKeyDown(theKeyMap, rightkey);
+                                                       player[0].jumpkeydown=IsKeyDown(theKeyMap, jumpkey);
+                                                       player[0].crouchkeydown=IsKeyDown(theKeyMap, crouchkey);
+                                                       player[0].drawkeydown=IsKeyDown(theKeyMap, drawkey);
+                                                       player[0].throwkeydown=IsKeyDown(theKeyMap, throwkey);
+                                               }
+                                               else
+                                               {
+                                                       player[0].forwardkeydown=0;
+                                                       player[0].leftkeydown=0;
+                                                       player[0].backkeydown=0;
+                                                       player[0].rightkeydown=0;
+                                                       player[0].jumpkeydown=0;
+                                                       player[0].crouchkeydown=0;
+                                                       player[0].drawkeydown=0;
+                                                       player[0].throwkeydown=0;
+                                               }
+
+                                               if(!player[0].jumpkeydown)player[0].jumpclimb=0;
+
+
+                                               static bool endkeydown;
+                                               if(indialogue!=-1){
+                                                       cameramode=1;
+                                                       if(directing){  
+                                                               facing=0;
+                                                               facing.z=-1;
+
+                                                               facing=DoRotation(facing,-rotation2,0,0);
+                                                               facing=DoRotation(facing,0,0-rotation,0);
+
+                                                               flatfacing=0;
+                                                               flatfacing.z=-1;
+
+                                                               flatfacing=DoRotation(flatfacing,0,-rotation,0);
+
+                                                               if(IsKeyDown(theKeyMap, forwardkey))viewer+=facing*multiplier*4;
+                                                               if(IsKeyDown(theKeyMap, backkey))viewer-=facing*multiplier*4;
+                                                               if(IsKeyDown(theKeyMap, leftkey))viewer+=DoRotation(flatfacing*multiplier,0,90,0)*4;
+                                                               if(IsKeyDown(theKeyMap, rightkey))viewer+=DoRotation(flatfacing*multiplier,0,-90,0)*4;
+                                                               if(IsKeyDown(theKeyMap, jumpkey))viewer.y+=multiplier*4;
+                                                               if(IsKeyDown(theKeyMap, crouchkey))viewer.y-=multiplier*4;
+                                                               if(!endkeydown&&(IsKeyDown(theKeyMap, MAC_1_KEY)||IsKeyDown(theKeyMap, MAC_2_KEY)||IsKeyDown(theKeyMap, MAC_3_KEY)||IsKeyDown(theKeyMap, MAC_4_KEY)||IsKeyDown(theKeyMap, MAC_5_KEY)
+                                                                       ||IsKeyDown(theKeyMap, MAC_6_KEY)||IsKeyDown(theKeyMap, MAC_7_KEY)||IsKeyDown(theKeyMap, MAC_8_KEY)||IsKeyDown(theKeyMap, MAC_9_KEY)||IsKeyDown(theKeyMap, MAC_0_KEY)
+                                                                       ||IsKeyDown(theKeyMap, MAC_MINUS_KEY))){
+                                                                               int whichend;
+                                                                               if(IsKeyDown(theKeyMap, MAC_1_KEY))whichend=1;
+                                                                               if(IsKeyDown(theKeyMap, MAC_2_KEY))whichend=2;
+                                                                               if(IsKeyDown(theKeyMap, MAC_3_KEY))whichend=3;
+                                                                               if(IsKeyDown(theKeyMap, MAC_4_KEY))whichend=4;
+                                                                               if(IsKeyDown(theKeyMap, MAC_5_KEY))whichend=5;
+                                                                               if(IsKeyDown(theKeyMap, MAC_6_KEY))whichend=6;
+                                                                               if(IsKeyDown(theKeyMap, MAC_7_KEY))whichend=7;
+                                                                               if(IsKeyDown(theKeyMap, MAC_8_KEY))whichend=8;
+                                                                               if(IsKeyDown(theKeyMap, MAC_9_KEY))whichend=9;
+                                                                               if(IsKeyDown(theKeyMap, MAC_0_KEY))whichend=0;
+                                                                               if(IsKeyDown(theKeyMap, MAC_MINUS_KEY))whichend=-1;
+                                                                               if(whichend!=-1){
+                                                                                       participantfocus[whichdialogue][indialogue]=whichend;
+                                                                                       participantlocation[whichdialogue][whichend]=player[whichend].coords;
+                                                                                       participantrotation[whichdialogue][whichend]=player[whichend].rotation;
+                                                                               }
+                                                                               if(whichend==-1){
+                                                                                       participantfocus[whichdialogue][indialogue]=-1;
+                                                                               }
+                                                                               if(player[participantfocus[whichdialogue][indialogue]].dead){
+                                                                                       indialogue=-1;
+                                                                                       directing=0;
+                                                                                       cameramode=0;
+                                                                               }
+                                                                               dialoguecamera[whichdialogue][indialogue]=viewer;
+                                                                               dialoguecamerarotation[whichdialogue][indialogue]=rotation;
+                                                                               dialoguecamerarotation2[whichdialogue][indialogue]=rotation2;
+                                                                               indialogue++;
+                                                                               if(indialogue<numdialogueboxes[whichdialogue]){
+                                                                                       if(dialogueboxsound[whichdialogue][indialogue]!=0){
+                                                                                               static float gLoc[3];
+                                                                                               static float vel[3];
+                                                                                               XYZ temppos;
+                                                                                               temppos=player[participantfocus[whichdialogue][indialogue]].coords;
+                                                                                               temppos=temppos-viewer;
+                                                                                               Normalise(&temppos);
+                                                                                               temppos+=viewer;
+
+                                                                                               gLoc[0]=temppos.x;
+                                                                                               gLoc[1]=temppos.y;
+                                                                                               gLoc[2]=temppos.z;vel[0]=0;
+                                                                                               vel[1]=0;
+                                                                                               vel[2]=0;
+                                                                                               int whichsoundplay;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==1)whichsoundplay=rabbitchitter;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==2)whichsoundplay=rabbitchitter2;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==3)whichsoundplay=rabbitpainsound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==4)whichsoundplay=rabbitpain1sound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==5)whichsoundplay=rabbitattacksound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==6)whichsoundplay=rabbitattack2sound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==7)whichsoundplay=rabbitattack3sound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==8)whichsoundplay=rabbitattack4sound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==9)whichsoundplay=growlsound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==10)whichsoundplay=growl2sound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==11)whichsoundplay=snarlsound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==12)whichsoundplay=snarl2sound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==13)whichsoundplay=barksound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==14)whichsoundplay=bark2sound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==15)whichsoundplay=bark3sound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==16)whichsoundplay=barkgrowlsound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==-1)whichsoundplay=fireendsound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==-2)whichsoundplay=firestartsound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==-3)whichsoundplay=consolesuccesssound;
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]==-4)whichsoundplay=consolefailsound;
+                                                                                               PlaySoundEx( whichsoundplay, samp[whichsoundplay], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[whichsoundplay], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[whichsoundplay], 256);
+                                                                                               FSOUND_SetPaused(channels[whichsoundplay], FALSE);
+                                                                                       }
+                                                                               }
+
+                                                                               for(j=0;j<numplayers;j++){
+                                                                                       participantfacing[whichdialogue][indialogue][j]=participantfacing[whichdialogue][indialogue-1][j];
+                                                                               }
+
+                                                                               endkeydown=1;
+                                                                       }
+                                                                       if((IsKeyDown(theKeyMap, MAC_NUMPAD_1_KEY)||IsKeyDown(theKeyMap, MAC_NUMPAD_2_KEY)||IsKeyDown(theKeyMap, MAC_NUMPAD_3_KEY)||IsKeyDown(theKeyMap, MAC_NUMPAD_4_KEY)||IsKeyDown(theKeyMap, MAC_NUMPAD_5_KEY)
+                                                                               ||IsKeyDown(theKeyMap, MAC_NUMPAD_6_KEY)||IsKeyDown(theKeyMap, MAC_NUMPAD_7_KEY)||IsKeyDown(theKeyMap, MAC_NUMPAD_8_KEY)||IsKeyDown(theKeyMap, MAC_NUMPAD_9_KEY)||IsKeyDown(theKeyMap, MAC_NUMPAD_0_KEY)
+                                                                               )){
+                                                                                       int whichend;
+                                                                                       if(IsKeyDown(theKeyMap, MAC_NUMPAD_1_KEY))whichend=1;
+                                                                                       if(IsKeyDown(theKeyMap, MAC_NUMPAD_2_KEY))whichend=2;
+                                                                                       if(IsKeyDown(theKeyMap, MAC_NUMPAD_3_KEY))whichend=3;
+                                                                                       if(IsKeyDown(theKeyMap, MAC_NUMPAD_4_KEY))whichend=4;
+                                                                                       if(IsKeyDown(theKeyMap, MAC_NUMPAD_5_KEY))whichend=5;
+                                                                                       if(IsKeyDown(theKeyMap, MAC_NUMPAD_6_KEY))whichend=6;
+                                                                                       if(IsKeyDown(theKeyMap, MAC_NUMPAD_7_KEY))whichend=7;
+                                                                                       if(IsKeyDown(theKeyMap, MAC_NUMPAD_8_KEY))whichend=8;
+                                                                                       if(IsKeyDown(theKeyMap, MAC_NUMPAD_9_KEY))whichend=9;
+                                                                                       if(IsKeyDown(theKeyMap, MAC_NUMPAD_0_KEY))whichend=0;
+                                                                                       participantfacing[whichdialogue][indialogue][whichend]=facing;
+                                                                               }
+                                                                               if(!IsKeyDown(theKeyMap, MAC_1_KEY)&&!IsKeyDown(theKeyMap, MAC_2_KEY)&&!IsKeyDown(theKeyMap, MAC_3_KEY)&&!IsKeyDown(theKeyMap, MAC_4_KEY)&&!IsKeyDown(theKeyMap, MAC_5_KEY)
+                                                                                       &&!IsKeyDown(theKeyMap, MAC_6_KEY)&&!IsKeyDown(theKeyMap, MAC_7_KEY)&&!IsKeyDown(theKeyMap, MAC_8_KEY)&&!IsKeyDown(theKeyMap, MAC_9_KEY)&&!IsKeyDown(theKeyMap, MAC_0_KEY)
+                                                                                       &&!IsKeyDown(theKeyMap, MAC_MINUS_KEY)){
+                                                                                               endkeydown=0;
+                                                                                       }
+                                                                                       if(indialogue>=numdialogueboxes[whichdialogue]){
+                                                                                               indialogue=-1;
+                                                                                               directing=0;
+                                                                                               cameramode=0;
+                                                                                       }
+                                                       }
+                                                       if(!directing){ 
+                                                               FSOUND_SetPaused(channels[whooshsound], TRUE);
+                                                               viewer=dialoguecamera[whichdialogue][indialogue];
+                                                               if(viewer.y<terrain.getHeight(viewer.x,viewer.z)+.1){
+                                                                       viewer.y=terrain.getHeight(viewer.x,viewer.z)+.1;
+                                                               }                               
+                                                               rotation=dialoguecamerarotation[whichdialogue][indialogue];
+                                                               rotation2=dialoguecamerarotation2[whichdialogue][indialogue];
+                                                               if(dialoguetime>0.5)
+                                                                       if((!endkeydown&&(IsKeyDown(theKeyMap, MAC_1_KEY)||IsKeyDown(theKeyMap, MAC_2_KEY)||IsKeyDown(theKeyMap, MAC_3_KEY)||IsKeyDown(theKeyMap, MAC_4_KEY)||IsKeyDown(theKeyMap, MAC_5_KEY)
+                                                                               ||IsKeyDown(theKeyMap, MAC_6_KEY)||IsKeyDown(theKeyMap, MAC_7_KEY)||IsKeyDown(theKeyMap, MAC_8_KEY)||IsKeyDown(theKeyMap, MAC_9_KEY)||IsKeyDown(theKeyMap, MAC_0_KEY)
+                                                                               ||IsKeyDown(theKeyMap, MAC_MINUS_KEY)))||(IsKeyDown(theKeyMap, attackkey)&&!oldbuttondialogue)){
+                                                                                       indialogue++;
+                                                                                       endkeydown=1;
+                                                                                       if(indialogue<numdialogueboxes[whichdialogue]){
+                                                                                               if(dialogueboxsound[whichdialogue][indialogue]!=0){
+                                                                                                       static float gLoc[3];
+                                                                                                       static float vel[3];
+                                                                                                       XYZ temppos;
+                                                                                                       temppos=player[participantfocus[whichdialogue][indialogue]].coords;
+                                                                                                       temppos=temppos-viewer;
+                                                                                                       Normalise(&temppos);
+                                                                                                       temppos+=viewer;
+
+                                                                                                       gLoc[0]=temppos.x;
+                                                                                                       gLoc[1]=temppos.y;
+                                                                                                       gLoc[2]=temppos.z;vel[0]=0;
+                                                                                                       vel[1]=0;
+                                                                                                       vel[2]=0;
+                                                                                                       int whichsoundplay;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==1)whichsoundplay=rabbitchitter;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==2)whichsoundplay=rabbitchitter2;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==3)whichsoundplay=rabbitpainsound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==4)whichsoundplay=rabbitpain1sound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==5)whichsoundplay=rabbitattacksound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==6)whichsoundplay=rabbitattack2sound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==7)whichsoundplay=rabbitattack3sound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==8)whichsoundplay=rabbitattack4sound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==9)whichsoundplay=growlsound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==10)whichsoundplay=growl2sound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==11)whichsoundplay=snarlsound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==12)whichsoundplay=snarl2sound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==13)whichsoundplay=barksound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==14)whichsoundplay=bark2sound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==15)whichsoundplay=bark3sound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==16)whichsoundplay=barkgrowlsound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-1)whichsoundplay=fireendsound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-2)whichsoundplay=firestartsound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-3)whichsoundplay=consolesuccesssound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-4)whichsoundplay=consolefailsound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-6)whichsoundplay=alarmsound;
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]!=-5){
+                                                                                                               PlaySoundEx( whichsoundplay, samp[whichsoundplay], NULL, TRUE);
+                                                                                                               FSOUND_3D_SetAttributes(channels[whichsoundplay], gLoc, vel);
+                                                                                                               FSOUND_SetVolume(channels[whichsoundplay], 256);
+                                                                                                               FSOUND_SetPaused(channels[whichsoundplay], FALSE);
+                                                                                                       }
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-5){
+                                                                                                               hotspot[numhotspots]=player[0].coords;
+                                                                                                               hotspotsize[numhotspots]=10;
+                                                                                                               hotspottype[numhotspots]=-1;
+
+                                                                                                               numhotspots++;
+                                                                                                       }
+                                                                                                       if(dialogueboxsound[whichdialogue][indialogue]==-6){
+                                                                                                               hostile=1;
+                                                                                                       }
+
+                                                                                                       if(player[participantfocus[whichdialogue][indialogue]].dead){
+                                                                                                               indialogue=-1;
+                                                                                                               directing=0;
+                                                                                                               cameramode=0;
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+                                                                               }
+                                                                               if(!IsKeyDown(theKeyMap, MAC_1_KEY)&&!IsKeyDown(theKeyMap, MAC_2_KEY)&&!IsKeyDown(theKeyMap, MAC_3_KEY)&&!IsKeyDown(theKeyMap, MAC_4_KEY)&&!IsKeyDown(theKeyMap, MAC_5_KEY)
+                                                                                       &&!IsKeyDown(theKeyMap, MAC_6_KEY)&&!IsKeyDown(theKeyMap, MAC_7_KEY)&&!IsKeyDown(theKeyMap, MAC_8_KEY)&&!IsKeyDown(theKeyMap, MAC_9_KEY)&&!IsKeyDown(theKeyMap, MAC_0_KEY)
+                                                                                       &&!IsKeyDown(theKeyMap, MAC_MINUS_KEY)){
+                                                                                               endkeydown=0;
+                                                                                       }
+                                                                                       if(indialogue>=numdialogueboxes[whichdialogue]){
+                                                                                               indialogue=-1;
+                                                                                               directing=0;
+                                                                                               cameramode=0;
+                                                                                               if(dialoguetype[whichdialogue]>19&&dialoguetype[whichdialogue]<30){
+                                                                                                       hostile=1;
+                                                                                               }
+                                                                                               if(dialoguetype[whichdialogue]>29&&dialoguetype[whichdialogue]<40){
+                                                                                                       windialogue=1;
+                                                                                               }
+                                                                                               if(dialoguetype[whichdialogue]>49&&dialoguetype[whichdialogue]<60){
+                                                                                                       hostile=1;
+                                                                                                       for(i=1;i<numplayers;i++){
+                                                                                                               player[i].aitype = attacktypecutoff;
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+                                                       }
+                                               }
+
+                                               if(!IsKeyDown(theKeyMap, attackkey))oldbuttondialogue=0;
+                                               else oldbuttondialogue=1;
+
+                                               static float keyrefreshdelay=0,bigrefreshdelay=0;
+
+                                               //Net updates
+
+                                               /*keyrefreshdelay-=multiplier;
+                                               bigrefreshdelay-=multiplier;
+
+                                               if(keyrefreshdelay<=0){
+                                               static int concat[4];
+
+                                               concat[0]=player[0].forwardkeydown;
+                                               concat[0]=concat[0]*2+player[0].forwardstogglekeydown;
+                                               concat[0]=concat[0]*2+player[0].rightkeydown;
+                                               concat[0]=concat[0]*2+player[0].leftkeydown;
+                                               concat[0]=concat[0]*2+player[0].backkeydown;
+                                               concat[0]=concat[0]*2+player[0].jumpkeydown;
+                                               concat[0]=concat[0]*2+player[0].jumptogglekeydown;
+                                               concat[0]=concat[0]*2+player[0].crouchkeydown;
+
+                                               concat[1]=player[0].crouchtogglekeydown;
+                                               concat[1]=concat[1]*2+player[0].drawkeydown;
+                                               concat[1]=concat[1]*2+player[0].drawtogglekeydown;
+                                               concat[1]=concat[1]*2+player[0].throwkeydown;
+                                               concat[1]=concat[1]*2+player[0].throwtogglekeydown;
+                                               concat[1]=concat[1]*2+player[0].attackkeydown;
+
+                                               //concat[2]=(char)((int)(rotation/2)%180);
+
+                                               //concat[3]=(char)((int)(rotation2/2)%180);
+
+                                               chatname[0]=concat[0]-128;
+                                               chatname[1]=concat[1]-128;
+                                               //chatname[2]=concat[2]-128;
+                                               //chatname[3]=concat[3]-128;
+                                               int temppoint=2;
+                                               memcpy(chatname+temppoint,&rotation,sizeof(float));
+                                               temppoint+=sizeof(float);
+                                               memcpy(chatname+temppoint,&rotation2,sizeof(float));
+                                               temppoint+=sizeof(float);
+
+                                               chatname[temppoint]='\0';
+
+                                               //if(!ishost)NetworkSendPlayerMessage( chatname, kMessageType_Keys );
+                                               //if(ishost)NetworkSendPlayerRelayMessage( chatname, kMessageType_Keys );
+                                               //keyrefreshdelay=.01;
+                                               keyrefreshdelay=.03;
+                                               }
+
+                                               if(bigrefreshdelay<=0){
+                                               for(i=0;i<1;i++){
+                                               /*int temppoint=0;
+                                               memcpy(chatname+temppoint,&i,sizeof(int));
+                                               temppoint+=sizeof(int);
+                                               memcpy(chatname+temppoint,&player[i].coords.x,sizeof(float));
+                                               temppoint+=sizeof(float);
+                                               memcpy(chatname+temppoint,&player[i].coords.y,sizeof(float));
+                                               temppoint+=sizeof(float);
+                                               memcpy(chatname+temppoint,&player[i].coords.z,sizeof(float));
+                                               temppoint+=sizeof(float);
+                                               memcpy(chatname+temppoint,&player[i].damage,sizeof(float));
+                                               temppoint+=sizeof(float);
+                                               memcpy(chatname+temppoint,&player[i].target,sizeof(float));
+                                               temppoint+=sizeof(float);
+                                               memcpy(chatname+temppoint,&player[i].targetanimation,sizeof(int));
+                                               temppoint+=sizeof(int);
+                                               memcpy(chatname+temppoint,&player[i].currentanimation,sizeof(int));
+                                               temppoint+=sizeof(int);
+                                               memcpy(chatname+temppoint,&player[i].velocity.x,sizeof(float));
+                                               temppoint+=sizeof(float);
+                                               memcpy(chatname+temppoint,&player[i].velocity.y,sizeof(float));
+                                               temppoint+=sizeof(float);
+                                               memcpy(chatname+temppoint,&player[i].velocity.z,sizeof(float));
+                                               temppoint+=sizeof(float);
+                                               memcpy(chatname+temppoint,&player[i].targetframe,sizeof(int));
+                                               temppoint+=sizeof(int);
+                                               memcpy(chatname+temppoint,&player[i].currentframe,sizeof(int));
+                                               temppoint+=sizeof(int);
+                                               memcpy(chatname+temppoint,&player[i].rotation,sizeof(float));
+                                               temppoint+=sizeof(float);
+                                               memcpy(chatname+temppoint,&player[i].targetrotation,sizeof(float));
+                                               temppoint+=sizeof(float);
+                                               memcpy(chatname+temppoint,&player[i].bloodloss,sizeof(float));
+                                               temppoint+=sizeof(float);
+                                               memcpy(chatname+temppoint,&player[i].weaponactive,sizeof(int));
+                                               temppoint+=sizeof(int);
+                                               memcpy(chatname+temppoint,&player[i].num_weapons,sizeof(int));
+                                               temppoint+=sizeof(int);
+                                               memcpy(chatname+temppoint,&player[i].weaponids[0],sizeof(int));
+                                               temppoint+=sizeof(int);
+                                               memcpy(chatname+temppoint,&player[i].weaponids[1],sizeof(int));
+                                               temppoint+=sizeof(int);
+                                               memcpy(chatname+temppoint,&player[i].weaponids[2],sizeof(int));
+                                               temppoint+=sizeof(int);
+                                               memcpy(chatname+temppoint,&player[i].weaponids[3],sizeof(int));
+                                               temppoint+=sizeof(int);
+                                               chatname[temppoint]='\0';
+
+                                               sprintf (chatname, "%d %f %f %f %f %f %d %d %f %f %f %d %d %f %f %f",i,player[i].coords.x,player[i].coords.y,player[i].coords.z,player[i].damage,player[i].target, player[i].targetanimation, player[i].currentanimation, player[i].velocity.x, player[i].velocity.y, player[i].velocity.z, player[i].targetframe, player[i].currentframe, player[i].rotation, player[i].targetrotation);
+                                               //if(ishost)NetworkSendPlayerRelayMessage( chatname, kMessageType_PlayerState );
+                                               //else NetworkSendPlayerMessage( chatname, kMessageType_PlayerState );
+
+                                               sprintf (chatname, "%d %f %d %d %d %d %d %d %d %d %f",i,player[i].bloodloss, player[i].weaponactive, player[i].num_weapons, player[i].weaponids[0], player[i].weaponids[1], player[i].weaponids[2], player[i].weaponids[3],player[i].dead,player[i].skeleton.free,player[i].permanentdamage);
+
+                                               //if(ishost)NetworkSendPlayerRelayMessage( chatname, kMessageType_PlayerStateMisc );
+                                               //else NetworkSendPlayerMessage( chatname, kMessageType_PlayerStateMisc );
+                                               }
+                                               //bigrefreshdelay=.02;
+                                               bigrefreshdelay=.1;
+                                               }
+                                               }*/
+
+                                               if(!player[0].jumpkeydown){
+                                                       player[0].jumptogglekeydown=0;
+                                               }
+                                               if(player[0].jumpkeydown&&player[0].targetanimation!=jumpupanim&&player[0].targetanimation!=jumpdownanim&&!player[0].isFlip())player[0].jumptogglekeydown=1;
+
+
+                                               dialoguetime+=multiplier;
+                                               skybox.cloudmove+=multiplier;
+                                               hawkrotation+=multiplier*25;
+                                               realhawkcoords=0;
+                                               realhawkcoords.x=25;
+                                               realhawkcoords=DoRotation(realhawkcoords,0,hawkrotation,0)+hawkcoords;
+                                               hawkcalldelay-=multiplier/2;
+
+                                               if(hawkcalldelay<=0)
+                                               {
+                                                       static float gLoc[3];
+                                                       static float vel[3];
+                                                       gLoc[0]=realhawkcoords.x;
+                                                       gLoc[1]=realhawkcoords.y;
+                                                       gLoc[2]=realhawkcoords.z;
+                                                       vel[0]=0;
+                                                       vel[1]=0;
+                                                       vel[2]=0;
+                                                       PlaySoundEx( hawksound, samp[hawksound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[hawksound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[hawksound], 128);
+                                                       FSOUND_SetPaused(channels[hawksound], FALSE);
+
+                                                       hawkcalldelay=16+abs(Random()%8);
+                                               }
+                                               static float temptexdetail;
+
+
+                                               if(IsKeyDown(theKeyMap, MAC_H_KEY)&&debugmode){
+                                                       player[0].damagetolerance=200000;
+                                                       player[0].damage=0;
+                                                       player[0].burnt=0;
+                                                       player[0].permanentdamage=0;
+                                                       player[0].superpermanentdamage=0;
+                                                       /*
+                                                       int whichchar;
+                                                       whichchar = abs(Random()%7);
+                                                       registrationname[whichchar]+=1;
+                                                       */
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_J_KEY)&&!envtogglekeydown&&debugmode){
+                                                       environment++;
+                                                       if(environment>2)environment=0;
+                                                       Setenvironment(environment);
+
+                                                       envtogglekeydown=1;
+                                               }
+
+
+                                               if(!IsKeyDown(theKeyMap, MAC_J_KEY)){
+                                                       envtogglekeydown=0;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_C_KEY)&&!cameratogglekeydown&&debugmode){
+                                                       cameramode=1-cameramode;
+                                                       cameratogglekeydown=1;
+                                               }
+
+                                               if(!IsKeyDown(theKeyMap, MAC_C_KEY)){
+                                                       cameratogglekeydown=0;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_X_KEY)&&!IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&!detailtogglekeydown&&debugmode){
+                                                       if(player[0].num_weapons>0){
+                                                               if(weapons.type[player[0].weaponids[0]]==sword)weapons.type[player[0].weaponids[0]]=staff;
+                                                               else if(weapons.type[player[0].weaponids[0]]==staff)weapons.type[player[0].weaponids[0]]=knife;
+                                                               else weapons.type[player[0].weaponids[0]]=sword;
+                                                               if(weapons.type[player[0].weaponids[0]]==sword){
+                                                                       weapons.mass[player[0].weaponids[0]]=1.5;
+                                                                       weapons.tipmass[player[0].weaponids[0]]=1;
+                                                                       weapons.length[player[0].weaponids[0]]=.8;
+                                                               }
+                                                               if(weapons.type[player[0].weaponids[0]]==staff){
+                                                                       weapons.mass[player[0].weaponids[0]]=2;
+                                                                       weapons.tipmass[player[0].weaponids[0]]=1;
+                                                                       weapons.length[player[0].weaponids[0]]=1.5;
+                                                               }
+
+                                                               if(weapons.type[player[0].weaponids[0]]==knife){
+                                                                       weapons.mass[player[0].weaponids[0]]=1;
+                                                                       weapons.tipmass[player[0].weaponids[0]]=1.2;
+                                                                       weapons.length[player[0].weaponids[0]]=.25;
+                                                               }
+                                                       }
+
+                                                       /*for(i=0;i<objects.numobjects;i++){
+                                                       if(objects.type[i]==treeleavestype){
+                                                       for(j=0;j<objects.numobjects;j++){
+                                                       if(objects.type[j]==treetrunktype)
+                                                       if(findDistancefast(&objects.position[i],&objects.position[j])<.5)
+                                                       objects.scale[i]=objects.scale[j];      
+                                                       }
+                                                       }
+                                                       }*/
+                                                       detailtogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_X_KEY)&&IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&!detailtogglekeydown&&debugmode){
+                                                       int closest=-1;
+                                                       float closestdist=-1;
+                                                       float distance;
+                                                       if(numplayers>1)
+                                                               for(i=1;i<numplayers;i++){
+                                                                       distance=findDistancefast(&player[i].coords,&player[0].coords);
+                                                                       if(closestdist==-1||distance<closestdist){
+                                                                               closestdist=distance;
+                                                                               closest=i;
+                                                                       }
+                                                               }
+                                                               if(closest!=-1){
+                                                                       if(player[closest].num_weapons)
+                                                                       {
+                                                                               if(weapons.type[player[closest].weaponids[0]]==sword)weapons.type[player[closest].weaponids[0]]=staff;
+                                                                               else if(weapons.type[player[closest].weaponids[0]]==staff)weapons.type[player[closest].weaponids[0]]=knife;
+                                                                               else weapons.type[player[closest].weaponids[0]]=sword;
+                                                                               if(weapons.type[player[closest].weaponids[0]]==sword){
+                                                                                       weapons.mass[player[closest].weaponids[0]]=1.5;
+                                                                                       weapons.tipmass[player[closest].weaponids[0]]=1;
+                                                                                       weapons.length[player[closest].weaponids[0]]=.8;
+                                                                               }
+                                                                               if(weapons.type[player[0].weaponids[0]]==staff){
+                                                                                       weapons.mass[player[0].weaponids[0]]=2;
+                                                                                       weapons.tipmass[player[0].weaponids[0]]=1;
+                                                                                       weapons.length[player[0].weaponids[0]]=1.5;
+                                                                               }
+                                                                               if(weapons.type[player[closest].weaponids[0]]==knife){
+                                                                                       weapons.mass[player[closest].weaponids[0]]=1;
+                                                                                       weapons.tipmass[player[closest].weaponids[0]]=1.2;
+                                                                                       weapons.length[player[closest].weaponids[0]]=.25;
+                                                                               }
+                                                                       }
+                                                                       if(!player[closest].num_weapons)
+                                                                       {
+                                                                               player[closest].weaponids[0]=weapons.numweapons;
+                                                                               weapons.owner[weapons.numweapons]=closest;
+                                                                               weapons.type[weapons.numweapons]=knife;
+                                                                               weapons.damage[weapons.numweapons]=0;
+                                                                               weapons.numweapons++;
+                                                                               player[closest].num_weapons=1;
+                                                                               if(weapons.type[player[closest].weaponids[0]]==sword){
+                                                                                       weapons.mass[player[closest].weaponids[0]]=1.5;
+                                                                                       weapons.tipmass[player[closest].weaponids[0]]=1;
+                                                                                       weapons.length[player[closest].weaponids[0]]=.8;
+                                                                               }
+                                                                               if(weapons.type[player[closest].weaponids[0]]==knife){
+                                                                                       weapons.mass[player[closest].weaponids[0]]=1;
+                                                                                       weapons.tipmass[player[closest].weaponids[0]]=1.2;
+                                                                                       weapons.length[player[closest].weaponids[0]]=.25;
+                                                                               }
+                                                                       }
+                                                               }
+                                                               detailtogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_U_KEY)&&debugmode){
+                                                       int closest=-1;
+                                                       float closestdist=-1;
+                                                       float distance;
+                                                       if(numplayers>1)
+                                                               for(i=1;i<numplayers;i++){
+                                                                       distance=findDistancefast(&player[i].coords,&player[0].coords);
+                                                                       if(closestdist==-1||distance<closestdist){
+                                                                               closestdist=distance;
+                                                                               closest=i;
+                                                                       }
+                                                               }
+
+                                                               player[closest].rotation+=multiplier*50;
+                                                               player[closest].targetrotation=player[closest].rotation;
+                                               }
+
+
+                                               if(IsKeyDown(theKeyMap, MAC_O_KEY)&&!IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&debugmode){
+                                                       int closest=-1;
+                                                       float closestdist=-1;
+                                                       float distance;
+                                                       if(numplayers>1)
+                                                               for(i=1;i<numplayers;i++){
+                                                                       distance=findDistancefast(&player[i].coords,&player[0].coords);
+                                                                       if(closestdist==-1||distance<closestdist){
+                                                                               closestdist=distance;
+                                                                               closest=i;
+                                                                       }
+                                                               }
+                                                               if(IsKeyDown(theKeyMap, MAC_CONTROL_KEY))closest=0;
+
+                                                               if(closest!=-1){
+                                                                       player[closest].whichskin++;
+                                                                       if(player[closest].whichskin>9)player[closest].whichskin=0;
+                                                                       if(player[closest].whichskin>2&&player[closest].creature==wolftype)player[closest].whichskin=0;
+
+                                                                       if(player[closest].creature==rabbittype){
+                                                                               if(player[closest].whichskin==0){
+                                                                                       LoadTextureSave(":Data:Textures:Fur3.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                               }
+                                                                               else if(player[closest].whichskin==1){
+                                                                                       LoadTextureSave(":Data:Textures:Fur.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                               }
+                                                                               else if(player[closest].whichskin==2){
+                                                                                       LoadTextureSave(":Data:Textures:Fur2.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                               }
+                                                                               else if(player[closest].whichskin==3){
+                                                                                       LoadTextureSave(":Data:Textures:Lynx.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                               }
+                                                                               else if(player[closest].whichskin==4){
+                                                                                       LoadTextureSave(":Data:Textures:Otter.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                               }
+                                                                               else if(player[closest].whichskin==5){
+                                                                                       LoadTextureSave(":Data:Textures:Opal.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                               }
+                                                                               else if(player[closest].whichskin==6){
+                                                                                       LoadTextureSave(":Data:Textures:Sable.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                               }
+                                                                               else if(player[closest].whichskin==7){
+                                                                                       LoadTextureSave(":Data:Textures:Chocolate.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                               }
+                                                                               else if(player[closest].whichskin==8){
+                                                                                       LoadTextureSave(":Data:Textures:BW2.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                               }
+                                                                               else if(player[closest].whichskin==9){
+                                                                                       LoadTextureSave(":Data:Textures:WB2.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                               }
+                                                                       }
+                                                                       if(player[closest].creature==wolftype){
+                                                                               k=abs(Random()%3);
+                                                                               if(player[closest].whichskin==0){
+                                                                                       LoadTextureSave(":Data:Textures:Wolf.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                               }
+                                                                               else if(player[closest].whichskin==1){
+                                                                                       LoadTextureSave(":Data:Textures:Darkwolf.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                               }
+                                                                               else if(player[closest].whichskin==2){
+                                                                                       LoadTextureSave(":Data:Textures:Snowwolf.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                               }
+                                                                       }
+                                                               }
+
+                                                               if(player[closest].numclothes){
+                                                                       for(i=0;i<player[closest].numclothes;i++){
+                                                                               tintr=player[closest].clothestintr[i];
+                                                                               tintg=player[closest].clothestintg[i];
+                                                                               tintb=player[closest].clothestintb[i];
+                                                                               AddClothes((char *)player[closest].clothes[i],0,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                       }
+                                                                       player[closest].DoMipmaps(5,0,0,player[closest].skeleton.skinsize,player[closest].skeleton.skinsize);
+                                                               }
+
+                                                               detailtogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_O_KEY)&&IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&debugmode){
+                                                       int closest=-1;
+                                                       float closestdist=-1;
+                                                       float distance;
+                                                       if(numplayers>1)
+                                                               for(i=1;i<numplayers;i++){
+                                                                       distance=findDistancefast(&player[i].coords,&player[0].coords);
+                                                                       if(closestdist==-1||distance<closestdist){
+                                                                               closestdist=distance;
+                                                                               closest=i;
+                                                                       }
+                                                               }
+                                                               if(closest!=-1){
+                                                                       if(player[closest].creature==wolftype){
+                                                                               headprop=player[closest].proportionhead.x/1.1;
+                                                                               bodyprop=player[closest].proportionbody.x/1.1;
+                                                                               armprop=player[closest].proportionarms.x/1.1;
+                                                                               legprop=player[closest].proportionlegs.x/1.1;
+                                                                       }
+
+                                                                       if(player[closest].creature==rabbittype){
+                                                                               headprop=player[closest].proportionhead.x/1.2;
+                                                                               bodyprop=player[closest].proportionbody.x/1.05;
+                                                                               armprop=player[closest].proportionarms.x/1.00;
+                                                                               legprop=player[closest].proportionlegs.x/1.1;
+                                                                       }
+
+
+                                                                       if(player[closest].creature==rabbittype){
+                                                                               player[closest].skeleton.id=closest;
+                                                                               player[closest].skeleton.Load((char *)":Data:Skeleton:Basic Figure Wolf",(char *)":Data:Skeleton:Basic Figure Wolf Low",(char *)":Data:Skeleton:Rabbitbelt",(char *)":Data:Models:Wolf.solid",(char *)":Data:Models:Wolf2.solid",(char *)":Data:Models:Wolf3.solid",(char *)":Data:Models:Wolf4.solid",(char *)":Data:Models:Wolf5.solid",(char *)":Data:Models:Wolf6.solid",(char *)":Data:Models:Wolf7.solid",(char *)":Data:Models:Wolflow.solid",(char *)":Data:Models:Belt.solid",0);
+                                                                               LoadTextureSave(":Data:Textures:Wolf.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[closest],&player[closest].skeleton.skinsize);
+                                                                               player[closest].whichskin=0;
+                                                                               player[closest].creature=wolftype;
+
+                                                                               player[closest].proportionhead=1.1;
+                                                                               player[closest].proportionbody=1.1;
+                                                                               player[closest].proportionarms=1.1;
+                                                                               player[closest].proportionlegs=1.1;
+                                                                               player[closest].proportionlegs.y=1.1;
+                                                                               player[closest].scale=.23*5*player[0].scale;
+
+                                                                               player[closest].damagetolerance=300;
+                                                                       }
+                                                                       else
+                                                                       {
+                                                                               player[closest].skeleton.id=closest;
+                                                                               player[closest].skeleton.Load((char *)":Data:Skeleton:Basic Figure",(char *)":Data:Skeleton:Basic Figurelow",(char *)":Data:Skeleton:Rabbitbelt",(char *)":Data:Models:Body.solid",(char *)":Data:Models:Body2.solid",(char *)":Data:Models:Body3.solid",(char *)":Data:Models:Body4.solid",(char *)":Data:Models:Body5.solid",(char *)":Data:Models:Body6.solid",(char *)":Data:Models:Body7.solid",(char *)":Data:Models:Bodylow.solid",(char *)":Data:Models:Belt.solid",1);
+                                                                               LoadTextureSave(":Data:Textures:Fur3.jpg",&player[closest].skeleton.drawmodel.textureptr,1,&player[closest].skeleton.skinText[0],&player[closest].skeleton.skinsize);
+                                                                               player[closest].whichskin=0;
+                                                                               player[closest].creature=rabbittype;
+
+                                                                               player[closest].proportionhead=1.2;
+                                                                               player[closest].proportionbody=1.05;
+                                                                               player[closest].proportionarms=1.00;
+                                                                               player[closest].proportionlegs=1.1;
+                                                                               player[closest].proportionlegs.y=1.05;
+                                                                               player[closest].scale=.2*5*player[0].scale;
+
+                                                                               player[closest].damagetolerance=200;
+                                                                       }
+
+                                                                       if(player[closest].creature==wolftype){
+                                                                               player[closest].proportionhead=1.1*headprop;
+                                                                               player[closest].proportionbody=1.1*bodyprop;
+                                                                               player[closest].proportionarms=1.1*armprop;
+                                                                               player[closest].proportionlegs=1.1*legprop;
+                                                                       }
+
+                                                                       if(player[closest].creature==rabbittype){
+                                                                               player[closest].proportionhead=1.2*headprop;
+                                                                               player[closest].proportionbody=1.05*bodyprop;
+                                                                               player[closest].proportionarms=1.00*armprop;
+                                                                               player[closest].proportionlegs=1.1*legprop;
+                                                                               player[closest].proportionlegs.y=1.05*legprop;
+                                                                       }
+
+                                                               }
+                                                               detailtogglekeydown=1;
+                                               }
+
+                                               if(!IsKeyDown(theKeyMap, MAC_X_KEY)){
+                                                       detailtogglekeydown=0;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_B_KEY)&&!slomotogglekeydown&&!IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&debugmode){
+                                                       slomo=1-slomo;
+                                                       slomodelay=1000;
+                                                       slomotogglekeydown=1;
+                                               }
+
+
+                                               if(((IsKeyDown(theKeyMap, MAC_I_KEY)&&!IsKeyDown(theKeyMap, MAC_SHIFT_KEY))/*||buttons[1]*/)&&!explodetogglekeydown&&debugmode){
+                                                       int closest=-1;
+                                                       float closestdist=-1;
+                                                       float distance;
+                                                       XYZ flatfacing2,flatvelocity2;
+                                                       XYZ blah;
+                                                       if(numplayers>1)
+                                                               for(i=1;i<numplayers;i++){
+                                                                       distance=findDistancefast(&player[i].coords,&player[0].coords);
+                                                                       if(distance<144&&!player[i].headless)
+                                                                               if(closestdist==-1||distance<closestdist){
+                                                                                       closestdist=distance;
+                                                                                       closest=i;
+                                                                                       blah = player[i].coords;
+                                                                               }
+                                                               }
+
+                                                               if(closest!=-1){                
+                                                                       XYZ headspurtdirection;
+                                                                       int i = player[closest].skeleton.jointlabels[head];
+                                                                       for(k=0;k<player[closest].skeleton.num_joints; k++){
+                                                                               if(!player[closest].skeleton.free)flatvelocity2=player[closest].velocity;
+                                                                               if(player[closest].skeleton.free)flatvelocity2=player[closest].skeleton.joints[i].velocity;
+                                                                               if(!player[closest].skeleton.free)flatfacing2=DoRotation(DoRotation(DoRotation(player[closest].skeleton.joints[i].position,0,0,player[closest].tilt),player[closest].tilt2,0,0),0,player[closest].rotation,0)*player[closest].scale+player[closest].coords;
+                                                                               if(player[closest].skeleton.free)flatfacing2=player[closest].skeleton.joints[i].position*player[closest].scale+player[closest].coords;
+                                                                               flatvelocity2.x+=(float)(abs(Random()%100)-50)/10;
+                                                                               flatvelocity2.y+=(float)(abs(Random()%100)-50)/10;
+                                                                               flatvelocity2.z+=(float)(abs(Random()%100)-50)/10;
+                                                                               headspurtdirection=player[closest].skeleton.joints[player[closest].skeleton.jointlabels[head]].position-player[closest].skeleton.joints[player[closest].skeleton.jointlabels[neck]].position;
+                                                                               Normalise(&headspurtdirection);
+                                                                               sprites.MakeSprite(bloodflamesprite, flatfacing2,flatvelocity2, 1,1,1, .6, 1);
+                                                                               flatvelocity2+=headspurtdirection*8;
+                                                                               sprites.MakeSprite(bloodsprite, flatfacing2,flatvelocity2/2, 1,1,1, .16, 1);
+                                                                       }
+                                                                       sprites.MakeSprite(cloudsprite, flatfacing2,flatvelocity2*0, .6,0,0, 1, .5);
+
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=blah.x;
+                                                                       gLoc[1]=blah.y;
+                                                                       gLoc[2]=blah.z;
+                                                                       vel[0]=0;
+                                                                       vel[1]=0;
+                                                                       vel[2]=0;
+                                                                       PlaySoundEx( splattersound, samp[splattersound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[splattersound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[splattersound], 256);
+                                                                       FSOUND_SetPaused(channels[splattersound], FALSE);
+
+                                                                       PlaySoundEx( breaksound2, samp[breaksound2], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[breaksound2], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[breaksound2], 100);
+                                                                       FSOUND_SetPaused(channels[breaksound2], FALSE);
+
+                                                                       if(player[closest].skeleton.free==2)player[closest].skeleton.free=0;
+                                                                       player[closest].RagDoll(0);
+                                                                       player[closest].dead=2;
+                                                                       player[closest].headless=1;
+                                                                       player[closest].DoBloodBig(3,165);
+
+                                                                       camerashake+=.3;
+                                                               }
+
+                                                               explodetogglekeydown=1;
+                                               }
+
+                                               if(((IsKeyDown(theKeyMap, MAC_I_KEY)&&IsKeyDown(theKeyMap, MAC_SHIFT_KEY))/*||buttons[2]*/)&&!explodetogglekeydown&&debugmode){
+                                                       int closest=-1;
+                                                       float closestdist=-1;
+                                                       float distance;
+                                                       XYZ flatfacing2,flatvelocity2;
+                                                       XYZ blah;
+                                                       if(numplayers>1)
+                                                               for(i=1;i<numplayers;i++){
+                                                                       distance=findDistancefast(&player[i].coords,&player[0].coords);
+                                                                       if(distance<144)
+                                                                               if(closestdist==-1||distance<closestdist){
+                                                                                       closestdist=distance;
+                                                                                       closest=i;
+                                                                                       blah=player[i].coords;
+                                                                               }
+                                                               }
+
+                                                               if(closest!=-1){                
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=blah.x;
+                                                                       gLoc[1]=blah.y;
+                                                                       gLoc[2]=blah.z;
+                                                                       vel[0]=0;
+                                                                       vel[1]=0;
+                                                                       vel[2]=0;
+
+                                                                       PlaySoundEx( splattersound, samp[splattersound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[splattersound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[splattersound], 256);
+                                                                       FSOUND_SetPaused(channels[splattersound], FALSE);
+
+                                                                       PlaySoundEx( breaksound2, samp[breaksound2], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[breaksound2], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[breaksound2], 600);
+                                                                       FSOUND_SetPaused(channels[breaksound2], FALSE);
+
+                                                                       for(i=0;i<player[closest].skeleton.num_joints; i++){
+                                                                               if(!player[closest].skeleton.free)flatvelocity2=player[closest].velocity;
+                                                                               if(player[closest].skeleton.free)flatvelocity2=player[closest].skeleton.joints[i].velocity;
+                                                                               if(!player[closest].skeleton.free)flatfacing2=DoRotation(DoRotation(DoRotation(player[closest].skeleton.joints[i].position,0,0,player[closest].tilt),player[closest].tilt2,0,0),0,player[closest].rotation,0)*player[closest].scale+player[closest].coords;
+                                                                               if(player[closest].skeleton.free)flatfacing2=player[closest].skeleton.joints[i].position*player[closest].scale+player[closest].coords;
+                                                                               flatvelocity2.x+=(float)(abs(Random()%100)-50)/10;
+                                                                               flatvelocity2.y+=(float)(abs(Random()%100)-50)/10;
+                                                                               flatvelocity2.z+=(float)(abs(Random()%100)-50)/10;
+                                                                               sprites.MakeSprite(bloodflamesprite, flatfacing2,flatvelocity2, 1,1,1, 3, 1);
+                                                                               sprites.MakeSprite(bloodsprite, flatfacing2,flatvelocity2, 1,1,1, .3, 1);
+                                                                               sprites.MakeSprite(cloudsprite, flatfacing2,flatvelocity2*0, .6,0,0, 1, .5);
+                                                                       }
+
+                                                                       for(i=0;i<player[closest].skeleton.num_joints; i++){
+                                                                               if(!player[closest].skeleton.free)flatvelocity2=player[closest].velocity;
+                                                                               if(player[closest].skeleton.free)flatvelocity2=player[closest].skeleton.joints[i].velocity;
+                                                                               if(!player[closest].skeleton.free)flatfacing2=DoRotation(DoRotation(DoRotation(player[closest].skeleton.joints[i].position,0,0,player[closest].tilt),player[closest].tilt2,0,0),0,player[closest].rotation,0)*player[closest].scale+player[closest].coords;
+                                                                               if(player[closest].skeleton.free)flatfacing2=player[closest].skeleton.joints[i].position*player[closest].scale+player[closest].coords;
+                                                                               flatvelocity2.x+=(float)(abs(Random()%100)-50)/10;
+                                                                               flatvelocity2.y+=(float)(abs(Random()%100)-50)/10;
+                                                                               flatvelocity2.z+=(float)(abs(Random()%100)-50)/10;
+                                                                               sprites.MakeSprite(bloodflamesprite, flatfacing2,flatvelocity2, 1,1,1, 3, 1);
+                                                                               sprites.MakeSprite(bloodsprite, flatfacing2,flatvelocity2, 1,1,1, .4, 1);
+                                                                       }
+
+                                                                       for(i=0;i<player[closest].skeleton.num_joints; i++){
+                                                                               if(!player[closest].skeleton.free)flatvelocity2=player[closest].velocity;
+                                                                               if(player[closest].skeleton.free)flatvelocity2=player[closest].skeleton.joints[i].velocity;
+                                                                               if(!player[closest].skeleton.free)flatfacing2=DoRotation(DoRotation(DoRotation(player[closest].skeleton.joints[i].position,0,0,player[closest].tilt),player[closest].tilt2,0,0),0,player[closest].rotation,0)*player[closest].scale+player[closest].coords;
+                                                                               if(player[closest].skeleton.free)flatfacing2=player[closest].skeleton.joints[i].position*player[closest].scale+player[closest].coords;
+                                                                               flatvelocity2.x+=(float)(abs(Random()%100)-50)/10;
+                                                                               flatvelocity2.y+=(float)(abs(Random()%100)-50)/10;
+                                                                               flatvelocity2.z+=(float)(abs(Random()%100)-50)/10;
+                                                                               sprites.MakeSprite(bloodflamesprite, flatfacing2,flatvelocity2*2, 1,1,1, 3, 1);
+                                                                               sprites.MakeSprite(bloodsprite, flatfacing2,flatvelocity2*2, 1,1,1, .4, 1);
+                                                                       }
+
+                                                                       for(i=0;i<player[closest].skeleton.num_joints; i++){
+                                                                               if(!player[closest].skeleton.free)flatvelocity2=player[closest].velocity;
+                                                                               if(player[closest].skeleton.free)flatvelocity2=player[closest].skeleton.joints[i].velocity;
+                                                                               if(!player[closest].skeleton.free)flatfacing2=DoRotation(DoRotation(DoRotation(player[closest].skeleton.joints[i].position,0,0,player[closest].tilt),player[closest].tilt2,0,0),0,player[closest].rotation,0)*player[closest].scale+player[closest].coords;
+                                                                               if(player[closest].skeleton.free)flatfacing2=player[closest].skeleton.joints[i].position*player[closest].scale+player[closest].coords;
+                                                                               flatvelocity2.x+=(float)(abs(Random()%100)-50)/10;
+                                                                               flatvelocity2.y+=(float)(abs(Random()%100)-50)/10;
+                                                                               flatvelocity2.z+=(float)(abs(Random()%100)-50)/10;
+                                                                               sprites.MakeSprite(bloodflamesprite, flatfacing2,flatvelocity2*2, 1,1,1, 3, 1);
+                                                                               sprites.MakeSprite(bloodsprite, flatfacing2,flatvelocity2*2, 1,1,1, .4, 1);
+                                                                       }
+
+                                                                       XYZ temppos;
+                                                                       for(j=0;j<numplayers; j++){
+                                                                               if(j!=closest){
+                                                                                       if(findDistancefast(&player[j].coords,&player[closest].coords)<25){
+                                                                                               player[j].DoDamage((25-findDistancefast(&player[j].coords,&player[closest].coords))*60);
+                                                                                               if(player[j].skeleton.free==2)player[j].skeleton.free=1;
+                                                                                               player[j].skeleton.longdead=0;
+                                                                                               player[j].RagDoll(0);
+                                                                                               for(i=0;i<player[j].skeleton.num_joints; i++){
+                                                                                                       temppos=player[j].skeleton.joints[i].position+player[j].coords;
+                                                                                                       if(findDistancefast(&temppos,&player[closest].coords)<25){
+                                                                                                               flatvelocity2=temppos-player[closest].coords;
+                                                                                                               Normalise(&flatvelocity2);
+                                                                                                               player[j].skeleton.joints[i].velocity+=flatvelocity2*((20-findDistancefast(&temppos,&player[closest].coords))*20);
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+                                                                               }
+                                                                       }
+
+                                                                       player[closest].DoDamage(10000);
+                                                                       player[closest].RagDoll(0);
+                                                                       player[closest].dead=2;
+                                                                       player[closest].coords=20;
+                                                                       player[closest].skeleton.free=2;
+
+                                                                       camerashake+=.6;
+
+                                                               }
+
+                                                               explodetogglekeydown=1;
+                                               }
+
+                                               if(!IsKeyDown(theKeyMap, MAC_I_KEY)){
+                                                       explodetogglekeydown=0;
+                                               }
+
+                                               /*
+                                               if(IsKeyDown(theKeyMap, MAC_S_KEY)&&IsKeyDown(theKeyMap, MAC_COMMAND_KEY)&&!slomotogglekeydown){
+                                               FILE                    *tfile;
+                                               //tfile=fopen( ":Data:Maps:mapsave", "wb" );
+                                               if(whichlevel==0)tfile=fopen( ":Data:Maps:map1", "wb" );
+                                               else if(whichlevel==1)tfile=fopen( ":Data:Maps:map2", "wb" );
+                                               else if(whichlevel==2)tfile=fopen( ":Data:Maps:map3", "wb" );
+                                               else if(whichlevel==3)tfile=fopen( ":Data:Maps:map4", "wb" );
+                                               else if(whichlevel==4)tfile=fopen( ":Data:Maps:map5", "wb" );
+                                               else tfile=fopen( ":Data:Maps:mapsave", "wb" );
+
+                                               fwrite( &player[0].coords, 1, sizeof(XYZ), tfile );
+                                               fwrite( &player[0].rotation, 1, sizeof(float), tfile );
+                                               fwrite( &player[0].targetrotation, 1, sizeof(float), tfile );
+                                               fwrite( &player[0].num_weapons, 1, sizeof(int), tfile );
+                                               for(j=0;j<player[0].num_weapons;j++){
+                                               fwrite( &weapons.type[player[0].weaponids[j]], 1, sizeof(int), tfile );
+                                               }
+                                               fwrite( &environment, 1, sizeof(int), tfile );
+
+                                               fwrite( &objects.numobjects, 1, sizeof(int), tfile );
+                                               fwrite( &objects.type, 1, sizeof(int)*objects.numobjects, tfile );
+                                               fwrite( &objects.rotation, 1, sizeof(float)*objects.numobjects, tfile );
+                                               fwrite( &objects.position, 1, sizeof(XYZ)*objects.numobjects, tfile );
+                                               fwrite( &objects.scale, 1, sizeof(float)*objects.numobjects, tfile );
+
+                                               fwrite( &numplayers, 1, sizeof(int), tfile );
+                                               if(numplayers>1&&numplayers<maxplayers)
+                                               for(i=1;i<numplayers;i++){
+                                               fwrite( &player[i].coords, 1, sizeof(XYZ), tfile );
+                                               fwrite( &player[i].num_weapons, 1, sizeof(int), tfile );
+                                               for(j=0;j<player[i].num_weapons;j++){
+                                               fwrite( &weapons.type[player[i].weaponids[j]], 1, sizeof(int), tfile );
+                                               }
+                                               if(player[i].numwaypoints<30){
+                                               fwrite( &player[i].numwaypoints, 1, sizeof(int), tfile );
+                                               fwrite( &player[i].waypoints, 1, sizeof(XYZ)*player[i].numwaypoints, tfile );
+                                               fwrite( &player[i].waypoint, 1, sizeof(int), tfile );
+                                               //fwrite( &player[i].jumppath, 1, sizeof(bool), tfile );
+                                               }
+                                               else{
+                                               player[i].numwaypoints=0;
+                                               player[i].waypoint=0;
+                                               fwrite( &player[i].numwaypoints, 1, sizeof(int), tfile );
+                                               fwrite( &player[i].waypoint, 1, sizeof(int), tfile );
+                                               fwrite( &player[i].waypoint, 1, sizeof(int), tfile );
+                                               }
+                                               }
+
+                                               fclose(tfile);
+
+                                               slomotogglekeydown=1;
+                                               }*/
+
+                                               if(!IsKeyDown(theKeyMap, MAC_B_KEY)&&!IsKeyDown(theKeyMap, MAC_F_KEY)&&!IsKeyDown(theKeyMap, MAC_K_KEY)&&!IsKeyDown(theKeyMap, MAC_S_KEY)){
+                                                       slomotogglekeydown=0;
+                                               }
+
+
+                                               if(IsKeyDown(theKeyMap, MAC_F_KEY)&&!slomotogglekeydown&&debugmode){
+                                                       player[0].onfire=1-player[0].onfire;
+                                                       if(player[0].onfire){
+                                                               player[0].CatchFire();
+                                                       }
+                                                       if(!player[0].onfire){
+                                                               float gLoc[3];
+                                                               float vel[3];
+                                                               gLoc[0]=player[0].coords.x;
+                                                               gLoc[1]=player[0].coords.y;
+                                                               gLoc[2]=player[0].coords.z;
+                                                               vel[0]=0;
+                                                               vel[1]=0;
+                                                               vel[2]=0;
+                                                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[fireendsound], 256);
+                                                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                                                               FSOUND_SetPaused(channels[stream_firesound], TRUE);
+                                                       }
+                                                       slomotogglekeydown=1;
+                                               }
+                                               /*
+                                               if(IsKeyDown(theKeyMap, MAC_L_KEY)){
+                                               if(player[0].bleeding<=0)
+                                               player[0].DoBlood(1,255);
+                                               }*/
+
+
+                                               if(IsKeyDown(theKeyMap, MAC_DELETE_KEY)&&editorenabled&&!drawmodetogglekeydown&&IsKeyDown(theKeyMap, MAC_SHIFT_KEY)){
+                                                       int closest=-1;
+                                                       float closestdist=-1;
+                                                       float distance;
+                                                       if(numplayers>1)
+                                                               for(i=1;i<numplayers;i++){
+                                                                       distance=findDistancefast(&player[i].coords,&player[0].coords);
+                                                                       if(closestdist==-1||distance<closestdist){
+                                                                               closestdist=distance;
+                                                                               closest=i;
+                                                                       }
+                                                               }
+                                                               if(closestdist>0&&closest>=0){
+                                                                       //player[closest]=player[numplayers-1];
+                                                                       //player[closest].skeleton=player[numplayers-1].skeleton;
+                                                                       numplayers--;
+                                                               }
+                                                               drawmodetogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_DELETE_KEY)&&editorenabled&&!drawmodetogglekeydown&&IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                                       int closest=-1;
+                                                       float closestdist=-1;
+                                                       float distance;
+                                                       if(max_objects>1)
+                                                               for(i=1;i<max_objects;i++){
+                                                                       distance=findDistancefast(&objects.position[i],&player[0].coords);
+                                                                       if(closestdist==-1||distance<closestdist){
+                                                                               closestdist=distance;
+                                                                               closest=i;
+                                                                       }
+                                                               }
+                                                               if(closestdist>0&&closest>=0){
+                                                                       objects.position[closest].y-=500;
+                                                               }
+                                                               drawmodetogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_M_KEY)&&!drawmodetogglekeydown&&!IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&editorenabled&&debugmode){
+                                                       //drawmode++;
+                                                       //if(drawmode>2)drawmode=0;
+                                                       if(objects.numobjects<max_objects-1){                   
+                                                               XYZ boxcoords;
+                                                               boxcoords.x=player[0].coords.x;
+                                                               boxcoords.z=player[0].coords.z;
+                                                               boxcoords.y=player[0].coords.y-3;
+                                                               if(editortype==bushtype)boxcoords.y=player[0].coords.y-.5;
+                                                               if(editortype==firetype)boxcoords.y=player[0].coords.y-.5;
+                                                               //objects.MakeObject(abs(Random()%3),boxcoords,Random()%360);
+                                                               float temprotat,temprotat2;
+                                                               temprotat=editorrotation;
+                                                               temprotat2=editorrotation2;
+                                                               if(temprotat<0||editortype==bushtype)temprotat=Random()%360;
+                                                               if(temprotat2<0)temprotat2=Random()%360;
+
+                                                               objects.MakeObject(editortype,boxcoords,(int)temprotat-((int)temprotat)%30,(int)temprotat2,editorsize);
+                                                               if(editortype==treetrunktype)
+                                                                       objects.MakeObject(treeleavestype,boxcoords,Random()%360*(temprotat2<2)+(int)editorrotation-((int)editorrotation)%30,editorrotation2,editorsize);
+                                                       }
+
+                                                       drawmodetogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_P_KEY)&&!drawmodetogglekeydown&&!IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&!IsKeyDown(theKeyMap, MAC_CONTROL_KEY)&&editorenabled){
+                                                       if(numplayers<maxplayers-1){
+                                                               player[numplayers].scale=.2*5*player[0].scale;
+                                                               player[numplayers].creature=rabbittype;
+                                                               player[numplayers].howactive=editoractive;
+                                                               player[numplayers].skeleton.id=numplayers;
+                                                               player[numplayers].skeleton.Load((char *)":Data:Skeleton:Basic Figure",(char *)":Data:Skeleton:Basic Figurelow",(char *)":Data:Skeleton:Rabbitbelt",(char *)":Data:Models:Body.solid",(char *)":Data:Models:Body2.solid",(char *)":Data:Models:Body3.solid",(char *)":Data:Models:Body4.solid",(char *)":Data:Models:Body5.solid",(char *)":Data:Models:Body6.solid",(char *)":Data:Models:Body7.solid",(char *)":Data:Models:Bodylow.solid",(char *)":Data:Models:Belt.solid",1);
+
+                                                               //texsize=512*512*3/texdetail/texdetail;
+                                                               //if(!player[numplayers].loaded)player[numplayers].skeleton.skinText = new GLubyte[texsize];
+                                                               //player[numplayers].skeleton.skinText.resize(texsize);
+
+                                                               k=abs(Random()%2)+1;
+                                                               if(k==0){
+                                                                       LoadTextureSave(":Data:Textures:Fur3.jpg",&player[numplayers].skeleton.drawmodel.textureptr,1,&player[numplayers].skeleton.skinText[0],&player[numplayers].skeleton.skinsize);
+                                                                       player[numplayers].whichskin=0;
+                                                               }
+                                                               else if(k==1){
+                                                                       LoadTextureSave(":Data:Textures:Fur.jpg",&player[numplayers].skeleton.drawmodel.textureptr,1,&player[numplayers].skeleton.skinText[0],&player[numplayers].skeleton.skinsize);
+                                                                       player[numplayers].whichskin=1;
+                                                               }
+                                                               else {
+                                                                       LoadTextureSave(":Data:Textures:Fur2.jpg",&player[numplayers].skeleton.drawmodel.textureptr,1,&player[numplayers].skeleton.skinText[0],&player[numplayers].skeleton.skinsize);
+                                                                       player[numplayers].whichskin=2;
+                                                               }
+
+                                                               LoadTexture(":Data:Textures:Belt.png",&player[numplayers].skeleton.drawmodelclothes.textureptr,1,1);
+                                                               player[numplayers].power=1;
+                                                               player[numplayers].speedmult=1;
+                                                               player[numplayers].currentanimation=bounceidleanim;
+                                                               player[numplayers].targetanimation=bounceidleanim;
+                                                               player[numplayers].currentframe=0;
+                                                               player[numplayers].targetframe=1;
+                                                               player[numplayers].target=0;
+                                                               player[numplayers].bled=0;
+                                                               player[numplayers].speed=1+(float)(Random()%100)/1000;
+
+                                                               player[numplayers].targetrotation=player[0].targetrotation;
+                                                               player[numplayers].rotation=player[0].rotation;
+
+                                                               player[numplayers].velocity=0;
+                                                               player[numplayers].coords=player[0].coords;
+                                                               player[numplayers].oldcoords=player[numplayers].coords;
+                                                               player[numplayers].realoldcoords=player[numplayers].coords;
+
+                                                               player[numplayers].id=numplayers;
+                                                               player[numplayers].skeleton.id=numplayers;
+                                                               player[numplayers].updatedelay=0;
+                                                               player[numplayers].normalsupdatedelay=0;
+
+                                                               player[numplayers].aitype=passivetype;
+                                                               player[numplayers].aitarget=0;
+
+                                                               if(player[0].creature==wolftype){
+                                                                       headprop=player[0].proportionhead.x/1.1;
+                                                                       bodyprop=player[0].proportionbody.x/1.1;
+                                                                       armprop=player[0].proportionarms.x/1.1;
+                                                                       legprop=player[0].proportionlegs.x/1.1;
+                                                               }
+
+                                                               if(player[0].creature==rabbittype){
+                                                                       headprop=player[0].proportionhead.x/1.2;
+                                                                       bodyprop=player[0].proportionbody.x/1.05;
+                                                                       armprop=player[0].proportionarms.x/1.00;
+                                                                       legprop=player[0].proportionlegs.x/1.1;
+                                                               }
+
+                                                               if(player[numplayers].creature==wolftype){
+                                                                       player[numplayers].proportionhead=1.1*headprop;
+                                                                       player[numplayers].proportionbody=1.1*bodyprop;
+                                                                       player[numplayers].proportionarms=1.1*armprop;
+                                                                       player[numplayers].proportionlegs=1.1*legprop;
+                                                               }
+
+                                                               if(player[numplayers].creature==rabbittype){
+                                                                       player[numplayers].proportionhead=1.2*headprop;
+                                                                       player[numplayers].proportionbody=1.05*bodyprop;
+                                                                       player[numplayers].proportionarms=1.00*armprop;
+                                                                       player[numplayers].proportionlegs=1.1*legprop;
+                                                                       player[numplayers].proportionlegs.y=1.05*legprop;
+                                                               }
+
+                                                               player[numplayers].headless=0;
+                                                               player[numplayers].onfire=0;
+
+                                                               if(cellophane){
+                                                                       player[numplayers].proportionhead.z=0;
+                                                                       player[numplayers].proportionbody.z=0;
+                                                                       player[numplayers].proportionarms.z=0;
+                                                                       player[numplayers].proportionlegs.z=0;
+                                                               }
+
+                                                               player[numplayers].tempanimation.Load((char *)":Data:Animations:Tempanim",0,0);
+
+                                                               player[numplayers].damagetolerance=200;
+
+                                                               player[numplayers].protectionhead=player[0].protectionhead;
+                                                               player[numplayers].protectionhigh=player[0].protectionhigh;
+                                                               player[numplayers].protectionlow=player[0].protectionlow;
+                                                               player[numplayers].armorhead=player[0].armorhead;
+                                                               player[numplayers].armorhigh=player[0].armorhigh;
+                                                               player[numplayers].armorlow=player[0].armorlow;
+                                                               player[numplayers].metalhead=player[0].metalhead;
+                                                               player[numplayers].metalhigh=player[0].metalhigh;
+                                                               player[numplayers].metallow=player[0].metallow;
+
+                                                               player[numplayers].immobile=player[0].immobile;
+
+                                                               player[numplayers].numclothes=player[0].numclothes;
+                                                               if(player[numplayers].numclothes)
+                                                                       for(i=0;i<player[numplayers].numclothes;i++){
+                                                                               strcpy(player[numplayers].clothes[i], player[0].clothes[i]);
+                                                                               player[numplayers].clothestintr[i]=player[0].clothestintr[i];
+                                                                               player[numplayers].clothestintg[i]=player[0].clothestintg[i];
+                                                                               player[numplayers].clothestintb[i]=player[0].clothestintb[i];
+                                                                               tintr=player[numplayers].clothestintr[i];
+                                                                               tintg=player[numplayers].clothestintg[i];
+                                                                               tintb=player[numplayers].clothestintb[i];
+                                                                               AddClothes((char *)player[numplayers].clothes[i],0,1,&player[numplayers].skeleton.skinText[0],&player[numplayers].skeleton.skinsize);
+                                                                       }
+                                                                       if(player[numplayers].numclothes){
+                                                                               player[numplayers].DoMipmaps(5,0,0,player[numplayers].skeleton.skinsize,player[numplayers].skeleton.skinsize);
+                                                                       }
+
+                                                                       player[numplayers].power=player[0].power;
+                                                                       player[numplayers].speedmult=player[0].speedmult;
+
+                                                                       player[numplayers].damage=0;
+                                                                       player[numplayers].permanentdamage=0;
+                                                                       player[numplayers].superpermanentdamage=0;
+                                                                       player[numplayers].deathbleeding=0;
+                                                                       player[numplayers].bleeding=0;
+                                                                       player[numplayers].numwaypoints=0;
+                                                                       player[numplayers].waypoint=0;
+                                                                       player[numplayers].jumppath=0;
+                                                                       player[numplayers].weaponstuck=-1;
+                                                                       player[numplayers].weaponactive=-1;
+                                                                       player[numplayers].num_weapons=0;
+                                                                       player[numplayers].bloodloss=0;
+                                                                       player[numplayers].dead=0;
+
+                                                                       player[numplayers].loaded=1;
+
+                                                                       numplayers++;
+                                                       }
+                                                       drawmodetogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_P_KEY)&&!drawmodetogglekeydown&&IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&editorenabled){
+                                                       if(player[numplayers-1].numwaypoints<90){
+                                                               player[numplayers-1].waypoints[player[numplayers-1].numwaypoints]=player[0].coords;
+                                                               player[numplayers-1].waypointtype[player[numplayers-1].numwaypoints]=editorpathtype;
+                                                               player[numplayers-1].numwaypoints++;
+                                                       }
+                                                       drawmodetogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_P_KEY)&&!drawmodetogglekeydown&&IsKeyDown(theKeyMap, MAC_CONTROL_KEY)&&editorenabled){
+                                                       if(numpathpoints<30){
+                                                               bool connected,alreadyconnected;
+                                                               connected=0;
+                                                               if(numpathpoints>1)
+                                                                       for(i=0;i<numpathpoints;i++){
+                                                                               if(findDistancefast(&pathpoint[i],&player[0].coords)<.5&&i!=pathpointselected&&!connected){
+                                                                                       alreadyconnected=0;
+                                                                                       for(j=0;j<numpathpointconnect[pathpointselected];j++){
+                                                                                               if(pathpointconnect[pathpointselected][j]==i)alreadyconnected=1;
+                                                                                       }
+                                                                                       if(!alreadyconnected){
+                                                                                               numpathpointconnect[pathpointselected]++;
+                                                                                               connected=1;
+                                                                                               pathpointconnect[pathpointselected][numpathpointconnect[pathpointselected]-1]=i;
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                                       if(!connected){
+                                                                               numpathpoints++;
+                                                                               pathpoint[numpathpoints-1]=player[0].coords;
+                                                                               numpathpointconnect[numpathpoints-1]=0;
+                                                                               if(numpathpoints>1&&pathpointselected!=-1){
+                                                                                       numpathpointconnect[pathpointselected]++;
+                                                                                       pathpointconnect[pathpointselected][numpathpointconnect[pathpointselected]-1]=numpathpoints-1;
+                                                                               }
+                                                                               pathpointselected=numpathpoints-1;
+                                                                       }
+                                                       }
+                                                       drawmodetogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_PERIOD_KEY)&&!drawmodetogglekeydown&&editorenabled){
+                                                       pathpointselected++;
+                                                       if(pathpointselected>=numpathpoints)pathpointselected=-1;
+                                                       drawmodetogglekeydown=1;
+                                               }
+                                               if(IsKeyDown(theKeyMap, MAC_COMMA_KEY)&&!IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&!drawmodetogglekeydown&&editorenabled){
+                                                       pathpointselected--;
+                                                       if(pathpointselected<=-2)pathpointselected=numpathpoints-1;
+                                                       drawmodetogglekeydown=1;
+                                               }
+                                               if(IsKeyDown(theKeyMap, MAC_COMMA_KEY)&&IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&!drawmodetogglekeydown&&editorenabled){
+                                                       if(pathpointselected!=-1){
+                                                               numpathpoints--;
+                                                               pathpoint[pathpointselected]=pathpoint[numpathpoints];
+                                                               numpathpointconnect[pathpointselected]=numpathpointconnect[numpathpoints];
+                                                               for(i=0;i<numpathpointconnect[pathpointselected];i++){
+                                                                       pathpointconnect[pathpointselected][i]=pathpointconnect[numpathpoints][i];
+                                                               }
+                                                               for(i=0;i<numpathpoints;i++){
+                                                                       for(j=0;j<numpathpointconnect[i];j++){
+                                                                               if(pathpointconnect[i][j]==pathpointselected){
+                                                                                       pathpointconnect[i][j]=pathpointconnect[i][numpathpointconnect[i]-1];
+                                                                                       numpathpointconnect[i]--;
+                                                                               }
+                                                                               if(pathpointconnect[i][j]==numpathpoints){
+                                                                                       pathpointconnect[i][j]=pathpointselected;
+                                                                               }
+                                                                       }
+                                                               }
+                                                               pathpointselected=numpathpoints-1;
+                                                       }
+                                                       drawmodetogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_M_KEY)&&!drawmodetogglekeydown&&IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&debugmode){
+                                                       editorenabled=1-editorenabled;
+                                                       if(editorenabled){
+                                                               player[0].damagetolerance=100000;
+                                                               player[0].damage=0;
+                                                               player[0].superpermanentdamage=0;
+                                                               player[0].bloodloss=0;
+                                                               player[0].deathbleeding=0;
+                                                       }
+                                                       if(!editorenabled){
+                                                               player[0].damagetolerance=200;
+                                                               player[0].damage=0;
+                                                               player[0].permanentdamage=0;
+                                                               player[0].superpermanentdamage=0;
+                                                               player[0].bloodloss=0;
+                                                               player[0].deathbleeding=0;
+                                                       }
+                                                       drawmodetogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_ARROW_LEFT_KEY)&&!drawmodetogglekeydown&&editorenabled&&IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&!IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                                       editortype--;
+                                                       if(editortype==treeleavestype||editortype==10)editortype--;
+                                                       if(editortype<0)editortype=firetype;
+                                                       drawmodetogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_ARROW_RIGHT_KEY)&&!drawmodetogglekeydown&&editorenabled&&IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&!IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                                       editortype++;
+                                                       if(editortype==treeleavestype||editortype==10)editortype++;
+                                                       if(editortype>firetype)editortype=0;
+                                                       drawmodetogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_ARROW_LEFT_KEY)&&editorenabled&&!IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&!IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                                       editorrotation-=multiplier*100;
+                                                       if(editorrotation<-.01)editorrotation=-.01;
+                                                       drawmodetogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_ARROW_RIGHT_KEY)&&editorenabled&&!IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&!IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                                       editorrotation+=multiplier*100;
+                                                       drawmodetogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_ARROW_UP_KEY)&&editorenabled&&!IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                                       editorsize+=multiplier;
+                                                       drawmodetogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_ARROW_DOWN_KEY)&&editorenabled&&!IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                                       editorsize-=multiplier;
+                                                       if(editorsize<.1)editorsize=.1;
+                                                       drawmodetogglekeydown=1;
+                                               }
+
+
+                                               if(IsKeyDown(theKeyMap, MAC_ARROW_LEFT_KEY)&&!drawmodetogglekeydown&&editorenabled&&IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                                       mapradius-=multiplier*10;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_ARROW_RIGHT_KEY)&&!drawmodetogglekeydown&&editorenabled&&IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                                       mapradius+=multiplier*10;
+                                               }
+                                               /*
+                                               if(IsKeyDown(theKeyMap, MAC_ARROW_LEFT_KEY)&&editorenabled&&!IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                               mapcenter.x+=multiplier*20;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_ARROW_RIGHT_KEY)&&editorenabled&&!IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                               mapcenter.x-=multiplier*20;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_ARROW_UP_KEY)&&editorenabled&&IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                               mapcenter.z+=multiplier*20;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_ARROW_DOWN_KEY)&&editorenabled&&IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                               mapcenter.z-=multiplier*20;
+                                               }
+                                               */
+                                               if(IsKeyDown(theKeyMap, MAC_ARROW_UP_KEY)&&editorenabled&&IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                                       editorrotation2+=multiplier*100;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_ARROW_DOWN_KEY)&&editorenabled&&IsKeyDown(theKeyMap, MAC_CONTROL_KEY)){
+                                                       editorrotation2-=multiplier*100;
+                                                       if(editorrotation2<-.01)editorrotation2=-.01;
+                                               }
+                                               if(IsKeyDown(theKeyMap, MAC_DELETE_KEY)&&editorenabled&&objects.numobjects&&!drawmodetogglekeydown&&!IsKeyDown(theKeyMap, MAC_SHIFT_KEY)){
+                                                       int closest=-1;
+                                                       float closestdist=-1;
+                                                       float distance;
+                                                       for(i=0;i<objects.numobjects;i++){
+                                                               distance=findDistancefast(&objects.position[i],&player[0].coords);
+                                                               if(closestdist==-1||distance<closestdist){
+                                                                       closestdist=distance;
+                                                                       closest=i;
+                                                               }
+                                                       }
+                                                       if(closestdist>0&&closest>=0)objects.DeleteObject(closest);             
+                                                       drawmodetogglekeydown=1;
+                                               }
+
+
+                                               if(!IsKeyDown(theKeyMap, MAC_M_KEY)&&!IsKeyDown(theKeyMap, MAC_ARROW_LEFT_KEY)&&!IsKeyDown(theKeyMap, MAC_COMMA_KEY)&&!IsKeyDown(theKeyMap, MAC_PERIOD_KEY)&&!IsKeyDown(theKeyMap, MAC_ARROW_RIGHT_KEY)&&!IsKeyDown(theKeyMap, MAC_DELETE_KEY)&&!IsKeyDown(theKeyMap, MAC_P_KEY)){
+                                                       drawmodetogglekeydown=0;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_N_KEY)&&!IsKeyDown(theKeyMap, MAC_CONTROL_KEY)&&!texturesizetogglekeydown&&debugmode){
+                                                       //if(!player[0].skeleton.free)player[0].damage+=500;
+                                                       player[0].RagDoll(0);
+                                                       //player[0].spurt=1;
+                                                       //player[0].DoDamage(1000);
+
+                                                       float gLoc[3];
+                                                       float vel[3];
+                                                       gLoc[0]=player[0].coords.x;
+                                                       gLoc[1]=player[0].coords.y;
+                                                       gLoc[2]=player[0].coords.z;
+                                                       vel[0]=player[0].velocity.x;
+                                                       vel[1]=player[0].velocity.y;
+                                                       vel[2]=player[0].velocity.z;
+                                                       PlaySoundEx( whooshsound, samp[whooshsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[whooshsound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[whooshsound], 128);
+                                                       FSOUND_SetPaused(channels[whooshsound], FALSE);
+                                                       //FSOUND_SetPaused(channels[whooshsound], TRUE);
+
+                                                       texturesizetogglekeydown=1;
+                                               }
+
+                                               if(IsKeyDown(theKeyMap, MAC_N_KEY)&&IsKeyDown(theKeyMap, MAC_CONTROL_KEY)&&!texturesizetogglekeydown&&debugmode){
+
+                                                       int closest=-1;
+                                                       float closestdist=-1;
+                                                       float distance;
+                                                       for(i=0;i<objects.numobjects;i++){
+                                                               if(objects.type[i]==treeleavestype){
+                                                                       objects.scale[i]*=.9;
+                                                               }
+                                                       }
+                                                       texturesizetogglekeydown=1;
+                                               }
+
+                                               static XYZ relative;
+                                               static int randattack;
+                                               //Attack
+                                               static bool playerrealattackkeydown=0;
+
+                                               if(!buttons[0])oldbutton=0;
+                                               if(!IsKeyDown(theKeyMap, attackkey))oldattackkey=0;
+                                               if(oldattackkey)player[0].attackkeydown=0;
+                                               if(oldattackkey)playerrealattackkeydown=0;
+                                               if(!oldattackkey)playerrealattackkeydown=IsKeyDown(theKeyMap, attackkey);
+                                               if((player[0].parriedrecently<=0||player[0].weaponactive==-1)&&(!oldattackkey||(realthreat&&player[0].lastattack!=swordslashanim&&player[0].lastattack!=knifeslashstartanim&&player[0].lastattack!=staffhitanim&&player[0].lastattack!=staffspinhitanim)))player[0].attackkeydown=IsKeyDown(theKeyMap, attackkey);
+                                               if(IsKeyDown(theKeyMap, attackkey)&&!oldattackkey&&!player[0].backkeydown){
+                                                       for(k=0;k<numplayers;k++){
+                                                               if((player[k].targetanimation==swordslashanim||player[k].targetanimation==staffhitanim||player[k].targetanimation==staffspinhitanim)&&player[0].currentanimation!=dodgebackanim&&!player[k].skeleton.free)
+                                                                       player[k].Reverse();
+                                                       }
+                                               }
+
+                                               if(!hostile||indialogue!=-1)player[0].attackkeydown=0;
+
+                                               for(k=0;k<numplayers;k++){
+                                                       if(indialogue!=-1)player[k].attackkeydown=0;
+                                                       if(player[k].targetanimation!=rabbitrunninganim&&player[k].targetanimation!=wolfrunninganim){
+                                                               if(player[k].aitype!=playercontrolled)player[k].victim=&player[0];
+                                                               if(player[k].attackkeydown&&player[k].jumppower<=1&&player[k].backkeydown&&player[k].targetanimation!=backhandspringanim&&(player[k].isIdle()||player[k].isStop()||player[k].isRun()||player[k].targetanimation==walkanim)){
+                                                                       player[k].jumppower-=2;
+                                                               }
+                                                               if(player[k].attackkeydown&&player[k].jumppower>1&&player[k].backkeydown&&player[k].targetanimation!=backhandspringanim&&(player[k].isIdle()||player[k].isStop()||player[k].isRun()||player[k].targetanimation==walkanim)){
+                                                                       for(i=0;i<numplayers;i++){
+                                                                               if(i==k)i++;
+                                                                               if(player[i].targetanimation==swordslashanim||player[i].targetanimation==knifeslashstartanim||player[i].targetanimation==staffhitanim||player[i].targetanimation==staffspinhitanim)
+                                                                                       if(findDistancefast(&player[k].coords,&player[i].coords)<6.5&&!player[i].skeleton.free){
+                                                                                               player[k].targetanimation=dodgebackanim;
+                                                                                               player[k].target=0;
+                                                                                               player[k].targetframe=0;
+                                                                                               rotatetarget=player[i].coords-player[k].coords;
+                                                                                               Normalise(&rotatetarget);
+                                                                                               player[k].targetrotation=-asin(0-rotatetarget.x);
+                                                                                               player[k].targetrotation*=360/6.28;
+                                                                                               if(rotatetarget.z<0)player[k].targetrotation=180-player[k].targetrotation;
+
+                                                                                               player[k].targettilt2=-asin(rotatetarget.y)*360/6.28;
+                                                                                       }
+                                                                       }
+                                                                       if(player[k].targetanimation!=dodgebackanim){
+                                                                               if(k==0)numflipped++;
+                                                                               player[k].targetanimation=backhandspringanim;
+                                                                               player[k].target=0;
+                                                                               player[k].targetframe=0;
+                                                                               player[k].targetrotation=-rotation+180;
+                                                                               if(player[k].leftkeydown)player[k].targetrotation-=45;
+                                                                               if(player[k].rightkeydown)player[k].targetrotation+=45;
+                                                                               player[k].rotation=player[k].targetrotation;
+                                                                               player[k].jumppower-=2;
+                                                                       }
+                                                               }
+                                                               if(player[k].attackkeydown&&!animation[player[k].targetanimation].attack&&!player[k].backkeydown&&(player[k].isIdle()||player[k].isRun()||player[k].targetanimation==walkanim||player[k].targetanimation==sneakanim||player[k].isCrouch())){
+                                                                       player[k].hasvictim=0;
+                                                                       if(numplayers>1)
+                                                                               for(i=0;i<numplayers;i++){
+                                                                                       if(i==k)i++;
+                                                                                       if(!player[k].hasvictim)
+                                                                                               if((k==0||i==0)&&i!=k&&i<numplayers&&k<numplayers&&animation[player[k].targetanimation].attack!=reversal){      
+                                                                                                       if(findDistancefast(&player[k].coords,&player[i].coords)<4.5&&!player[i].skeleton.free&&player[i].howactive<typedead1&&player[i].targetanimation!=jumpreversedanim&&player[i].targetanimation!=rabbitkickreversedanim&&player[i].targetanimation!=rabbitkickanim&&player[k].targetanimation!=rabbitkickanim&&player[i].targetanimation!=getupfrombackanim&&(player[i].targetanimation!=staggerbackhighanim&&(player[i].targetanimation!=staggerbackhardanim||animation[staggerbackhardanim].label[player[i].targetframe]==6))&&player[i].targetanimation!=jumpdownanim&&player[i].targetanimation!=jumpupanim&&player[i].targetanimation!=getupfromfrontanim){
+                                                                                                               player[k].victim=&player[i];
+                                                                                                               player[k].hasvictim=1;
+                                                                                                               if(player[k].aitype==playercontrolled){
+                                                                                                                       if(findDistancefast(&player[k].coords,&player[i].coords)<2.5*(player[k].scale*5)*(player[k].scale*5)&&player[k].crouchkeydown&&animation[player[i].targetanimation].height!=lowheight)player[k].targetanimation=sweepanim;
+                                                                                                                       else if(findDistancefast(&player[k].coords,&player[i].coords)<1.5*(player[k].scale*5)*(player[k].scale*5)&&animation[player[i].targetanimation].height!=lowheight&&!player[k].forwardkeydown&&!player[k].leftkeydown&&!player[k].rightkeydown&&!player[k].crouchkeydown&&player[k].weaponactive==-1&&!reversaltrain)player[k].targetanimation=winduppunchanim;
+                                                                                                                       else if(findDistancefast(&player[k].coords,&player[i].coords)<2.5*(player[k].scale*5)*(player[k].scale*5)&&animation[player[i].targetanimation].height!=lowheight&&!player[k].forwardkeydown&&!player[k].leftkeydown&&!player[k].rightkeydown&&!player[k].crouchkeydown&&player[k].weaponactive==-1)player[k].targetanimation=upunchanim;
+                                                                                                                       else if(findDistancefast(&player[k].coords,&player[i].coords)<2.5*(player[k].scale*5)*(player[k].scale*5)&&player[k].weaponactive!=-1&&player[i].staggerdelay>0&&weapons.type[player[k].weaponids[player[k].weaponactive]]==knife&&player[i].bloodloss>player[i].damagetolerance/2)player[k].targetanimation=knifefollowanim;
+                                                                                                                       else if(findDistancefast(&player[k].coords,&player[i].coords)<2.5*(player[k].scale*5)*(player[k].scale*5)&&animation[player[i].targetanimation].height!=lowheight&&!player[k].forwardkeydown&&!player[k].leftkeydown&&!player[k].rightkeydown&&!player[k].crouchkeydown&&player[k].weaponactive!=-1&&weapons.type[player[k].weaponids[player[k].weaponactive]]==knife&&player[k].weaponmissdelay<=0)player[k].targetanimation=knifeslashstartanim;
+                                                                                                                       else if(findDistancefast(&player[k].coords,&player[i].coords)<4.5*(player[k].scale*5)*(player[k].scale*5)&&animation[player[i].targetanimation].height!=lowheight&&!player[k].crouchkeydown&&player[k].weaponactive!=-1&&weapons.type[player[k].weaponids[player[k].weaponactive]]==sword&&player[k].weaponmissdelay<=0)player[k].targetanimation=swordslashanim;
+                                                                                                                       else if(findDistancefast(&player[k].coords,&player[i].coords)<4.5*(player[k].scale*5)*(player[k].scale*5)&&animation[player[i].targetanimation].height!=lowheight&&!player[k].crouchkeydown&&player[k].weaponactive!=-1&&weapons.type[player[k].weaponids[player[k].weaponactive]]==staff&&player[k].weaponmissdelay<=0&&!player[k].leftkeydown&&!player[k].rightkeydown&&!player[k].forwardkeydown)player[k].targetanimation=staffhitanim;
+                                                                                                                       else if(findDistancefast(&player[k].coords,&player[i].coords)<4.5*(player[k].scale*5)*(player[k].scale*5)&&animation[player[i].targetanimation].height!=lowheight&&!player[k].crouchkeydown&&player[k].weaponactive!=-1&&weapons.type[player[k].weaponids[player[k].weaponactive]]==staff&&player[k].weaponmissdelay<=0)player[k].targetanimation=staffspinhitanim;
+                                                                                                                       else if(findDistancefast(&player[k].coords,&player[i].coords)<2.5*(player[k].scale*5)*(player[k].scale*5)&&animation[player[i].targetanimation].height!=lowheight)player[k].targetanimation=spinkickanim;
+                                                                                                                       else if(findDistancefast(&player[k].coords,&player[i].coords)<2.5*(player[k].scale*5)*(player[k].scale*5)&&animation[player[i].targetanimation].height==lowheight&&animation[player[k].targetanimation].attack!=normalattack)player[k].targetanimation=lowkickanim;
+                                                                                                               }
+                                                                                                               else {
+                                                                                                                       if(findDistancefast(&player[k].coords,&player[i].coords)<4.5*(player[k].scale*5)*(player[k].scale*5)){
+                                                                                                                               if(player[k].weaponactive==-1)randattack=abs(Random()%5);
+                                                                                                                               else randattack=abs(Random()%5);
+                                                                                                                               if(player[k].weaponactive==-1&&findDistancefast(&player[k].coords,&player[i].coords)<2.5*(player[k].scale*5)*(player[k].scale*5)){
+                                                                                                                                       if(randattack==0&&animation[player[i].targetanimation].height!=lowheight)player[k].targetanimation=sweepanim;
+                                                                                                                                       else if(randattack==1&&animation[player[i].targetanimation].height!=lowheight&&player[k].weaponactive==-1)player[k].targetanimation=upunchanim;
+                                                                                                                                       else if(randattack==2&&animation[player[i].targetanimation].height!=lowheight)player[k].targetanimation=spinkickanim;
+                                                                                                                                       else if(animation[player[i].targetanimation].height==lowheight)player[k].targetanimation=lowkickanim;
+                                                                                                                               }
+                                                                                                                               if(player[k].weaponactive!=-1){
+                                                                                                                                       if((tutoriallevel!=1||player[k].weaponactive==-1)&&findDistancefast(&player[k].coords,&player[i].coords)<2.5*(player[k].scale*5)*(player[k].scale*5)&&randattack==0&&animation[player[i].targetanimation].height!=lowheight)player[k].targetanimation=sweepanim;
+                                                                                                                                       else if(findDistancefast(&player[k].coords,&player[i].coords)<2.5*(player[k].scale*5)*(player[k].scale*5)/*&&animation[player[i].targetanimation].height!=lowheight*/&&weapons.type[player[k].weaponids[player[k].weaponactive]]==knife&&player[k].weaponmissdelay<=0)player[k].targetanimation=knifeslashstartanim;
+                                                                                                                                       //else if(findDistancefast(&player[k].coords,&player[i].coords)<2.5&&player[k].weaponactive!=-1&&player[i].staggerdelay>0&&weapons.type[player[k].weaponids[player[k].weaponactive]]==knife)player[k].targetanimation=knifefollowanim;
+                                                                                                                                       else if(!(player[0].victim==&player[i]&&player[0].hasvictim&&player[0].targetanimation==swordslashanim)&&weapons.type[player[k].weaponids[player[k].weaponactive]]==sword&&player[k].weaponmissdelay<=0)player[k].targetanimation=swordslashanim;
+                                                                                                                                       else if(!(player[0].victim==&player[i]&&player[0].hasvictim&&player[0].targetanimation==swordslashanim)&&weapons.type[player[k].weaponids[player[k].weaponactive]]==staff&&player[k].weaponmissdelay<=0&&randattack<3)player[k].targetanimation=staffhitanim;
+                                                                                                                                       else if(!(player[0].victim==&player[i]&&player[0].hasvictim&&player[0].targetanimation==swordslashanim)&&weapons.type[player[k].weaponids[player[k].weaponactive]]==staff&&player[k].weaponmissdelay<=0&&randattack>=3)player[k].targetanimation=staffspinhitanim;
+                                                                                                                                       else if((tutoriallevel!=1||player[k].weaponactive==-1)&&findDistancefast(&player[k].coords,&player[i].coords)<2.5*(player[k].scale*5)*(player[k].scale*5)&&randattack==1&&animation[player[i].targetanimation].height!=lowheight)player[k].targetanimation=spinkickanim;
+                                                                                                                                       else if(findDistancefast(&player[k].coords,&player[i].coords)<2.5*(player[k].scale*5)*(player[k].scale*5)&&animation[player[i].targetanimation].height==lowheight&&animation[player[k].targetanimation].attack!=normalattack)player[k].targetanimation=lowkickanim;
+                                                                                                                               }
+                                                                                                                       }
+                                                                                                               }
+                                                                                                               if(player[k].targetanimation==upunchanim&&player[k].creature==wolftype)player[k].targetanimation=wolfslapanim;
+                                                                                                       }
+                                                                                                       if((tutoriallevel!=1||tutorialstage==22)&&player[i].howactive<typedead1&&findDistancefast(&player[k].coords,&player[i].coords)<1.5*(player[k].scale*5)*(player[k].scale*5)&&!player[i].skeleton.free&&player[i].targetanimation!=getupfrombackanim&&player[i].targetanimation!=getupfromfrontanim&&(((player[i].stunned>0&&player[k].madskills)||(player[i].surprised>0)||player[i].aitype==passivetype)||(player[k].weaponactive!=-1&&player[i].stunned>0))&&normaldotproduct(player[i].facing,player[i].coords-player[k].coords)>0&&(k==0)){
+                                                                                                               if(player[k].weaponactive==-1){
+                                                                                                                       player[i].targetanimation=sneakattackedanim;
+                                                                                                                       player[i].currentanimation=sneakattackedanim;
+                                                                                                                       player[k].currentanimation=sneakattackanim;
+                                                                                                                       player[k].targetanimation=sneakattackanim;
+                                                                                                                       player[k].oldcoords=player[k].coords;
+                                                                                                                       player[k].coords=player[i].coords;
+                                                                                                               }
+                                                                                                               if(player[k].weaponactive!=-1&&weapons.type[player[k].weaponids[player[k].weaponactive]]==knife){
+                                                                                                                       player[i].targetanimation=knifesneakattackedanim;
+                                                                                                                       player[i].currentanimation=knifesneakattackedanim;
+                                                                                                                       player[k].currentanimation=knifesneakattackanim;
+                                                                                                                       player[k].targetanimation=knifesneakattackanim;
+                                                                                                                       player[i].oldcoords=player[i].coords;
+                                                                                                                       player[i].coords=player[k].coords;
+                                                                                                               }
+                                                                                                               if(player[k].weaponactive!=-1&&weapons.type[player[k].weaponids[player[k].weaponactive]]==sword){
+                                                                                                                       player[i].targetanimation=swordsneakattackedanim;
+                                                                                                                       player[i].currentanimation=swordsneakattackedanim;
+                                                                                                                       player[k].currentanimation=swordsneakattackanim;
+                                                                                                                       player[k].targetanimation=swordsneakattackanim;
+                                                                                                                       player[i].oldcoords=player[i].coords;
+                                                                                                                       player[i].coords=player[k].coords;
+                                                                                                               }
+                                                                                                               if(player[k].weaponactive==-1||weapons.type[player[k].weaponids[player[k].weaponactive]]!=staff){
+                                                                                                                       player[k].victim=&player[i];
+                                                                                                                       player[k].hasvictim=1;
+                                                                                                                       player[i].targettilt2=0;
+                                                                                                                       player[i].targetframe=1;
+                                                                                                                       player[i].currentframe=0;
+                                                                                                                       player[i].target=0;
+                                                                                                                       player[i].velocity=0;
+                                                                                                                       player[k].targettilt2=player[i].targettilt2;
+                                                                                                                       player[k].currentframe=player[i].currentframe;
+                                                                                                                       player[k].targetframe=player[i].targetframe;
+                                                                                                                       player[k].target=player[i].target;
+                                                                                                                       player[k].velocity=0;
+                                                                                                                       player[k].targetrotation=player[i].rotation;
+                                                                                                                       player[k].rotation=player[i].rotation;
+                                                                                                                       player[i].targetrotation=player[i].rotation;
+                                                                                                               }
+                                                                                                       }
+                                                                                                       if(animation[player[k].targetanimation].attack==normalattack&&player[k].victim==&player[i]&&(!player[i].skeleton.free)){
+                                                                                                               oldattackkey=1;
+                                                                                                               player[k].targetframe=0;
+                                                                                                               player[k].target=0;
+                                                                                                               //player[k].velocity=0;
+
+                                                                                                               rotatetarget=player[i].coords-player[k].coords;
+                                                                                                               Normalise(&rotatetarget);
+                                                                                                               player[k].targetrotation=-asin(0-rotatetarget.x);
+                                                                                                               player[k].targetrotation*=360/6.28;
+                                                                                                               if(rotatetarget.z<0)player[k].targetrotation=180-player[k].targetrotation;
+
+                                                                                                               player[k].targettilt2=-asin(rotatetarget.y)*360/6.28;//*-70;
+
+                                                                                                               player[k].lastattack3=player[k].lastattack2;
+                                                                                                               player[k].lastattack2=player[k].lastattack;
+                                                                                                               player[k].lastattack=player[k].targetanimation;
+                                                                                                               //player[k].targettilt2=0;
+                                                                                                               //slomo=1;
+                                                                                                               //slomodelay=.2;
+                                                                                                       }
+                                                                                                       if(player[k].targetanimation==knifefollowanim&&player[k].victim==&player[i]){
+                                                                                                               rotatetarget=player[i].coords-player[k].coords;
+                                                                                                               Normalise(&rotatetarget);
+                                                                                                               player[k].targetrotation=-asin(0-rotatetarget.x);
+                                                                                                               player[k].targetrotation*=360/6.28;
+                                                                                                               if(rotatetarget.z<0)player[k].targetrotation=180-player[k].targetrotation;
+                                                                                                               player[k].targettilt2=-asin(rotatetarget.y)*360/6.28;//*-70;
+                                                                                                               oldattackkey=1;
+                                                                                                               player[k].victim=&player[i];
+                                                                                                               player[k].hasvictim=1;
+                                                                                                               player[i].targetanimation=knifefollowedanim;
+                                                                                                               player[i].currentanimation=knifefollowedanim;
+                                                                                                               player[i].targettilt2=0;
+                                                                                                               player[i].targettilt2=player[k].targettilt2;
+                                                                                                               player[i].targetframe=1;
+                                                                                                               player[i].currentframe=0;
+                                                                                                               player[i].target=0;
+                                                                                                               player[i].velocity=0;
+                                                                                                               player[k].currentanimation=knifefollowanim;
+                                                                                                               player[k].targetanimation=knifefollowanim;
+                                                                                                               player[k].targettilt2=player[i].targettilt2;
+                                                                                                               player[k].currentframe=player[i].currentframe;
+                                                                                                               player[k].targetframe=player[i].targetframe;
+                                                                                                               player[k].target=player[i].target;
+                                                                                                               player[k].velocity=0;
+                                                                                                               player[k].oldcoords=player[k].coords;
+                                                                                                               player[i].coords=player[k].coords;
+                                                                                                               player[i].targetrotation=player[k].targetrotation;
+                                                                                                               player[i].rotation=player[k].targetrotation;
+                                                                                                               player[k].rotation=player[k].targetrotation;
+                                                                                                               player[i].rotation=player[k].targetrotation;
+                                                                                                       }
+                                                                                               }
+                                                                               }
+                                                                               bool hasstaff=0;
+                                                                               if(player[k].weaponactive!=-1){
+                                                                                       if(weapons.type[player[k].weaponids[player[k].weaponactive]]==staff)hasstaff=1;
+                                                                               }
+                                                                               if(numplayers>1)
+                                                                                       for(i=0;i<numplayers;i++){
+                                                                                               if(i==k)i++;
+                                                                                               if((playerrealattackkeydown||player[i].dead||!hasstaff)&&(k==0||i==0)&&i!=k&&i<numplayers&&k<numplayers&&animation[player[k].targetanimation].attack==neutral&&k==0){   
+                                                                                                       if(!player[i].dead||!realthreat||(player[k].weaponactive==-1&&player[k].crouchkeydown))
+                                                                                                               if(player[i].skeleton.free)
+                                                                                                                       if(findDistancefast(&player[k].coords,&player[i].coords)<3.5*(player[k].scale*5)*(player[k].scale*5)&&(player[i].dead||player[i].skeleton.longdead>1000||player[k].isRun()||(hasstaff)||(player[k].weaponactive!=-1&&player[i].skeleton.free&&(player[i].skeleton.longdead>2000||player[i].damage>player[i].damagetolerance/8||player[i].bloodloss>player[i].damagetolerance/2)&&findDistancefast(&player[k].coords,&player[i].coords)<1.5*(player[k].scale*5)*(player[k].scale*5)))){
+                                                                                                                               player[k].victim=&player[i];
+                                                                                                                               player[k].hasvictim=1;
+                                                                                                                               if(player[k].weaponactive!=-1&&tutoriallevel!=1){
+                                                                                                                                       if(player[k].crouchkeydown&&player[k].weaponactive!=-1&&weapons.type[player[k].weaponids[player[k].weaponactive]]==knife&&findDistancefast(&player[k].coords,&player[i].coords)<1.5*(player[k].scale*5)*(player[k].scale*5))player[k].targetanimation=crouchstabanim;
+                                                                                                                                       if(player[k].crouchkeydown&&findDistancefast(&player[k].coords,&player[i].coords)<1.5*(player[k].scale*5)*(player[k].scale*5)/*&&player[i].dead!=2*/&&weapons.type[player[k].weaponids[player[k].weaponactive]]==sword)player[k].targetanimation=swordgroundstabanim;
+                                                                                                                                       if(/*(player[k].crouchkeydown||!player[i].dead)&&*/findDistancefast(&player[k].coords,&player[i].coords)<3.5*(player[k].scale*5)*(player[k].scale*5)/*&&player[i].dead!=2*/&&weapons.type[player[k].weaponids[player[k].weaponactive]]==staff)player[k].targetanimation=staffgroundsmashanim;
+                                                                                                                               }
+                                                                                                                               if(findDistancefast(&player[k].coords,&player[i].coords)<2.5&&player[k].crouchkeydown&&player[k].targetanimation!=crouchstabanim&&(player[k].weaponactive==-1)&&player[i].dead&&player[i].skeleton.free&&player[i].skeleton.longdead>1000){
+                                                                                                                                       player[k].targetanimation=killanim;
+                                                                                                                                       for(j=0;j<terrain.numdecals;j++){
+                                                                                                                                               if((terrain.decaltype[j]==blooddecal||terrain.decaltype[j]==blooddecalslow)&&terrain.decalalivetime[j]<2){
+                                                                                                                                                       terrain.DeleteDecal(j);
+                                                                                                                                               }
+                                                                                                                                       }
+                                                                                                                                       for(l=0;l<objects.numobjects;l++){
+                                                                                                                                               if(objects.model[l].type==decalstype)
+                                                                                                                                                       for(j=0;j<objects.model[l].numdecals;j++){
+                                                                                                                                                               if((objects.model[l].decaltype[j]==blooddecal||objects.model[l].decaltype[j]==blooddecalslow)&&objects.model[l].decalalivetime[j]<2){
+                                                                                                                                                                       objects.model[l].DeleteDecal(j);
+                                                                                                                                                               }
+                                                                                                                                                       }
+                                                                                                                                       }
+                                                                                                                               }
+                                                                                                                               if(!player[i].dead||musictype!=2)
+                                                                                                                                       if(findDistancefast(&player[k].coords,&player[i].coords)<3.5&&(player[k].isRun()||(player[k].isIdle()&&player[k].attackkeydown))&&(player[k].staggerdelay<=0&&(player[i].dead||(player[i].skeleton.longdead<300&&player[k].lastattack!=spinkickanim&&player[i].skeleton.free)))&&(!player[i].dead||musictype!=stream_music2)){
+                                                                                                                                               player[k].targetanimation=dropkickanim;
+                                                                                                                                               for(j=0;j<terrain.numdecals;j++){
+                                                                                                                                                       if((terrain.decaltype[j]==blooddecal||terrain.decaltype[j]==blooddecalslow)&&terrain.decalalivetime[j]<2){
+                                                                                                                                                               terrain.DeleteDecal(j);
+                                                                                                                                                       }
+                                                                                                                                               }
+                                                                                                                                               for(l=0;l<objects.numobjects;l++){
+                                                                                                                                                       if(objects.model[l].type==decalstype)
+                                                                                                                                                               for(j=0;j<objects.model[l].numdecals;j++){
+                                                                                                                                                                       if((objects.model[l].decaltype[j]==blooddecal||objects.model[l].decaltype[j]==blooddecalslow)&&objects.model[l].decalalivetime[j]<2){
+                                                                                                                                                                               objects.model[l].DeleteDecal(j);
+                                                                                                                                                                       }
+                                                                                                                                                               }
+                                                                                                                                               }
+                                                                                                                                       }
+                                                                                                                       }
+                                                                                                                       if(animation[player[k].targetanimation].attack==normalattack&&player[k].victim==&player[i]&&(!player[i].skeleton.free||player[k].targetanimation==killanim||player[k].targetanimation==crouchstabanim||player[k].targetanimation==swordgroundstabanim||player[k].targetanimation==staffgroundsmashanim||player[k].targetanimation==dropkickanim)){
+                                                                                                                               oldattackkey=1;
+                                                                                                                               player[k].targetframe=0;
+                                                                                                                               player[k].target=0;
+                                                                                                                               //player[k].velocity=0;
+
+                                                                                                                               rotatetarget=player[i].coords-player[k].coords;
+                                                                                                                               if(player[k].targetanimation==crouchstabanim||player[k].targetanimation==swordgroundstabanim||player[k].targetanimation==staffgroundsmashanim){
+                                                                                                                                       rotatetarget=(player[i].coords+(player[i].skeleton.joints[player[i].skeleton.jointlabels[abdomen]].position+player[i].skeleton.joints[player[i].skeleton.jointlabels[neck]].position)/2*player[i].scale)-player[k].coords;
+                                                                                                                               }
+                                                                                                                               Normalise(&rotatetarget);
+                                                                                                                               player[k].targetrotation=-asin(0-rotatetarget.x);
+                                                                                                                               player[k].targetrotation*=360/6.28;
+                                                                                                                               if(rotatetarget.z<0)player[k].targetrotation=180-player[k].targetrotation;
+
+                                                                                                                               if(player[k].targetanimation==crouchstabanim||player[k].targetanimation==swordgroundstabanim){
+                                                                                                                                       player[k].targetrotation+=(float)(abs(Random()%100)-50)/4;
+                                                                                                                               }
+
+                                                                                                                               player[k].targettilt2=-asin(rotatetarget.y)*360/6.28;//*-70;
+                                                                                                                               if(player[k].targetanimation==staffgroundsmashanim)player[k].targettilt2+=10;
+
+                                                                                                                               player[k].lastattack3=player[k].lastattack2;
+                                                                                                                               player[k].lastattack2=player[k].lastattack;
+                                                                                                                               player[k].lastattack=player[k].targetanimation;
+
+                                                                                                                               if(player[k].targetanimation==swordgroundstabanim){
+                                                                                                                                       player[k].targetrotation+=30;
+                                                                                                                               }
+                                                                                                                               //player[k].targettilt2=0;
+                                                                                                                               //slomo=1;
+                                                                                                                               //slomodelay=.2;
+                                                                                                                       }
+                                                                                               }
+                                                                                       }
+                                                                                       if(!player[k].hasvictim){
+                                                                                               for(i=0;i<numplayers;i++){
+                                                                                                       if((player[k].hasvictim==0)&&i!=k&&(i==0||k==0)&&!player[i].skeleton.free){
+                                                                                                               player[k].victim=&player[i];
+                                                                                                               player[k].hasvictim=1;
+                                                                                                       }
+                                                                                                       if(player[k].hasvictim&&!player[i].skeleton.free)
+                                                                                                               if(findDistancefast(&player[k].coords,&player[i].coords)<findDistancefast(&player[k].coords,&player[k].victim->coords)&&i!=k&&(i==0||k==0)){
+                                                                                                                       player[k].victim=&player[i];
+                                                                                                               }
+                                                                                               }
+                                                                                       }
+                                                                                       if(player[k].aitype==playercontrolled)
+                                                                                               if(player[k].attackkeydown&&(player[k].isRun())&&player[k].wasRun()&&((player[k].hasvictim&&findDistancefast(&player[k].coords,&player[k].victim->coords)<12*(player[k].scale*5)*(player[k].scale*5)&&findDistancefast(&player[k].coords,&player[k].victim->coords)>7*(player[k].scale*5)*(player[k].scale*5)&&!player[k].victim->skeleton.free&&player[k].victim->targetanimation!=getupfrombackanim&&player[k].victim->targetanimation!=getupfromfrontanim&&animation[player[k].victim->targetanimation].height!=lowheight&&player[k].aitype!=playercontrolled&&normaldotproduct(player[k].facing,player[k].victim->coords-player[k].coords)>0&&player[k].rabbitkickenabled)||player[k].jumpkeydown)){
+                                                                                                       oldattackkey=1;
+                                                                                                       player[k].targetanimation=rabbitkickanim;
+                                                                                                       player[k].targetframe=0;
+                                                                                                       player[k].target=0;
+                                                                                               }
+                                                                                               if(animation[player[k].targetanimation].attack&&k==0){
+                                                                                                       numattacks++;
+                                                                                                       bool armedstaff=0;
+                                                                                                       if(player[k].weaponactive!=-1){
+                                                                                                               if(weapons.type[player[k].weaponids[player[k].weaponactive]]==staff)armedstaff=1;
+                                                                                                       }
+                                                                                                       bool armedsword=0;
+                                                                                                       if(player[k].weaponactive!=-1){
+                                                                                                               if(weapons.type[player[k].weaponids[player[k].weaponactive]]==sword)armedsword=1;
+                                                                                                       }
+                                                                                                       bool armedknife=0;
+                                                                                                       if(player[k].weaponactive!=-1){
+                                                                                                               if(weapons.type[player[k].weaponids[player[k].weaponactive]]==knife)armedknife=1;
+                                                                                                       }
+                                                                                                       if(armedstaff)numstaffattack++;
+                                                                                                       else if(armedsword)numswordattack++;
+                                                                                                       else if(armedknife)numknifeattack++;
+                                                                                                       else numunarmedattack++;
+                                                                                               }
+                                                               }
+                                                       }
+                                               }
+
+                                               //Collisions
+                                               static float collisionradius;
+                                               if(numplayers>1)
+                                                       for(k=0;k<numplayers;k++){
+                                                               for(i=k;i<numplayers;i++){
+                                                                       if(i==k)i++;
+                                                                       if(i<numplayers)
+                                                                               if((animation[player[i].targetanimation].attack!=reversed&&animation[player[i].targetanimation].attack!=reversal&&animation[player[k].targetanimation].attack!=reversed&&animation[player[k].targetanimation].attack!=reversal)||(i!=0&&k!=0))
+                                                                                       if((animation[player[i].currentanimation].attack!=reversed&&animation[player[i].currentanimation].attack!=reversal&&animation[player[k].currentanimation].attack!=reversed&&animation[player[k].currentanimation].attack!=reversal)||(i!=0&&k!=0))
+                                                                                               if(player[i].howactive<=typesleeping&&player[k].howactive<=typesleeping)
+                                                                                                       if(player[i].howactive!=typesittingwall&&player[k].howactive!=typesittingwall)
+                                                                                                               if(i!=k&&player[i].whichpatchx==player[k].whichpatchx&&player[i].whichpatchz==player[k].whichpatchz&&player[k].skeleton.oldfree==player[k].skeleton.free&&player[i].skeleton.oldfree==player[i].skeleton.free&&player[i].targetanimation!=climbanim&&player[i].targetanimation!=hanganim&&player[k].targetanimation!=climbanim&&player[k].targetanimation!=hanganim)
+                                                                                                                       if(player[i].coords.y>player[k].coords.y-3)
+                                                                                                                               if(player[i].coords.y<player[k].coords.y+3)
+                                                                                                                                       if(player[i].coords.x>player[k].coords.x-3)
+                                                                                                                                               if(player[i].coords.x<player[k].coords.x+3)
+                                                                                                                                                       if(player[i].coords.z>player[k].coords.z-3)
+                                                                                                                                                               if(player[i].coords.z<player[k].coords.z+3){
+                                                                                                                                                                       if(findDistancefast(&player[i].coords,&player[k].coords)<3*((player[i].scale+player[k].scale)*2.5)*((player[i].scale+player[k].scale)*2.5)){
+                                                                                                                                                                               if(player[i].onfire||player[k].onfire){
+                                                                                                                                                                                       if(!player[i].onfire)player[i].CatchFire();
+                                                                                                                                                                                       if(!player[k].onfire)player[k].CatchFire();
+                                                                                                                                                                               }       
+                                                                                                                                                                       }
+
+                                                                                                                                                                       tempcoords1=player[i].coords;
+                                                                                                                                                                       tempcoords2=player[k].coords;
+                                                                                                                                                                       if(!player[i].skeleton.oldfree)tempcoords1.y+=player[i].skeleton.joints[player[i].skeleton.jointlabels[abdomen]].position.y*player[i].scale;
+                                                                                                                                                                       if(!player[k].skeleton.oldfree)tempcoords2.y+=player[k].skeleton.joints[player[k].skeleton.jointlabels[abdomen]].position.y*player[k].scale;
+                                                                                                                                                                       collisionradius=1.2*((player[i].scale+player[k].scale)*2.5)*((player[i].scale+player[k].scale)*2.5);
+                                                                                                                                                                       if(player[0].hasvictim)
+                                                                                                                                                                               if(player[0].targetanimation==rabbitkickanim&&(k==0||i==0)&&!player[0].victim->skeleton.free)collisionradius=3;
+                                                                                                                                                                       if((!player[i].skeleton.oldfree||!player[k].skeleton.oldfree)&&(findDistancefast(&tempcoords1,&tempcoords2)<collisionradius||findDistancefast(&player[i].coords,&player[k].coords)<collisionradius)){   
+                                                                                                                                                                               if(k==0)
+                                                                                                                                                                                       if(player[k].targetanimation==jumpdownanim&&!player[k].skeleton.oldfree&&!player[k].skeleton.free&&player[i].skeleton.oldfree&&player[i].skeleton.free&&player[i].dead&&player[k].lastcollide<=0&&abs(player[i].coords.y-player[k].coords.y)<.2&&findDistancefast(&player[k].coords,&player[i].coords)<.7*((player[i].scale+player[k].scale)*2.5)*((player[i].scale+player[k].scale)*2.5)){
+                                                                                                                                                                                               player[k].coords.y=player[i].coords.y;
+                                                                                                                                                                                               player[i].velocity=player[k].velocity;
+                                                                                                                                                                                               player[i].skeleton.free=0;
+                                                                                                                                                                                               player[i].rotation=0;
+                                                                                                                                                                                               player[i].RagDoll(0);
+                                                                                                                                                                                               player[i].DoDamage(20);
+                                                                                                                                                                                               if(k==0)camerashake+=.3;
+                                                                                                                                                                                               player[i].skeleton.longdead=0;
+                                                                                                                                                                                               player[k].lastcollide=1;        
+                                                                                                                                                                                       }
+                                                                                                                                                                                       if(i==0)
+                                                                                                                                                                                               if(player[i].targetanimation==jumpdownanim&&!player[i].skeleton.oldfree&&!player[i].skeleton.free&&player[k].skeleton.oldfree&&player[k].skeleton.free&&player[k].dead&&player[i].lastcollide<=0&&abs(player[i].coords.y-player[k].coords.y)<.2&&findDistancefast(&player[k].coords,&player[i].coords)<.7*((player[i].scale+player[k].scale)*2.5)*((player[i].scale+player[k].scale)*2.5)){
+                                                                                                                                                                                                       player[i].coords.y=player[k].coords.y;
+                                                                                                                                                                                                       player[k].velocity=player[i].velocity;
+                                                                                                                                                                                                       player[k].skeleton.free=0;
+                                                                                                                                                                                                       player[k].rotation=0;
+                                                                                                                                                                                                       player[k].RagDoll(0);
+                                                                                                                                                                                                       player[k].DoDamage(20);
+                                                                                                                                                                                                       if(i==0)camerashake+=.3;
+                                                                                                                                                                                                       player[k].skeleton.longdead=0;
+                                                                                                                                                                                                       player[i].lastcollide=1;        
+                                                                                                                                                                                               }
+
+                                                                                                                                                                                               if((player[i].skeleton.oldfree==1&&findLengthfast(&player[i].velocity)>1)||(player[k].skeleton.oldfree==1&&findLengthfast(&player[k].velocity)>1)||(player[i].skeleton.oldfree==0&&player[k].skeleton.oldfree==0)){     
+                                                                                                                                                                                                       rotatetarget=player[k].velocity-player[i].velocity;
+                                                                                                                                                                                                       if(((player[i].targetanimation!=getupfrombackanim&&player[i].targetanimation!=getupfromfrontanim)||player[i].skeleton.free)&&((player[k].targetanimation!=getupfrombackanim&&player[k].targetanimation!=getupfromfrontanim)||player[k].skeleton.free))
+                                                                                                                                                                                                               if(((((findLengthfast(&rotatetarget)>150&&(i!=0&&k!=0))||(findLengthfast(&rotatetarget)>50&&player[0].rabbitkickragdoll/*currentanimation==rabbitkickanim*/&&(i==0||k==0)))&&normaldotproduct(rotatetarget,player[k].coords-player[i].coords)>0)&&((i==0||k==0)||((player[i].skeleton.oldfree==1&&k!=0&&animation[player[k].currentanimation].attack==neutral)||(player[k].skeleton.oldfree==1&&i!=0&&animation[player[i].currentanimation].attack==neutral)||(player[i].isFlip()&&!player[i].skeleton.oldfree&&(i==0||k==0))||(player[k].isFlip()&&!player[k].skeleton.oldfree&&(i==0||k==0))||(i==0||k==0))))||((player[i].targetanimation==jumpupanim||player[i].targetanimation==jumpdownanim||player[i].isFlip())&&(player[k].targetanimation==jumpupanim||player[k].targetanimation==jumpdownanim||player[k].isFlip())&&(i==0||k==0)&&(!player[i].skeleton.oldfree&&!player[k].skeleton.oldfree))){
+                                                                                                                                                                                                                       //If hit by body
+                                                                                                                                                                                                                       if((i!=0||player[i].skeleton.free)&&(k!=0||player[k].skeleton.free)||(animation[player[i].targetanimation].height==highheight&&animation[player[k].targetanimation].height==highheight)){
+                                                                                                                                                                                                                               static float gLoc[3];
+                                                                                                                                                                                                                               static float vel[3];
+                                                                                                                                                                                                                               gLoc[0]=player[i].coords.x;
+                                                                                                                                                                                                                               gLoc[1]=player[i].coords.y;
+                                                                                                                                                                                                                               gLoc[2]=player[i].coords.z;
+                                                                                                                                                                                                                               vel[0]=player[i].velocity.x;
+                                                                                                                                                                                                                               vel[1]=player[i].velocity.y;
+                                                                                                                                                                                                                               vel[2]=player[i].velocity.z;
+                                                                                                                                                                                                                               if(tutoriallevel!=1){
+                                                                                                                                                                                                                                       PlaySoundEx( heavyimpactsound, samp[heavyimpactsound], NULL, TRUE);
+                                                                                                                                                                                                                                       FSOUND_3D_SetAttributes(channels[heavyimpactsound], gLoc, vel);
+                                                                                                                                                                                                                                       FSOUND_SetVolume(channels[heavyimpactsound], 256);
+                                                                                                                                                                                                                                       FSOUND_SetPaused(channels[heavyimpactsound], FALSE);
+                                                                                                                                                                                                                               }
+                                                                                                                                                                                                                               //player[i].velocity=player[k].velocity;
+                                                                                                                                                                                                                               //player[k].velocity=player[i].velocity;
+
+                                                                                                                                                                                                                               player[i].RagDoll(0);
+                                                                                                                                                                                                                               if(player[i].damage>player[i].damagetolerance-findLengthfast(&rotatetarget)/4&&!player[i].dead){
+                                                                                                                                                                                                                                       bonus=aimbonus;
+                                                                                                                                                                                                                                       bonustime=0;
+                                                                                                                                                                                                                                       bonusvalue=150;
+                                                                                                                                                                                                                               }
+                                                                                                                                                                                                                               player[i].DoDamage(findLengthfast(&rotatetarget)/4);
+                                                                                                                                                                                                                               player[k].RagDoll(0);
+                                                                                                                                                                                                                               if(player[k].damage>player[k].damagetolerance-findLengthfast(&rotatetarget)/4&&!player[k].dead){
+                                                                                                                                                                                                                                       bonus=aimbonus;
+                                                                                                                                                                                                                                       bonustime=0;
+                                                                                                                                                                                                                                       bonusvalue=150;
+                                                                                                                                                                                                                               }
+                                                                                                                                                                                                                               player[k].DoDamage(findLengthfast(&rotatetarget)/4);
+
+                                                                                                                                                                                                                               //if(player[i].skeleton.oldfree){
+                                                                                                                                                                                                                               for(j=0;j<player[i].skeleton.num_joints;j++){
+                                                                                                                                                                                                                                       player[i].skeleton.joints[j].velocity=player[i].skeleton.joints[j].velocity/5+player[k].velocity;
+                                                                                                                                                                                                                               }
+                                                                                                                                                                                                                               //}
+                                                                                                                                                                                                                               //if(player[k].skeleton.oldfree){
+                                                                                                                                                                                                                               for(j=0;j<player[k].skeleton.num_joints;j++){
+                                                                                                                                                                                                                                       player[k].skeleton.joints[j].velocity=player[k].skeleton.joints[j].velocity/5+player[i].velocity;
+                                                                                                                                                                                                                               }
+                                                                                                                                                                                                                               //}
+
+                                                                                                                                                                                                                       }
+                                                                                                                                                                                                               }
+                                                                                                                                                                                                               if((animation[player[i].targetanimation].attack==neutral||animation[player[i].targetanimation].attack==normalattack)&&(animation[player[k].targetanimation].attack==neutral||animation[player[k].targetanimation].attack==normalattack)){
+                                                                                                                                                                                                                       //If bumped
+                                                                                                                                                                                                                       if(player[i].skeleton.oldfree==0&&player[k].skeleton.oldfree==0){
+                                                                                                                                                                                                                               if(findDistancefast(&player[k].coords,&player[i].coords)<.5*((player[i].scale+player[k].scale)*2.5)*((player[i].scale+player[k].scale)*2.5)){
+                                                                                                                                                                                                                                       rotatetarget=player[k].coords-player[i].coords;
+                                                                                                                                                                                                                                       Normalise(&rotatetarget);
+                                                                                                                                                                                                                                       player[k].coords=(player[k].coords+player[i].coords)/2;
+                                                                                                                                                                                                                                       player[i].coords=player[k].coords-rotatetarget*fast_sqrt(.6)/2*((player[i].scale+player[k].scale)*2.5)*((player[i].scale+player[k].scale)*2.5);
+                                                                                                                                                                                                                                       player[k].coords+=rotatetarget*fast_sqrt(.6)/2*((player[i].scale+player[k].scale)*2.5)*((player[i].scale+player[k].scale)*2.5);
+                                                                                                                                                                                                                                       if(player[k].howactive==typeactive||hostile)
+                                                                                                                                                                                                                                               if(player[k].isIdle()){
+                                                                                                                                                                                                                                                       if(player[k].howactive<typesleeping){
+                                                                                                                                                                                                                                                               player[k].targetanimation=player[k].getStop();
+                                                                                                                                                                                                                                                               player[k].targetframe=0;
+                                                                                                                                                                                                                                                               player[k].target=0;
+                                                                                                                                                                                                                                                       }
+                                                                                                                                                                                                                                                       else if(player[k].howactive==typesleeping)
+                                                                                                                                                                                                                                                       {
+                                                                                                                                                                                                                                                               player[k].targetanimation=getupfromfrontanim;
+                                                                                                                                                                                                                                                               player[k].targetframe=0;
+                                                                                                                                                                                                                                                               player[k].target=0;
+                                                                                                                                                                                                                                                       }
+                                                                                                                                                                                                                                                       if(!editorenabled)player[k].howactive=typeactive;
+                                                                                                                                                                                                                                               }
+                                                                                                                                                                                                                                               if(player[i].howactive==typeactive||hostile)
+                                                                                                                                                                                                                                                       if(player[i].isIdle()){
+                                                                                                                                                                                                                                                               if(player[i].howactive<typesleeping){
+                                                                                                                                                                                                                                                                       player[i].targetanimation=player[i].getStop();
+                                                                                                                                                                                                                                                                       player[i].targetframe=0;
+                                                                                                                                                                                                                                                                       player[i].target=0;
+                                                                                                                                                                                                                                                               }
+                                                                                                                                                                                                                                                               else
+                                                                                                                                                                                                                                                               {
+                                                                                                                                                                                                                                                                       player[i].targetanimation=getupfromfrontanim;
+                                                                                                                                                                                                                                                                       player[i].targetframe=0;
+                                                                                                                                                                                                                                                                       player[i].target=0;
+                                                                                                                                                                                                                                                               }
+                                                                                                                                                                                                                                                               if(!editorenabled)player[i].howactive=typeactive;
+                                                                                                                                                                                                                                                       }
+                                                                                                                                                                                                                               }
+                                                                                                                                                                                                                               if(hostile){
+                                                                                                                                                                                                                                       if(k==0&&i!=0&&player[k].targetanimation==jumpdownanim&&!player[i].isCrouch()&&player[i].targetanimation!=rollanim&&!player[k].skeleton.oldfree&&!player[k].skeleton.free&&player[k].lastcollide<=0&&player[k].velocity.y<-10){
+                                                                                                                                                                                                                                               player[i].velocity=player[k].velocity;
+                                                                                                                                                                                                                                               player[k].velocity=player[k].velocity*-.5;
+                                                                                                                                                                                                                                               //player[i].velocity.y-=10;
+                                                                                                                                                                                                                                               player[k].velocity.y=player[i].velocity.y;
+                                                                                                                                                                                                                                               player[i].DoDamage(20);
+                                                                                                                                                                                                                                               player[i].RagDoll(0);
+                                                                                                                                                                                                                                               player[k].lastcollide=1;        
+                                                                                                                                                                                                                                               if(k==0){
+                                                                                                                                                                                                                                                       bonus=AboveBonus;
+                                                                                                                                                                                                                                                       bonustime=0;
+                                                                                                                                                                                                                                                       bonusvalue=50;
+                                                                                                                                                                                                                                               }
+                                                                                                                                                                                                                                       }
+                                                                                                                                                                                                                                       if(i==0&&k!=0&&player[i].targetanimation==jumpdownanim&&!player[k].isCrouch()&&player[k].targetanimation!=rollanim&&!player[i].skeleton.oldfree&&!player[i].skeleton.free&&player[i].lastcollide<=0&&player[i].velocity.y<-10){
+                                                                                                                                                                                                                                               player[k].velocity=player[i].velocity;
+                                                                                                                                                                                                                                               player[i].velocity=player[i].velocity*-.3;
+                                                                                                                                                                                                                                               //player[k].velocity.y-=10;
+                                                                                                                                                                                                                                               player[i].velocity.y=player[k].velocity.y;
+                                                                                                                                                                                                                                               player[k].DoDamage(20);
+                                                                                                                                                                                                                                               player[k].RagDoll(0);   
+                                                                                                                                                                                                                                               player[i].lastcollide=1;        
+                                                                                                                                                                                                                                               if(i==0){
+                                                                                                                                                                                                                                                       bonus=AboveBonus;
+                                                                                                                                                                                                                                                       bonustime=0;
+                                                                                                                                                                                                                                                       bonusvalue=50;
+                                                                                                                                                                                                                                               }
+                                                                                                                                                                                                                                       }
+                                                                                                                                                                                                                               }
+                                                                                                                                                                                                                       }
+                                                                                                                                                                                                               }
+                                                                                                                                                                                               }
+                                                                                                                                                                                               player[i].CheckKick();
+                                                                                                                                                                                               player[k].CheckKick();
+                                                                                                                                                                       }
+                                                                                                                                                               }
+                                                               }
+                                                       }
+
+                                                       for(k=0;k<numplayers;k++){
+                                                               for(i=k;i<numplayers;i++){
+                                                                       if(i==k)i++;
+                                                                       if(i<numplayers&&i!=k&&player[k].skeleton.free==0&&player[i].skeleton.oldfree==0&&(player[i].targetanimation==jumpupanim||player[k].targetanimation==jumpupanim)&&(player[i].aitype==playercontrolled||player[k].aitype==playercontrolled)&&((player[i].aitype==attacktypecutoff&&player[i].stunned<=0)||(player[k].aitype==attacktypecutoff&&player[k].stunned<=0))){
+                                                                               if(findDistancefast(&player[i].coords,&player[k].coords)<10*((player[i].scale+player[k].scale)*2.5)*((player[i].scale+player[k].scale)*2.5)&&findDistancefastflat(&player[i].coords,&player[k].coords)<2*((player[i].scale+player[k].scale)*2.5)*((player[i].scale+player[k].scale)*2.5)){
+                                                                                       if(player[i].targetanimation==jumpupanim&&player[k].targetanimation!=getupfrombackanim&&player[k].targetanimation!=getupfromfrontanim&&animation[player[k].targetanimation].height==middleheight&&normaldotproduct(player[i].velocity,player[k].coords-player[i].coords)<0&&((player[k].aitype==playercontrolled&&player[k].attackkeydown)||player[k].aitype!=playercontrolled)){
+                                                                                               player[i].victim=&player[k];
+                                                                                               player[i].targetanimation=jumpreversedanim;
+                                                                                               player[i].currentanimation=jumpreversedanim;
+                                                                                               player[k].currentanimation=jumpreversalanim;
+                                                                                               player[k].targetanimation=jumpreversalanim;
+                                                                                               player[i].targettilt2=0;
+                                                                                               player[i].currentframe=0;
+                                                                                               player[i].targetframe=1;
+                                                                                               player[k].currentframe=0;
+                                                                                               player[k].targetframe=1;
+                                                                                               if(player[i].coords.y<player[k].coords.y+1){
+                                                                                                       player[i].targetanimation=rabbitkickreversedanim;
+                                                                                                       player[i].currentanimation=rabbitkickreversedanim;
+                                                                                                       player[k].currentanimation=rabbitkickreversalanim;
+                                                                                                       player[k].targetanimation=rabbitkickreversalanim;
+                                                                                                       player[k].currentframe=1;
+                                                                                                       player[k].targetframe=2;
+                                                                                                       player[i].currentframe=1;
+                                                                                                       player[i].targetframe=2;
+                                                                                               }
+                                                                                               player[k].targettilt2=0;
+                                                                                               player[i].target=0;
+                                                                                               player[i].velocity=0;
+                                                                                               player[k].velocity=0;
+                                                                                               player[k].oldcoords=player[k].coords;
+                                                                                               player[i].coords=player[k].coords;
+                                                                                               player[k].targetrotation=player[i].targetrotation;
+                                                                                               player[k].rotation=player[i].targetrotation;
+                                                                                               player[k].victim=&player[i];
+                                                                                               if(player[k].aitype==attacktypecutoff)player[k].stunned=.5;
+                                                                                       }
+                                                                                       if(player[k].targetanimation==jumpupanim&&player[i].targetanimation!=getupfrombackanim&&player[i].targetanimation!=getupfromfrontanim&&animation[player[i].targetanimation].height==middleheight&&normaldotproduct(player[k].velocity,player[i].coords-player[k].coords)<0&&((player[i].aitype==playercontrolled&&player[i].attackkeydown)||player[i].aitype!=playercontrolled)){
+                                                                                               player[k].victim=&player[i];
+                                                                                               player[k].targetanimation=jumpreversedanim;
+                                                                                               player[k].currentanimation=jumpreversedanim;
+                                                                                               player[i].currentanimation=jumpreversalanim;
+                                                                                               player[i].targetanimation=jumpreversalanim;
+                                                                                               player[k].targettilt2=0;
+                                                                                               player[i].targettilt2=0;
+                                                                                               player[k].currentframe=0;
+                                                                                               player[k].targetframe=1;
+                                                                                               player[i].currentframe=0;
+                                                                                               player[i].targetframe=1;
+                                                                                               if(player[k].coords.y<player[i].coords.y+1){
+                                                                                                       player[k].targetanimation=rabbitkickreversedanim;
+                                                                                                       player[k].currentanimation=rabbitkickreversedanim;
+                                                                                                       player[i].currentanimation=rabbitkickreversalanim;
+                                                                                                       player[i].targetanimation=rabbitkickreversalanim;
+                                                                                                       player[k].currentframe=1;
+                                                                                                       player[k].targetframe=2;
+                                                                                                       player[i].currentframe=1;
+                                                                                                       player[i].targetframe=2;
+                                                                                               }
+                                                                                               player[k].target=0;
+                                                                                               player[k].velocity=0;
+                                                                                               player[i].velocity=0;
+                                                                                               player[i].oldcoords=player[i].coords;
+                                                                                               player[k].coords=player[i].coords;
+                                                                                               player[i].targetrotation=player[k].targetrotation;
+                                                                                               player[i].rotation=player[k].targetrotation;
+                                                                                               player[i].victim=&player[k];
+                                                                                               if(player[i].aitype==attacktypecutoff)player[i].stunned=.5;
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+
+                                                       for(k=0;k<numplayers;k++)
+                                                               if(player[k].immobile&&k!=0)player[k].coords=player[k].realoldcoords;
+
+
+                                                       //pile
+                                                       /*
+                                                       XYZ tempdiff;
+                                                       XYZ tempoldpos;
+                                                       XYZ temp1,temp2;
+                                                       bool isgood;
+                                                       static float checkdelay;
+                                                       checkdelay-=multiplier;
+                                                       int m;
+                                                       static bool checkedcoll[maxplayers][maxplayers];
+                                                       static bool above[maxplayers];
+
+                                                       for(i=0;i<maxplayers;i++){
+                                                       for(j=0;j<maxplayers;j++){
+                                                       checkedcoll[i][j]=0;
+                                                       }
+                                                       }
+
+                                                       if(numplayers>1&&checkdelay<=0){
+                                                       checkdelay=.015;
+                                                       for(k=0;k<numplayers;k++){
+                                                       if(player[k].skeleton.free!=2)above[k]=-1;
+
+                                                       for(i=k;i<numplayers;i++){
+                                                       if(i==k)i++;
+                                                       if(i<numplayers)
+                                                       if(!checkedcoll[i][k]){
+                                                       checkedcoll[i][k]=1;
+                                                       checkedcoll[k][i]=1;
+                                                       if(player[i].skeleton.free&&player[k].skeleton.free)
+                                                       if(player[i].skeleton.free!=2||player[k].skeleton.free!=2)
+                                                       if(i!=k&&player[i].whichpatchx==player[k].whichpatchx&&player[i].whichpatchz==player[k].whichpatchz)
+                                                       if(player[i].coords.y>player[k].coords.y-3)
+                                                       if(player[i].coords.y<player[k].coords.y+3)
+                                                       if(player[i].coords.x>player[k].coords.x-3)
+                                                       if(player[i].coords.x<player[k].coords.x+3)
+                                                       if(player[i].coords.z>player[k].coords.z-3)
+                                                       if(player[i].coords.z<player[k].coords.z+3)
+                                                       if(findDistancefast(&player[i].coords,&player[k].coords)<3*((player[i].scale+player[k].scale)*2.5)*((player[i].scale+player[k].scale)*2.5)){
+                                                       int stuck,moving;
+                                                       if((player[i].skeleton.longdead>player[k].skeleton.longdead&&player[k].skeleton.free!=2)||player[i].skeleton.free==2){
+                                                       stuck=i;
+                                                       moving=k;
+                                                       }
+                                                       else
+                                                       {
+                                                       moving=i;
+                                                       stuck=k;
+                                                       }
+                                                       isgood=1;
+
+                                                       if(isgood){
+                                                       above[moving]=stuck;
+                                                       for(l=0;l<player[moving].skeleton.num_joints;l++){
+                                                       for(m=0;m<player[stuck].skeleton.num_joints;m++){
+                                                       while(findDistancefast(player[moving].skeleton.joints[l].position+player[moving].coords,player[stuck].skeleton.joints[m].position+player[stuck].coords)<.25)
+                                                       {
+                                                       player[moving].skeleton.joints[l].position.y+=.003;
+                                                       if(player[moving].skeleton.joints[l].velocity.y<-.05)player[moving].skeleton.joints[l].velocity.y+=.003/.015/2;
+
+                                                       }
+                                                       }
+                                                       }
+                                                       }
+                                                       }
+                                                       }
+                                                       }
+                                                       }
+                                                       }
+
+                                                       */
+
+                                                       if(!IsKeyDown(theKeyMap, MAC_N_KEY)){
+                                                               texturesizetogglekeydown=0;
+                                                       }
+
+                                                       for(k=0;k<numplayers;k++){
+                                                               if(!isnormal(player[k].coords.x)||!isnormal(player[k].coords.y)||!isnormal(player[k].coords.z)){
+                                                                       if(!isnormal(player[k].coords.x)||!isnormal(player[k].coords.y)||!isnormal(player[k].coords.z)){
+                                                                               player[k].DoDamage(1000);
+                                                                       }
+                                                               }
+                                                       }
+
+                                                       static bool respawnkeydown;
+                                                       if(!editorenabled&&(whichlevel!=-2&&(IsKeyDown(theKeyMap, MAC_Z_KEY)&&IsKeyDown(theKeyMap, MAC_COMMAND_KEY)&&debugmode&&!editorenabled)||(IsKeyDown(theKeyMap, jumpkey)&&!respawnkeydown&&!oldattackkey&&player[0].dead))){
+                                                               targetlevel=whichlevel;
+                                                               loading=1;
+                                                               leveltime=5;
+                                                       }
+                                                       if(!IsKeyDown(theKeyMap, jumpkey))respawnkeydown=0;
+                                                       if(IsKeyDown(theKeyMap, jumpkey))respawnkeydown=1;
+
+
+
+
+                                                       if(whichlevel!=-2&&IsKeyDown(theKeyMap, MAC_K_KEY)&&IsKeyDown(theKeyMap, MAC_SHIFT_KEY)&&!slomotogglekeydown&&debugmode&&!editorenabled){
+                                                               targetlevel++;
+                                                               if(targetlevel>numchallengelevels-1)targetlevel=0;
+                                                               loading=1;
+                                                               leveltime=5;
+                                                               slomotogglekeydown=1;
+                                                       }
+
+                                                       /*
+                                                       if(IsKeyDown(theKeyMap, MAC_Z_KEY)){
+                                                       //Respawn
+                                                       FSOUND_SetPaused(channels[whooshsound], TRUE);
+                                                       changedelay=0;
+                                                       for(k=0;k<numplayers;k++){
+                                                       player[k].dead=0;
+                                                       player[k].damage=0;
+                                                       player[k].permanentdamage=0;
+                                                       if(player[k].skeleton.free==2)player[k].skeleton.free=1;
+                                                       player[k].aitype=passivetype;
+                                                       }
+                                                       player[0].aitype=playercontrolled;
+                                                       }
+                                                       */
+
+                                                       static bool movekey;
+                                                       static bool connected;
+                                                       /*player[0].forwardkeydown=IsKeyDown(theKeyMap, MAC_W_KEY);
+                                                       player[0].leftkeydown=IsKeyDown(theKeyMap, MAC_A_KEY);
+                                                       player[0].backkeydown=IsKeyDown(theKeyMap, MAC_S_KEY);
+                                                       player[0].rightkeydown=IsKeyDown(theKeyMap, MAC_D_KEY);
+                                                       player[0].jumpkeydown=IsKeyDown(theKeyMap, MAC_SPACE_KEY);
+                                                       player[0].crouchkeydown=IsKeyDown(theKeyMap, MAC_SHIFT_KEY);*/
+
+                                                       //if(!player[0].crouchkeydown)player[0].crouchkeydown=IsKeyDown(theKeyMap, MAC_CONTROL_KEY);
+
+               for(int i=0;i<numplayers;i++){  
+                                                               if(!player[i].skeleton.free){
+                                                                       oldtargetrotation=player[i].targetrotation;
+                                                                       if(i==0&&indialogue==-1){
+                                                                               if(!animation[player[0].targetanimation].attack&&player[0].targetanimation!=staggerbackhighanim&&player[0].targetanimation!=staggerbackhardanim&&player[0].targetanimation!=crouchremoveknifeanim&&player[0].targetanimation!=removeknifeanim&&player[0].targetanimation!=backhandspringanim&&player[0].targetanimation!=dodgebackanim&&player[0].targetanimation!=walljumprightkickanim&&player[0].targetanimation!=walljumpleftkickanim){
+                                                                                       if(!cameramode)player[0].targetrotation=-rotation+180;
+                                                                                       if(cameramode)player[0].targetrotation=0;
+                                                                               }
+
+                                                                               facing=0;
+                                                                               facing.z=-1;
+
+                                                                               flatfacing=DoRotation(facing,0,player[i].rotation+180,0);
+                                                                               if(cameramode){facing=flatfacing;}
+                                                                               else{
+                                                                                       facing=DoRotation(facing,-rotation2,0,0);
+                                                                                       facing=DoRotation(facing,0,0-rotation,0);
+                                                                               }
+
+                                                                               player[0].lookrotation=-rotation;
+
+                                                                               player[i].targetheadrotation=rotation;
+                                                                               player[i].targetheadrotation2=rotation2;                        
+                                                                       }
+                                                                       if(i!=0&&player[i].aitype==playercontrolled&&indialogue==-1){
+                                                                               if(!animation[player[i].targetanimation].attack&&player[i].targetanimation!=staggerbackhighanim&&player[i].targetanimation!=staggerbackhardanim&&player[i].targetanimation!=crouchremoveknifeanim&&player[i].targetanimation!=removeknifeanim&&player[i].targetanimation!=backhandspringanim&&player[i].targetanimation!=dodgebackanim&&player[i].targetanimation!=walljumprightkickanim&&player[i].targetanimation!=walljumpleftkickanim){
+                                                                                       player[i].targetrotation=-player[i].lookrotation+180;
+                                                                               }
+
+                                                                               facing=0;
+                                                                               facing.z=-1;
+
+                                                                               flatfacing=DoRotation(facing,0,player[i].rotation+180,0);
+
+                                                                               facing=DoRotation(facing,-player[i].lookrotation2,0,0);
+                                                                               facing=DoRotation(facing,0,0-player[i].lookrotation,0);
+
+                                                                               player[i].targetheadrotation=player[i].lookrotation;
+                                                                               player[i].targetheadrotation2=player[i].lookrotation2;                  
+                                                                       }
+                                                                       if(indialogue!=-1){
+                                                                               rotatetarget=participantfacing[whichdialogue][indialogue][i];
+                                                                               Normalise(&rotatetarget);
+                                                                               player[i].targetheadrotation=-asin(0-rotatetarget.x);
+                                                                               player[i].targetheadrotation*=360/6.28;
+                                                                               if(rotatetarget.z<0)player[i].targetheadrotation=180-player[i].targetheadrotation;
+
+                                                                               player[i].targetheadrotation*=-1;
+                                                                               player[i].targetheadrotation+=180;
+                                                                               player[i].targetheadrotation2=-asin(rotatetarget.y)*360/6.28;
+                                                                       }
+
+                                                                       bool pause;
+
+                                                                       if(leveltime<.5)
+                                                                               numenvsounds=0;
+
+                                                                       player[i].avoidsomething=0;
+
+                                                                       for(j=0;j<objects.numobjects;j++){
+                                                                               if(objects.onfire[j]){
+                                                                                       if(findDistancefast(&objects.position[j],&player[i].coords)<objects.scale[j]*objects.scale[j]*200)
+                                                                                       {
+                                                                                               if(findDistancefast(&player[i].coords,&objects.position[j])<findDistancefast(&player[i].coords,&player[0].coords)){
+                                                                                                       player[i].collided=0;
+                                                                                                       player[i].avoidcollided=1;
+                                                                                                       if(player[i].avoidsomething==0||findDistancefast(&objects.position[j],&player[i].coords)<findDistancefast(&player[i].coords,&player[i].avoidwhere))
+                                                                                                               player[i].avoidwhere=objects.position[j];
+                                                                                               }
+                                                                                       }
+                                                                               }
+                                                                       }
+
+                                                                       //Add avoidwhere to players
+
+                                                                       for(j=0;j<numplayers;j++){
+                                                                               if(player[j].onfire){
+                                                                                       if(findDistancefast(&player[j].coords,&player[i].coords)<0.3*0.3*200)
+                                                                                       {
+                                                                                               if(findDistancefast(&player[i].coords,&player[j].coords)<findDistancefast(&player[i].coords,&player[0].coords)){
+                                                                                                       player[i].collided=0;
+                                                                                                       player[i].avoidcollided=1;
+                                                                                                       if(player[i].avoidsomething==0||findDistancefast(&player[j].coords,&player[i].coords)<findDistancefast(&player[i].coords,&player[i].avoidwhere))
+                                                                                                               player[i].avoidwhere=objects.position[j];
+                                                                                               }
+                                                                                       }
+                                                                               }
+                                                                       }
+
+                                                                       if(player[i].collided>.8)player[i].avoidcollided=0;
+                                                                       if(player[i].aitype!=playercontrolled&&indialogue==-1){
+                                                                               player[i].jumpclimb=0;
+                                                                               //AI
+                                                                               if(editorenabled)player[i].stunned=1;
+
+                                                                               player[i].pause=0;
+                                                                               //if(findDistancefastflat(&player[i].coords,&player[0].coords)<3/*&&player[0].coords.y>player[i].coords.y+.1*/)player[i].pause=1;
+                                                                               if(findDistancefastflat(&player[0].coords,&player[i].coords)<30&&player[0].coords.y>player[i].coords.y+2&&!player[0].onterrain)player[i].pause=1;
+
+                                                                               /*if(player[i].aitype==passivetype&&player[i].numwaypoints<=1){
+                                                                               player[i].forwardkeydown=0;
+                                                                               player[i].leftkeydown=0;
+                                                                               player[i].backkeydown=0;
+                                                                               player[i].rightkeydown=0;
+                                                                               player[i].crouchkeydown=0;
+                                                                               player[i].attackkeydown=0;
+                                                                               player[i].jumpkeydown=0;
+                                                                               player[i].throwkeydown=0;
+                                                                               }*/
+
+                                                                               if(player[i].aitype==pathfindtype){
+                                                                                       if(player[i].finalpathfindpoint==-1){
+                                                                                               float closestdistance;
+                                                                                               float tempdist;
+                                                                                               int closest;
+                                                                                               XYZ colpoint;
+                                                                                               closest=-1;
+                                                                                               closestdistance=-1;
+                                                                                               for(j=0;j<numpathpoints;j++){
+                                                                                                       if(closest==-1||findDistancefast(&player[i].finalfinaltarget,&pathpoint[j])<closestdistance){
+                                                                                                               closestdistance=findDistancefast(&player[i].finalfinaltarget,&pathpoint[j]);
+                                                                                                               closest=j;
+                                                                                                               player[i].finaltarget=pathpoint[j];
+                                                                                                       }
+                                                                                               }
+                                                                                               player[i].finalpathfindpoint=closest;
+                                                                                               for(j=0;j<numpathpoints;j++){
+                                                                                                       if(numpathpointconnect[j])
+                                                                                                               for(k=0;k<numpathpointconnect[j];k++){
+                                                                                                                       DistancePointLine(&player[i].finalfinaltarget, &pathpoint[j], &pathpoint[pathpointconnect[j][k]], &tempdist,&colpoint );
+                                                                                                                       if(tempdist*tempdist<closestdistance){
+                                                                                                                               if(findDistance(&colpoint,&pathpoint[j])+findDistance(&colpoint,&pathpoint[pathpointconnect[j][k]])<findDistance(&pathpoint[j],&pathpoint[pathpointconnect[j][k]])+.1){
+                                                                                                                                       closestdistance=tempdist*tempdist;
+                                                                                                                                       closest=j;
+                                                                                                                                       player[i].finaltarget=colpoint;
+                                                                                                                               }
+                                                                                                                       }
+                                                                                                               }
+                                                                                               }
+                                                                                               player[i].finalpathfindpoint=closest;
+
+                                                                                       }
+                                                                                       if(player[i].targetpathfindpoint==-1){
+                                                                                               float closestdistance;
+                                                                                               float tempdist;
+                                                                                               int closest;
+                                                                                               XYZ colpoint;
+                                                                                               closest=-1;
+                                                                                               closestdistance=-1;
+                                                                                               if(player[i].lastpathfindpoint==-1){
+                                                                                                       for(j=0;j<numpathpoints;j++){
+                                                                                                               if(j!=player[i].lastpathfindpoint)
+                                                                                                                       if(closest==-1||(findDistancefast(&player[i].coords,&pathpoint[j])<closestdistance/*&&findDistancefast(&player[i].finaltarget,&pathpoint[j])<findDistancefast(&player[i].finaltarget,&player[i].coords)*/)){
+                                                                                                                               closestdistance=findDistancefast(&player[i].coords,&pathpoint[j]);
+                                                                                                                               closest=j;
+                                                                                                                       }
+                                                                                                       }
+                                                                                                       player[i].targetpathfindpoint=closest;
+                                                                                                       for(j=0;j<numpathpoints;j++){
+                                                                                                               if(j!=player[i].lastpathfindpoint)
+                                                                                                                       if(numpathpointconnect[j])
+                                                                                                                               for(k=0;k<numpathpointconnect[j];k++){
+                                                                                                                                       DistancePointLine(&player[i].coords, &pathpoint[j], &pathpoint[pathpointconnect[j][k]], &tempdist,&colpoint );
+                                                                                                                                       if(tempdist*tempdist<closestdistance){
+                                                                                                                                               if(findDistance(&colpoint,&pathpoint[j])+findDistance(&colpoint,&pathpoint[pathpointconnect[j][k]])<findDistance(&pathpoint[j],&pathpoint[pathpointconnect[j][k]])+.1){
+                                                                                                                                                       //if(findDistancefast(&player[i].finaltarget,&colpoint)<findDistancefast(&player[i].finaltarget,&player[i].coords)){
+                                                                                                                                                       closestdistance=tempdist*tempdist;
+                                                                                                                                                       closest=j;
+                                                                                                                                                       //}
+                                                                                                                                               }
+                                                                                                                                       }
+                                                                                                                               }
+                                                                                                       }
+                                                                                                       player[i].targetpathfindpoint=closest;
+                                                                                               }
+                                                                                               else
+                                                                                               {
+                                                                                                       for(j=0;j<numpathpoints;j++){
+                                                                                                               if(j!=player[i].lastpathfindpoint&&j!=player[i].lastpathfindpoint2&&j!=player[i].lastpathfindpoint3&&j!=player[i].lastpathfindpoint4)
+                                                                                                               {
+                                                                                                                       connected=0;
+                                                                                                                       if(numpathpointconnect[j])
+                                                                                                                               for(k=0;k<numpathpointconnect[j];k++){
+                                                                                                                                       if(pathpointconnect[j][k]==player[i].lastpathfindpoint)connected=1;
+                                                                                                                               }
+                                                                                                                               if(!connected)
+                                                                                                                                       if(numpathpointconnect[player[i].lastpathfindpoint])
+                                                                                                                                               for(k=0;k<numpathpointconnect[player[i].lastpathfindpoint];k++){
+                                                                                                                                                       if(pathpointconnect[player[i].lastpathfindpoint][k]==j)connected=1;
+                                                                                                                                               }
+                                                                                                                                               if(connected){
+                                                                                                                                                       tempdist=findPathDist(j,player[i].finalpathfindpoint);
+                                                                                                                                                       if(closest==-1||tempdist<closestdistance){
+                                                                                                                                                               closestdistance=tempdist;
+                                                                                                                                                               closest=j;
+                                                                                                                                                       }
+                                                                                                                                               }
+                                                                                                               }
+                                                                                                       }
+                                                                                                       player[i].targetpathfindpoint=closest;
+                                                                                               }
+                                                                                       }
+                                                                                       player[i].losupdatedelay-=multiplier;
+
+                                                                                       rotatetarget=pathpoint[player[i].targetpathfindpoint]-player[i].coords;
+                                                                                       Normalise(&rotatetarget);
+                                                                                       player[i].targetrotation=-asin(0-rotatetarget.x);
+                                                                                       player[i].targetrotation*=360/6.28;
+                                                                                       if(rotatetarget.z<0)player[i].targetrotation=180-player[i].targetrotation;
+                                                                                       player[i].lookrotation=player[i].targetrotation;
+                                                                                       //player[i].aiupdatedelay=.05;
+
+                                                                                       if(findDistancefastflat(&player[i].coords,&pathpoint[player[i].targetpathfindpoint])<.6){
+                                                                                               player[i].lastpathfindpoint4=player[i].lastpathfindpoint3;
+                                                                                               player[i].lastpathfindpoint3=player[i].lastpathfindpoint2;
+                                                                                               player[i].lastpathfindpoint2=player[i].lastpathfindpoint;
+                                                                                               player[i].lastpathfindpoint=player[i].targetpathfindpoint;
+                                                                                               if(player[i].lastpathfindpoint2==-1)player[i].lastpathfindpoint2=player[i].lastpathfindpoint;
+                                                                                               if(player[i].lastpathfindpoint3==-1)player[i].lastpathfindpoint3=player[i].lastpathfindpoint2;
+                                                                                               if(player[i].lastpathfindpoint4==-1)player[i].lastpathfindpoint4=player[i].lastpathfindpoint3;
+                                                                                               player[i].targetpathfindpoint=-1;
+                                                                                       }
+                                                                                       if(findDistancefastflat(&player[i].coords,&player[i].finalfinaltarget)<findDistancefastflat(&player[i].coords,&player[i].finaltarget)||findDistancefastflat(&player[i].coords,&player[i].finaltarget)<.6*(player[i].scale*5)*(player[i].scale*5)||player[i].lastpathfindpoint==player[i].finalpathfindpoint){
+                                                                                               player[i].aitype=passivetype;
+                                                                                       }
+
+                                                                                       player[i].forwardkeydown=1;
+                                                                                       player[i].leftkeydown=0;
+                                                                                       player[i].backkeydown=0;
+                                                                                       player[i].rightkeydown=0;
+                                                                                       player[i].crouchkeydown=0;
+                                                                                       player[i].attackkeydown=0;
+                                                                                       player[i].throwkeydown=0;
+
+                                                                                       if(player[i].avoidcollided>.8&&!player[i].jumpkeydown&&player[i].collided<.8)player[i].targetrotation+=90*(player[i].whichdirection*2-1);
+
+                                                                                       if(player[i].collided<1||player[i].targetanimation!=jumpupanim)player[i].jumpkeydown=0;
+                                                                                       if((player[i].collided>.8&&player[i].jumppower>=5))player[i].jumpkeydown=1;
+
+                                                                                       if((tutoriallevel!=1||cananger)&&hostile&&!player[0].dead&&findDistancefast(&player[i].coords,&player[0].coords)<400&&player[i].occluded<25){
+                                                                                               if(findDistancefast(&player[i].coords,&player[0].coords)<12&&animation[player[0].targetanimation].height!=lowheight&&!editorenabled&&(player[0].coords.y<player[i].coords.y+5||player[0].onterrain))
+                                                                                                       player[i].aitype=attacktypecutoff;
+                                                                                               if(findDistancefast(&player[i].coords,&player[0].coords)<30&&animation[player[0].targetanimation].height==highheight&&!editorenabled)
+                                                                                                       player[i].aitype=attacktypecutoff;
+
+                                                                                               if(player[i].losupdatedelay<0&&!editorenabled&&player[i].occluded<2){
+                                                                                                       player[i].losupdatedelay=.2;
+                                                                                                       for(j=0;j<numplayers;j++){
+                                                                                                               if(j==0||player[j].skeleton.free||player[j].aitype!=passivetype){
+                                                                                                                       if(abs(Random()%2)||animation[player[j].targetanimation].height!=lowheight||j!=0)
+                                                                                                                               if(findDistancefast(&player[i].coords,&player[j].coords)<400)
+                                                                                                                                       if(normaldotproduct(player[i].facing,player[j].coords-player[i].coords)>0)
+                                                                                                                                               if(player[j].coords.y<player[i].coords.y+5||player[j].onterrain)
+                                                                                                                                                       if((-1==checkcollide(DoRotation(player[i].skeleton.joints[player[i].skeleton.jointlabels[head]].position,0,player[i].rotation,0)*player[i].scale+player[i].coords,DoRotation(player[j].skeleton.joints[player[j].skeleton.jointlabels[head]].position,0,player[j].rotation,0)*player[j].scale+player[j].coords)&&!player[j].isWallJump())||(player[j].targetanimation==hanganim&&normaldotproduct(player[j].facing,player[i].coords-player[j].coords)<0)){
+                                                                                                                                                               player[i].aitype=searchtype;
+                                                                                                                                                               player[i].lastchecktime=12;
+                                                                                                                                                               player[i].lastseen=player[j].coords;
+                                                                                                                                                               player[i].lastseentime=12;
+                                                                                                                                                       }
+                                                                                                               }
+                                                                                                       }
+                                                                                               }
+                                                                                       }       
+                                                                                       if(player[i].aitype==attacktypecutoff&&musictype!=2){
+                                                                                               if(player[i].creature!=wolftype){
+                                                                                                       player[i].stunned=.6;
+                                                                                                       player[i].surprised=.6;
+                                                                                               }
+                                                                                       }
+                                                                               }
+
+                                                                               if(player[i].aitype!=passivetype&&leveltime>.5){
+                                                                                       player[i].howactive=typeactive;
+                                                                               }
+
+                                                                               if(player[i].aitype==passivetype){
+                                                                                       player[i].aiupdatedelay-=multiplier;
+                                                                                       player[i].losupdatedelay-=multiplier;
+                                                                                       player[i].lastseentime+=multiplier;
+                                                                                       player[i].pausetime-=multiplier;
+                                                                                       if(player[i].lastseentime>1)player[i].lastseentime=1;
+
+                                                                                       if(player[i].aiupdatedelay<0){
+                                                                                               if(player[i].numwaypoints>1&&player[i].howactive==typeactive&&player[i].pausetime<=0){
+                                                                                                       rotatetarget=player[i].waypoints[player[i].waypoint]-player[i].coords;
+                                                                                                       Normalise(&rotatetarget);
+                                                                                                       player[i].targetrotation=-asin(0-rotatetarget.x);
+                                                                                                       player[i].targetrotation*=360/6.28;
+                                                                                                       if(rotatetarget.z<0)player[i].targetrotation=180-player[i].targetrotation;
+                                                                                                       player[i].lookrotation=player[i].targetrotation;
+                                                                                                       player[i].aiupdatedelay=.05;
+
+                                                                                                       if(findDistancefastflat(&player[i].coords,&player[i].waypoints[player[i].waypoint])<1){
+                                                                                                               if(player[i].waypointtype[player[i].waypoint]==wppause)player[i].pausetime=4;
+                                                                                                               player[i].waypoint++;
+                                                                                                               if(player[i].waypoint>player[i].numwaypoints-1)player[i].waypoint=0;
+
+                                                                                                       }
+                                                                                               }                       
+
+                                                                                               if(player[i].numwaypoints>1&&player[i].howactive==typeactive&&player[i].pausetime<=0)player[i].forwardkeydown=1;
+                                                                                               else player[i].forwardkeydown=0;
+                                                                                               player[i].leftkeydown=0;
+                                                                                               player[i].backkeydown=0;
+                                                                                               player[i].rightkeydown=0;
+                                                                                               player[i].crouchkeydown=0;
+                                                                                               player[i].attackkeydown=0;
+                                                                                               player[i].throwkeydown=0;
+
+                                                                                               if(player[i].avoidcollided>.8&&!player[i].jumpkeydown&&player[i].collided<.8){
+                                                                                                       if(!player[i].avoidsomething)player[i].targetrotation+=90*(player[i].whichdirection*2-1);
+                                                                                                       else{
+                                                                                                               XYZ leftpos,rightpos;
+                                                                                                               float leftdist,rightdist;
+                                                                                                               leftpos = player[i].coords+DoRotation(player[i].facing,0,90,0);
+                                                                                                               rightpos = player[i].coords-DoRotation(player[i].facing,0,90,0);
+                                                                                                               leftdist = findDistancefast(&leftpos, &player[i].avoidwhere);
+                                                                                                               rightdist = findDistancefast(&rightpos, &player[i].avoidwhere);
+                                                                                                               if(leftdist<rightdist)player[i].targetrotation+=90;
+                                                                                                               else player[i].targetrotation-=90;
+                                                                                                       }
+                                                                                               }
+                                                                                       }                       
+                                                                                       if(player[i].collided<1||player[i].targetanimation!=jumpupanim)player[i].jumpkeydown=0;
+                                                                                       if((player[i].collided>.8&&player[i].jumppower>=5))player[i].jumpkeydown=1;
+
+
+                                                                                       if(!editorenabled){
+                                                                                               if(player[i].howactive<typesleeping)
+                                                                                                       if(numenvsounds>0&&(tutoriallevel!=1||cananger)&&hostile)
+                                                                                                               for(j=0;j<numenvsounds;j++){
+                                                                                                                       if(findDistancefast(&player[i].coords,&envsound[j])<2*(envsoundvol[j]+envsoundvol[j]*(player[i].creature==rabbittype)*3)){
+                                                                                                                               player[i].aitype=attacktypecutoff;
+                                                                                                                       }
+                                                                                                               }
+
+                                                                                                               if(player[i].howactive==typesleeping)
+                                                                                                                       if(numenvsounds>0&&(tutoriallevel!=1||cananger)&&hostile)
+                                                                                                                               for(j=0;j<numenvsounds;j++){
+                                                                                                                                       if(envsoundvol[j]>14)
+                                                                                                                                               if(findDistancefast(&player[i].coords,&envsound[j])<2*((envsoundvol[j]-14)+(envsoundvol[j]-14)*(player[i].creature==rabbittype)*3)){
+                                                                                                                                                       player[i].aitype=attacktypecutoff;
+                                                                                                                                               }
+                                                                                                                               }
+
+                                                                                                                               if(player[i].aitype!=passivetype){
+                                                                                                                                       if(player[i].howactive==typesleeping){
+                                                                                                                                               player[i].targetanimation=getupfromfrontanim;
+                                                                                                                                               player[i].targetframe=0;
+                                                                                                                                               player[i].target=0;
+                                                                                                                                       }
+
+                                                                                                                                       player[i].howactive=typeactive;
+                                                                                                                               }
+                                                                                       }                       
+
+                                                                                       if(player[i].howactive<typesleeping&&((tutoriallevel!=1||cananger)&&hostile)&&!player[0].dead&&findDistancefast(&player[i].coords,&player[0].coords)<400&&player[i].occluded<25){
+                                                                                               if(findDistancefast(&player[i].coords,&player[0].coords)<12&&animation[player[0].targetanimation].height!=lowheight&&!editorenabled)
+                                                                                                       player[i].aitype=attacktypecutoff;
+                                                                                               if(findDistancefast(&player[i].coords,&player[0].coords)<30&&animation[player[0].targetanimation].height==highheight&&!editorenabled)
+                                                                                                       player[i].aitype=attacktypecutoff;
+
+                                                                                               if(player[i].creature==wolftype){
+                                                                                                       XYZ windsmell;
+                                                                                                       float smelldistance;
+                                                                                                       smelldistance=50;
+                                                                                                       for(j=0;j<numplayers;j++){
+                                                                                                               if(j==0||(player[j].dead&&player[j].bloodloss>0)){
+                                                                                                                       if(j==0&&player[j].num_weapons>0){
+                                                                                                                               if(weapons.bloody[player[j].weaponids[0]])smelldistance=100;
+                                                                                                                               if(player[j].num_weapons==2)
+                                                                                                                                       if(weapons.bloody[player[j].weaponids[1]])smelldistance=100;
+                                                                                                                       }
+                                                                                                                       if(j!=0){
+                                                                                                                               smelldistance=100;
+                                                                                                                       }
+                                                                                                                       windsmell=windvector;
+                                                                                                                       Normalise(&windsmell);
+                                                                                                                       windsmell=windsmell*2+player[j].coords;
+                                                                                                                       if(findDistancefast(&player[i].coords,&windsmell)<smelldistance&&!editorenabled)
+                                                                                                                               player[i].aitype=attacktypecutoff;
+                                                                                                               }
+                                                                                                       }
+                                                                                               }
+
+                                                                                               if(player[i].howactive<typesleeping&&player[i].losupdatedelay<0&&!editorenabled&&player[i].occluded<2){
+                                                                                                       player[i].losupdatedelay=.2;
+                                                                                                       for(j=0;j<numplayers;j++){
+                                                                                                               if(j==0||player[j].skeleton.free||player[j].aitype!=passivetype){
+                                                                                                                       if(abs(Random()%2)||animation[player[j].targetanimation].height!=lowheight||j!=0)
+                                                                                                                               if(findDistancefast(&player[i].coords,&player[j].coords)<400)
+                                                                                                                                       if(normaldotproduct(player[i].facing,player[j].coords-player[i].coords)>0)
+                                                                                                                                               if((-1==checkcollide(DoRotation(player[i].skeleton.joints[player[i].skeleton.jointlabels[head]].position,0,player[i].rotation,0)*player[i].scale+player[i].coords,DoRotation(player[j].skeleton.joints[player[j].skeleton.jointlabels[head]].position,0,player[j].rotation,0)*player[j].scale+player[j].coords)&&!player[j].isWallJump())||(player[j].targetanimation==hanganim&&normaldotproduct(player[j].facing,player[i].coords-player[j].coords)<0)){
+                                                                                                                                                       player[i].lastseentime-=.2;
+                                                                                                                                                       if(j==0&&animation[player[j].targetanimation].height==lowheight)player[i].lastseentime-=.4;
+                                                                                                                                                       else player[i].lastseentime-=.6;                                                                
+                                                                                                                                               }
+                                                                                                                                               if(player[i].lastseentime<=0){
+                                                                                                                                                       player[i].aitype=searchtype;
+                                                                                                                                                       player[i].lastchecktime=12;
+                                                                                                                                                       player[i].lastseen=player[j].coords;
+                                                                                                                                                       player[i].lastseentime=12;
+                                                                                                                                               }
+                                                                                                               }
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+                                                                                       if(player[i].aitype==attacktypecutoff&&musictype!=2){
+                                                                                               if(player[i].creature!=wolftype){
+                                                                                                       player[i].stunned=.6;
+                                                                                                       player[i].surprised=.6;
+                                                                                               }
+                                                                                               if(player[i].creature==wolftype){
+                                                                                                       player[i].stunned=.47;
+                                                                                                       player[i].surprised=.47;
+                                                                                               }
+                                                                                               numseen++;
+                                                                                       }
+                                                                               }               
+
+                                                                               if(player[i].aitype==searchtype){
+                                                                                       player[i].aiupdatedelay-=multiplier;
+                                                                                       player[i].losupdatedelay-=multiplier;
+                                                                                       if(!player[i].pause)player[i].lastseentime-=multiplier;
+                                                                                       player[i].lastchecktime-=multiplier;
+
+                                                                                       if(player[i].isRun()&&!player[i].onground){
+                                                                                               if(player[i].coords.y>terrain.getHeight(player[i].coords.x,player[i].coords.z)+10){
+                                                                                                       test2=player[i].coords+player[i].facing;
+                                                                                                       test2.y+=5;
+                                                                                                       test=player[i].coords+player[i].facing;
+                                                                                                       test.y-=10;
+                                                                                                       j=checkcollide(test2,test,player[i].laststanding);
+                                                                                                       if(j==-1)j=checkcollide(test2,test);
+                                                                                                       if(j==-1){
+                                                                                                               player[i].velocity=0;
+                                                                                                               player[i].targetanimation=player[i].getStop();
+                                                                                                               player[i].targetframe=0;
+                                                                                                               player[i].target=0;
+                                                                                                               player[i].targetrotation+=180;
+                                                                                                               player[i].stunned=.5;
+                                                                                                               //player[i].aitype=passivetype;
+                                                                                                               player[i].aitype=pathfindtype;
+                                                                                                               player[i].finalfinaltarget=player[i].waypoints[player[i].waypoint];
+                                                                                                               player[i].finalpathfindpoint=-1;
+                                                                                                               player[i].targetpathfindpoint=-1;
+                                                                                                               player[i].lastpathfindpoint=-1;
+                                                                                                               player[i].lastpathfindpoint2=-1;
+                                                                                                               player[i].lastpathfindpoint3=-1;
+                                                                                                               player[i].lastpathfindpoint4=-1;
+                                                                                                       }
+                                                                                                       else player[i].laststanding=j;
+                                                                                               }
+                                                                                       }       
+                                                                                       if(player[i].aiupdatedelay<0){
+                                                                                               rotatetarget=player[i].lastseen-player[i].coords;
+                                                                                               Normalise(&rotatetarget);
+                                                                                               player[i].targetrotation=-asin(0-rotatetarget.x);
+                                                                                               player[i].targetrotation*=360/6.28;
+                                                                                               if(rotatetarget.z<0)player[i].targetrotation=180-player[i].targetrotation;
+                                                                                               player[i].lookrotation=player[i].targetrotation;
+                                                                                               player[i].aiupdatedelay=.05;
+                                                                                               player[i].forwardkeydown=1;
+
+                                                                                               if(findDistancefastflat(&player[i].coords,&player[i].lastseen)<1*(player[i].scale*5)*(player[i].scale*5)||player[i].lastchecktime<0){
+                                                                                                       player[i].forwardkeydown=0;
+                                                                                                       player[i].aiupdatedelay=1;
+                                                                                                       player[i].lastseen.x+=(float(Random()%100)-50)/25;
+                                                                                                       player[i].lastseen.z+=(float(Random()%100)-50)/25;
+                                                                                                       player[i].lastchecktime=3;
+                                                                                               }
+
+                                                                                               player[i].leftkeydown=0;
+                                                                                               player[i].backkeydown=0;
+                                                                                               player[i].rightkeydown=0;
+                                                                                               player[i].crouchkeydown=0;
+                                                                                               player[i].attackkeydown=0;
+                                                                                               player[i].throwkeydown=0;
+
+                                                                                               if(player[i].avoidcollided>.8&&!player[i].jumpkeydown&&player[i].collided<.8){
+                                                                                                       if(!player[i].avoidsomething)player[i].targetrotation+=90*(player[i].whichdirection*2-1);
+                                                                                                       else{
+                                                                                                               XYZ leftpos,rightpos;
+                                                                                                               float leftdist,rightdist;
+                                                                                                               leftpos = player[i].coords+DoRotation(player[i].facing,0,90,0);
+                                                                                                               rightpos = player[i].coords-DoRotation(player[i].facing,0,90,0);
+                                                                                                               leftdist = findDistancefast(&leftpos, &player[i].avoidwhere);
+                                                                                                               rightdist = findDistancefast(&rightpos, &player[i].avoidwhere);
+                                                                                                               if(leftdist<rightdist)player[i].targetrotation+=90;
+                                                                                                               else player[i].targetrotation-=90;
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+                                                                                       if(player[i].collided<1||player[i].targetanimation!=jumpupanim)player[i].jumpkeydown=0;
+                                                                                       if((player[i].collided>.8&&player[i].jumppower>=5))player[i].jumpkeydown=1;
+
+                                                                                       if(numenvsounds>0&&((tutoriallevel!=1||cananger)&&hostile))
+                                                                                               for(j=0;j<numenvsounds;j++){
+                                                                                                       if(findDistancefast(&player[i].coords,&envsound[j])<2*(envsoundvol[j]+envsoundvol[j]*(player[i].creature==rabbittype)*3)){
+                                                                                                               player[i].aitype=attacktypecutoff;
+                                                                                                       }
+                                                                                               }
+
+                                                                                               if(!player[0].dead&&player[i].losupdatedelay<0&&!editorenabled&&player[i].occluded<2&&((tutoriallevel!=1||cananger)&&hostile)){
+                                                                                                       player[i].losupdatedelay=.2;
+                                                                                                       if(findDistancefast(&player[i].coords,&player[0].coords)<4&&animation[player[i].targetanimation].height!=lowheight)
+                                                                                                       {player[i].aitype=attacktypecutoff;
+                                                                                                       player[i].lastseentime=1;}
+                                                                                                       if(abs(Random()%2)||animation[player[i].targetanimation].height!=lowheight)
+                                                                                                               if(findDistancefast(&player[i].coords,&player[0].coords)<400)
+                                                                                                                       if(normaldotproduct(player[i].facing,player[0].coords-player[i].coords)>0)
+                                                                                                                               if((-1==checkcollide(DoRotation(player[i].skeleton.joints[player[i].skeleton.jointlabels[head]].position,0,player[i].rotation,0)*player[i].scale+player[i].coords,DoRotation(player[0].skeleton.joints[player[0].skeleton.jointlabels[head]].position,0,player[0].rotation,0)*player[0].scale+player[0].coords))||(player[j].targetanimation==hanganim&&normaldotproduct(player[j].facing,player[i].coords-player[j].coords)<0)){
+                                                                                                                                       player[i].aitype=attacktypecutoff;
+                                                                                                                                       player[i].lastseentime=1;
+                                                                                                                               }
+                                                                                               }
+                                                                                               if(player[i].lastseentime<0){
+                                                                                                       //player[i].aitype=passivetype;
+                                                                                                       numescaped++;
+                                                                                                       player[i].aitype=pathfindtype;
+                                                                                                       player[i].finalfinaltarget=player[i].waypoints[player[i].waypoint];
+                                                                                                       player[i].finalpathfindpoint=-1;
+                                                                                                       player[i].targetpathfindpoint=-1;
+                                                                                                       player[i].lastpathfindpoint=-1;
+                                                                                                       player[i].lastpathfindpoint2=-1;
+                                                                                                       player[i].lastpathfindpoint3=-1;
+                                                                                                       player[i].lastpathfindpoint4=-1;
+                                                                                               }
+                                                                               }
+
+                                                                               if(player[i].aitype!=gethelptype){
+                                                                                       player[i].runninghowlong=0;
+                                                                               }
+
+                                                                               if(player[i].aitype==gethelptype){
+                                                                                       player[i].runninghowlong+=multiplier;
+                                                                                       player[i].aiupdatedelay-=multiplier;
+
+                                                                                       if(player[i].aiupdatedelay<0||player[i].ally==0){
+                                                                                               player[i].aiupdatedelay=.2;
+
+                                                                                               int closest;
+                                                                                               float closestdist;
+                                                                                               closest=-1;
+                                                                                               closestdist=-1;
+                                                                                               float distance;
+
+                                                                                               if(!player[i].ally){
+                                                                                                       for(j=0;j<numplayers;j++){
+                                                                                                               if(j!=i&&j!=0&&!player[j].dead&&player[j].howactive<typedead1&&!player[j].skeleton.free&&player[j].aitype==passivetype){
+                                                                                                                       distance=findDistancefast(&player[i].coords,&player[j].coords);
+                                                                                                                       if(closestdist==-1||distance<closestdist){
+                                                                                                                               closestdist=distance;
+                                                                                                                               closest=j;
+                                                                                                                       }
+                                                                                                                       closest=j;
+                                                                                                               }
+                                                                                                       }
+                                                                                                       if(closest!=-1)player[i].ally=closest;
+                                                                                                       else player[i].ally=0;
+                                                                                                       player[i].lastseen=player[0].coords;
+                                                                                                       player[i].lastseentime=12;
+                                                                                               }
+
+
+                                                                                               player[i].lastchecktime=12;
+                                                                                               //player[i].lastseentime-=.5;
+
+                                                                                               facing=player[i].coords;
+                                                                                               flatfacing=player[player[i].ally].coords;
+                                                                                               facing.y+=player[i].skeleton.joints[player[i].skeleton.jointlabels[head]].position.y*player[i].scale;
+                                                                                               flatfacing.y+=player[player[i].ally].skeleton.joints[player[player[i].ally].skeleton.jointlabels[head]].position.y*player[player[i].ally].scale;
+                                                                                               if(-1!=checkcollide(facing,flatfacing))
+                                                                                                       player[i].lastseentime-=.1;
+
+                                                                                               if(player[i].ally<=0||player[player[i].ally].skeleton.free||player[player[i].ally].aitype!=passivetype||player[i].lastseentime<=0){
+                                                                                                       player[i].aitype=searchtype;
+                                                                                                       player[i].lastseentime=12;
+                                                                                               }
+
+                                                                                               if(player[i].ally>0){
+                                                                                                       rotatetarget=player[player[i].ally].coords-player[i].coords;
+                                                                                                       Normalise(&rotatetarget);
+                                                                                                       player[i].targetrotation=-asin(0-rotatetarget.x);
+                                                                                                       player[i].targetrotation*=360/6.28;
+                                                                                                       if(rotatetarget.z<0)player[i].targetrotation=180-player[i].targetrotation;
+                                                                                                       player[i].lookrotation=player[i].targetrotation;
+                                                                                                       player[i].aiupdatedelay=.05;
+                                                                                                       player[i].forwardkeydown=1;                                     
+
+                                                                                                       if(findDistancefastflat(&player[i].coords,&player[player[i].ally].coords)<3){
+                                                                                                               player[i].aitype=searchtype;
+                                                                                                               player[i].lastseentime=12;
+                                                                                                               player[player[i].ally].aitype=searchtype;
+                                                                                                               if(player[player[i].ally].lastseentime<player[i].lastseentime){
+                                                                                                                       player[player[i].ally].lastseen=player[i].lastseen;
+                                                                                                                       player[player[i].ally].lastseentime=player[i].lastseentime;
+                                                                                                                       player[player[i].ally].lastchecktime=player[i].lastchecktime;
+                                                                                                               }
+                                                                                                       }
+
+                                                                                                       if(player[i].avoidcollided>.8&&!player[i].jumpkeydown&&player[i].collided<.8){
+                                                                                                               if(!player[i].avoidsomething)player[i].targetrotation+=90*(player[i].whichdirection*2-1);
+                                                                                                               else{
+                                                                                                                       XYZ leftpos,rightpos;
+                                                                                                                       float leftdist,rightdist;
+                                                                                                                       leftpos = player[i].coords+DoRotation(player[i].facing,0,90,0);
+                                                                                                                       rightpos = player[i].coords-DoRotation(player[i].facing,0,90,0);
+                                                                                                                       leftdist = findDistancefast(&leftpos, &player[i].avoidwhere);
+                                                                                                                       rightdist = findDistancefast(&rightpos, &player[i].avoidwhere);
+                                                                                                                       if(leftdist<rightdist)player[i].targetrotation+=90;
+                                                                                                                       else player[i].targetrotation-=90;
+                                                                                                               }
+                                                                                                       }
+                                                                                               }
+
+                                                                                               player[i].leftkeydown=0;
+                                                                                               player[i].backkeydown=0;
+                                                                                               player[i].rightkeydown=0;
+                                                                                               player[i].crouchkeydown=0;
+                                                                                               player[i].attackkeydown=0;
+                                                                                       }
+                                                                                       if(player[i].collided<1||player[i].targetanimation!=jumpupanim)player[i].jumpkeydown=0;
+                                                                                       if((player[i].collided>.8&&player[i].jumppower>=5))player[i].jumpkeydown=1;
+                                                                               }
+
+                                                                               if(player[i].aitype==getweapontype){
+                                                                                       player[i].aiupdatedelay-=multiplier;
+                                                                                       player[i].lastchecktime-=multiplier;
+
+                                                                                       if(player[i].aiupdatedelay<0){
+                                                                                               player[i].aiupdatedelay=.2;
+
+                                                                                               int closest;
+                                                                                               float closestdist;
+                                                                                               closest=-1;
+                                                                                               closestdist=-1;
+                                                                                               float distance;
+
+                                                                                               if(player[i].ally<0){
+                                                                                                       for(j=0;j<weapons.numweapons;j++){
+                                                                                                               if(weapons.owner[j]==-1){
+                                                                                                                       distance=findDistancefast(&player[i].coords,&weapons.position[j]);
+                                                                                                                       if(closestdist==-1||distance<closestdist){
+                                                                                                                               closestdist=distance;
+                                                                                                                               closest=j;
+                                                                                                                       }
+                                                                                                                       closest=j;
+                                                                                                               }
+                                                                                                       }
+                                                                                                       if(closest!=-1)player[i].ally=closest;
+                                                                                                       else player[i].ally=-1;
+                                                                                               }
+
+                                                                                               player[i].lastseentime=12;
+
+                                                                                               if(!player[0].dead&&((tutoriallevel!=1||cananger)&&hostile))
+                                                                                                       if(player[i].ally<0||player[i].weaponactive!=-1||player[i].lastchecktime<=0){
+                                                                                                               player[i].aitype=attacktypecutoff;
+                                                                                                               player[i].lastseentime=1;
+                                                                                                       }                                       
+                                                                                                       if(!player[0].dead)
+                                                                                                               if(player[i].ally>=0){
+                                                                                                                       if(weapons.owner[player[i].ally]!=-1||findDistancefast(&player[i].coords,&weapons.position[player[i].ally])>16){
+                                                                                                                               player[i].aitype=attacktypecutoff;
+                                                                                                                               player[i].lastseentime=1;
+                                                                                                                       }
+                                                                                                                       rotatetarget=weapons.position[player[i].ally]-player[i].coords;
+                                                                                                                       Normalise(&rotatetarget);
+                                                                                                                       player[i].targetrotation=-asin(0-rotatetarget.x);
+                                                                                                                       player[i].targetrotation*=360/6.28;
+                                                                                                                       if(rotatetarget.z<0)player[i].targetrotation=180-player[i].targetrotation;
+                                                                                                                       player[i].lookrotation=player[i].targetrotation;
+                                                                                                                       player[i].aiupdatedelay=.05;
+                                                                                                                       player[i].forwardkeydown=1;                                     
+
+
+                                                                                                                       if(player[i].avoidcollided>.8&&!player[i].jumpkeydown&&player[i].collided<.8){
+                                                                                                                               if(!player[i].avoidsomething)player[i].targetrotation+=90*(player[i].whichdirection*2-1);
+                                                                                                                               else{
+                                                                                                                                       XYZ leftpos,rightpos;
+                                                                                                                                       float leftdist,rightdist;
+                                                                                                                                       leftpos = player[i].coords+DoRotation(player[i].facing,0,90,0);
+                                                                                                                                       rightpos = player[i].coords-DoRotation(player[i].facing,0,90,0);
+                                                                                                                                       leftdist = findDistancefast(&leftpos, &player[i].avoidwhere);
+                                                                                                                                       rightdist = findDistancefast(&rightpos, &player[i].avoidwhere);
+                                                                                                                                       if(leftdist<rightdist)player[i].targetrotation+=90;
+                                                                                                                                       else player[i].targetrotation-=90;
+                                                                                                                               }
+                                                                                                                       }
+                                                                                                                       /*if(findDistancefast(&player[i].coords,&weapons.position[player[i].ally])<3){
+                                                                                                                       if(abs(Random()%6)){
+                                                                                                                       player[i].crouchkeydown=1;
+                                                                                                                       if(!findDistancefast(&player[i].coords,&weapons.position[player[i].ally])<1){
+                                                                                                                       if(player[i].isRun()){
+                                                                                                                       player[i].targetframe=0;
+                                                                                                                       player[i].target=0;
+                                                                                                                       player[i].targetanimation=sneakanim;
+                                                                                                                       }
+                                                                                                                       }
+                                                                                                                       else player[i].forwardkeydown=0;
+                                                                                                                       }
+                                                                                                                       else player[i].crouchkeydown=0;
+                                                                                                                       }
+                                                                                                                       else player[i].crouchkeydown=0;*/
+                                                                                                               }
+
+                                                                                                               player[i].leftkeydown=0;
+                                                                                                               player[i].backkeydown=0;
+                                                                                                               player[i].rightkeydown=0;
+                                                                                                               player[i].attackkeydown=0;
+                                                                                                               player[i].throwkeydown=1;
+                                                                                                               player[i].crouchkeydown=0;      
+                                                                                                               if(player[i].targetanimation!=crouchremoveknifeanim&&player[i].targetanimation!=removeknifeanim)player[i].throwtogglekeydown=0;
+                                                                                                               player[i].drawkeydown=0;
+                                                                                       }
+                                                                                       if(player[i].collided<1||player[i].targetanimation!=jumpupanim)player[i].jumpkeydown=0;
+                                                                                       if((player[i].collided>.8&&player[i].jumppower>=5))player[i].jumpkeydown=1;
+                                                                               }
+
+                                                                               if(player[i].aitype==attacktypecutoff){
+                                                                                       player[i].aiupdatedelay-=multiplier;
+                                                                                       if(player[i].damage<player[i].damagetolerance*2/3)
+                                                                                               if((player[0].targetanimation==rabbitkickanim||player[0].targetanimation==knifethrowanim||(player[0].isFlip()&&normaldotproduct(player[0].facing,player[0].coords-player[i].coords)<0))&&!player[0].skeleton.free&&(player[i].aiupdatedelay<.1)){
+                                                                                                       player[i].attackkeydown=0;
+                                                                                                       if(player[i].isIdle())player[i].crouchkeydown=1;
+                                                                                                       if(player[0].targetanimation!=rabbitkickanim&&player[0].weaponactive!=-1){
+                                                                                                               if(weapons.type[player[0].weaponids[0]]==knife){
+                                                                                                                       if(player[i].isIdle()||player[i].isCrouch()||player[i].isRun()||player[i].isFlip()){
+                                                                                                                               if(abs(Random()%2==0))player[i].targetanimation=backhandspringanim;
+                                                                                                                               else player[i].targetanimation=rollanim;
+                                                                                                                               player[i].target=0;
+                                                                                                                               player[i].targetframe=0;
+                                                                                                                               player[i].targetrotation+=90*(abs(Random()%2)*2-1);
+                                                                                                                               player[i].wentforweapon=0;
+                                                                                                                       }
+                                                                                                                       if(player[i].targetanimation==jumpupanim||player[i].targetanimation==jumpdownanim){
+                                                                                                                               player[i].targetanimation=flipanim;
+                                                                                                                               player[i].target=0;
+                                                                                                                               player[i].targetframe=0;
+                                                                                                                       }
+                                                                                                               }
+                                                                                                       }
+                                                                                                       player[i].forwardkeydown=0;
+                                                                                                       player[i].aiupdatedelay=.02;
+                                                                                               }
+                                                                                               if(player[0].isFlip()&&!player[0].skeleton.free&&player[0].targetanimation!=walljumprightkickanim&&player[0].targetanimation!=walljumpleftkickanim){
+                                                                                                       if(findDistancefast(&player[0].coords,&player[i].coords)<25)
+                                                                                                               if((1-player[i].damage/player[i].damagetolerance)>.5)player[i].stunned=1;
+                                                                                               }
+                                                                                               if(player[i].wentforweapon<3)
+                                                                                                       for(j=0;j<weapons.numweapons;j++){
+                                                                                                               if(player[i].creature!=wolftype)
+                                                                                                                       if(player[i].num_weapons==0&&weapons.owner[j]==-1&&weapons.velocity[i].x==0&&weapons.velocity[i].z==0&&weapons.velocity[i].y==0){
+                                                                                                                               if(findDistancefast(&player[i].coords,&weapons.position[j])<16){
+                                                                                                                                       player[i].wentforweapon++;
+                                                                                                                                       player[i].lastchecktime=6;
+                                                                                                                                       player[i].aitype=getweapontype;
+                                                                                                                                       player[i].ally=-1;
+                                                                                                                               }
+                                                                                                                       }
+                                                                                                       }
+                                                                                                       if(player[i].damage<player[i].damagetolerance/2)
+                                                                                                               if(animation[player[i].targetanimation].height!=highheight)
+                                                                                                                       if(player[i].damage<player[i].damagetolerance*.5&&((player[0].targetanimation==walljumprightkickanim||player[0].targetanimation==walljumpleftkickanim)&&((player[i].aiupdatedelay<.15&&difficulty==2)||(player[i].aiupdatedelay<.08&&difficulty!=2)))){
+                                                                                                                               player[i].crouchkeydown=1;
+                                                                                                                       }
+                                                                                                                       if(player[i].isRun()&&!player[i].onground){
+                                                                                                                               if(player[i].coords.y>terrain.getHeight(player[i].coords.x,player[i].coords.z)+10){
+                                                                                                                                       test2=player[i].coords+player[i].facing;
+                                                                                                                                       test2.y+=5;
+                                                                                                                                       test=player[i].coords+player[i].facing;
+                                                                                                                                       test.y-=10;
+                                                                                                                                       j=checkcollide(test2,test,player[i].laststanding);
+                                                                                                                                       if(j==-1)j=checkcollide(test2,test);
+                                                                                                                                       if(j==-1){
+                                                                                                                                               player[i].velocity=0;
+                                                                                                                                               player[i].targetanimation=player[i].getStop();
+                                                                                                                                               player[i].targetframe=0;
+                                                                                                                                               player[i].target=0;
+                                                                                                                                               player[i].targetrotation+=180;
+                                                                                                                                               player[i].stunned=.5;
+                                                                                                                                               //player[i].aitype=passivetype;
+                                                                                                                                               player[i].aitype=pathfindtype;
+                                                                                                                                               player[i].finalfinaltarget=player[i].waypoints[player[i].waypoint];
+                                                                                                                                               player[i].finalpathfindpoint=-1;
+                                                                                                                                               player[i].targetpathfindpoint=-1;
+                                                                                                                                               player[i].lastpathfindpoint=-1;
+                                                                                                                                               player[i].lastpathfindpoint2=-1;
+                                                                                                                                               player[i].lastpathfindpoint3=-1;
+                                                                                                                                               player[i].lastpathfindpoint4=-1;
+                                                                                                                                       }
+                                                                                                                                       else player[i].laststanding=j;
+                                                                                                                               }
+                                                                                                                       }
+                                                                                                                       if(player[0].coords.y>player[i].coords.y+5&&animation[player[0].targetanimation].height!=highheight&&!player[0].onterrain){
+                                                                                                                               player[i].aitype=pathfindtype;
+                                                                                                                               player[i].finalfinaltarget=player[i].waypoints[player[i].waypoint];
+                                                                                                                               player[i].finalpathfindpoint=-1;
+                                                                                                                               player[i].targetpathfindpoint=-1;
+                                                                                                                               player[i].lastpathfindpoint=-1;
+                                                                                                                               player[i].lastpathfindpoint2=-1;
+                                                                                                                               player[i].lastpathfindpoint3=-1;
+                                                                                                                               player[i].lastpathfindpoint4=-1;
+                                                                                                                       }       
+                                                                                                                       if(player[i].aiupdatedelay<0&&!animation[player[i].targetanimation].attack&&player[i].targetanimation!=staggerbackhighanim&&player[i].targetanimation!=staggerbackhardanim&&player[i].targetanimation!=backhandspringanim&&player[i].targetanimation!=dodgebackanim){
+                                                                                                                               if(player[i].weaponactive==-1&&player[i].num_weapons>0)player[i].drawkeydown=Random()%2;
+                                                                                                                               else player[i].drawkeydown=0;
+                                                                                                                               player[i].rabbitkickenabled=Random()%2;
+                                                                                                                               rotatetarget=player[player[i].aitarget].coords+player[player[i].aitarget].velocity;
+                                                                                                                               if(findDistancefast(&player[player[i].aitarget].coords,&player[i].coords)<findDistancefast(&rotatetarget,&player[i].coords))
+                                                                                                                                       rotatetarget=player[player[i].aitarget].coords+player[player[i].aitarget].velocity*findDistance(&player[player[i].aitarget].coords,&player[i].coords)/findLength(&player[i].velocity)-player[i].coords;
+                                                                                                                               else rotatetarget=player[player[i].aitarget].coords-player[i].coords;
+                                                                                                                               Normalise(&rotatetarget);
+                                                                                                                               player[i].targetrotation=-asin(0-rotatetarget.x);
+                                                                                                                               player[i].targetrotation*=360/6.28;
+                                                                                                                               if(rotatetarget.z<0)player[i].targetrotation=180-player[i].targetrotation;
+                                                                                                                               player[i].lookrotation=player[i].targetrotation;
+                                                                                                                               player[i].aiupdatedelay=.2+abs((float)(Random()%100)/1000);
+
+                                                                                                                               oldkey=player[i].forwardkeydown;
+                                                                                                                               if(findDistancefast(&player[i].coords,&player[0].coords)>5&&(player[0].weaponactive==-1||player[i].weaponactive!=-1))player[i].forwardkeydown=1;
+                                                                                                                               else if((findDistancefast(&player[i].coords,&player[0].coords)>16||findDistancefast(&player[i].coords,&player[0].coords)<9)&&player[0].weaponactive!=-1)player[i].forwardkeydown=1;
+                                                                                                                               else if(Random()%6==0||(player[i].creature==wolftype&&Random()%3==0))player[i].forwardkeydown=1;
+                                                                                                                               else player[i].forwardkeydown=0;
+                                                                                                                               if(player[0].dead){
+                                                                                                                                       player[i].forwardkeydown=0;
+                                                                                                                                       if(Random()%10==0)player[i].forwardkeydown=1;
+                                                                                                                                       if(Random()%100==0){
+                                                                                                                                               player[i].aitype=pathfindtype;
+                                                                                                                                               player[i].finalfinaltarget=player[i].waypoints[player[i].waypoint];
+                                                                                                                                               player[i].finalpathfindpoint=-1;
+                                                                                                                                               player[i].targetpathfindpoint=-1;
+                                                                                                                                               player[i].lastpathfindpoint=-1;
+                                                                                                                                               player[i].lastpathfindpoint2=-1;
+                                                                                                                                               player[i].lastpathfindpoint3=-1;
+                                                                                                                                               player[i].lastpathfindpoint4=-1;
+                                                                                                                                       }
+                                                                                                                               }
+                                                                                                                               player[i].leftkeydown=0;
+                                                                                                                               player[i].backkeydown=0;
+                                                                                                                               player[i].rightkeydown=0;
+                                                                                                                               player[i].crouchkeydown=0;
+                                                                                                                               player[i].throwkeydown=0;
+
+                                                                                                                               if(player[i].avoidcollided>.8&&!player[i].jumpkeydown&&player[i].collided<.8)player[i].targetrotation+=90*(player[i].whichdirection*2-1);
+                                                                                                                               /*for(j=0;j<numplayers;j++){
+                                                                                                                               if(player[j].victim->id==i&&(player[j].targetanimation==spinkickanim&&player[j].targetframe<3)){
+                                                                                                                               player[i].crouchkeydown=1;
+                                                                                                                               }
+                                                                                                                               }*/
+                                                                                                                               if(Random()%2==0/*||player[0].weaponactive!=-1*/||player[i].weaponactive!=-1||player[i].creature==wolftype)player[i].attackkeydown=1;
+                                                                                                                               else player[i].attackkeydown=0;
+                                                                                                                               if((player[i].isRun())&&Random()%6&&findDistancefast(&player[i].coords,&player[0].coords)>7)player[i].attackkeydown=0;
+                                                                                                                               //if(player[i].attackkeydown&&findDistancefast(&player[i].coords,&player[0].coords)<3&&player[i].targetanimation!=runanim&&!player[0].skeleton.free)player[i].crouchkeydown=1;
+                                                                                                                               /*if(player[0].targetanimation==rabbitkickanim&&!player[0].skeleton.free){
+                                                                                                                               player[i].attackkeydown=0;
+                                                                                                                               if(player[i].isIdle())player[i].crouchkeydown=1;
+                                                                                                                               player[i].forwardkeydown=0;
+                                                                                                                               player[i].aiupdatedelay=.02;
+                                                                                                                               }*/
+
+                                                                                                                               if(player[i].aitype!=playercontrolled&&(player[i].isIdle()||player[i].isCrouch()||player[i].isRun())){
+                                                                                                                                       target=-2;
+                                                                                                                                       for(j=0;j<numplayers;j++){
+                                                                                                                                               if(j!=i&&!player[j].skeleton.free&&player[j].hasvictim&&((tutoriallevel==1&&reversaltrain)||(Random()%2==0&&difficulty==2)||(Random()%4==0&&difficulty==1)||(Random()%8==0&&difficulty==0)||(player[j].lastattack2==player[j].targetanimation&&player[j].lastattack3==player[j].targetanimation&&(Random()%2==0||difficulty==2))||((player[i].isIdle()||player[i].isRun())&&player[j].weaponactive!=-1)||(player[j].targetanimation==swordslashanim&&player[i].weaponactive!=-1)||player[j].targetanimation==staffhitanim||player[j].targetanimation==staffspinhitanim)){
+                                                                                                                                                       if(findDistancefast(&player[j].coords,&player[j].victim->coords)<4&&player[j].victim==&player[i]&&(player[j].targetanimation==sweepanim||player[j].targetanimation==spinkickanim||player[j].targetanimation==staffhitanim||player[j].targetanimation==staffspinhitanim||player[j].targetanimation==winduppunchanim||player[j].targetanimation==upunchanim||player[j].targetanimation==wolfslapanim||player[j].targetanimation==knifeslashstartanim||((player[j].targetanimation==swordslashanim)&&(findDistancefast(&player[j].coords,&player[i].coords)<2||(player[i].weaponactive!=-1))))){
+                                                                                                                                                               if(target>=0)target=-1;
+                                                                                                                                                               else target=j;
+                                                                                                                                                       }
+                                                                                                                                               }
+                                                                                                                                       }
+                                                                                                                                       if(target>=0)player[target].Reverse();
+                                                                                                                               }
+
+                                                                                                                               if(player[i].collided<1)player[i].jumpkeydown=0;
+                                                                                                                               if((player[i].collided>.8&&player[i].jumppower>=5)||(findDistancefast(&player[i].coords,&player[0].coords)>400&&player[i].onterrain&&player[i].creature==rabbittype))player[i].jumpkeydown=1;
+                                                                                                                               if(normaldotproduct(player[i].facing,player[0].coords-player[i].coords)>0)
+                                                                                                                                       player[0].jumpkeydown=0;
+                                                                                                                               if(player[0].targetanimation==jumpdownanim&&findDistancefast(&player[0].coords,&player[i].coords)<40)player[i].crouchkeydown=1;
+                                                                                                                               if(player[i].jumpkeydown)player[i].attackkeydown=0;
+                                                                                                                               //if(animation[player[i].targetanimation].attack==reversed)player[i].crouchkeydown=1;
+
+                                                                                                                               if(tutoriallevel==1){
+                                                                                                                                       if(!canattack)player[i].attackkeydown=0;
+                                                                                                                               }
+
+
+                                                                                                                               facing=player[i].coords;
+                                                                                                                               flatfacing=player[0].coords;
+                                                                                                                               facing.y+=player[i].skeleton.joints[player[i].skeleton.jointlabels[head]].position.y*player[i].scale;
+                                                                                                                               flatfacing.y+=player[0].skeleton.joints[player[0].skeleton.jointlabels[head]].position.y*player[0].scale;
+                                                                                                                               if(player[i].occluded>=2)
+                                                                                                                                       if(-1!=checkcollide(facing,flatfacing)){
+                                                                                                                                               if(!player[i].pause)player[i].lastseentime-=.2;
+                                                                                                                                               if(player[i].lastseentime<=0&&(player[i].creature!=wolftype||player[i].weaponstuck==-1)){
+                                                                                                                                                       player[i].aitype=searchtype;
+                                                                                                                                                       player[i].lastchecktime=12;
+                                                                                                                                                       player[i].lastseen=player[0].coords;
+                                                                                                                                                       player[i].lastseentime=12;
+                                                                                                                                               }
+                                                                                                                                       }
+                                                                                                                                       else player[i].lastseentime=1;
+                                                                                                                       }
+                                                                               }
+                                                                               if(animation[player[0].targetanimation].height==highheight&&(player[i].aitype==attacktypecutoff||player[i].aitype==searchtype)){
+                                                                                       if(player[0].coords.y>terrain.getHeight(player[0].coords.x,player[0].coords.z)+10){
+                                                                                               test=player[0].coords;
+                                                                                               test.y-=40;
+                                                                                               if(-1==checkcollide(player[0].coords,test))player[i].stunned=1;
+                                                                                       }
+                                                                               }
+                                                                               // NOTE: Ask about logic of this call : NOTE
+                                                                               if((player[i].aitype==passivetype && !(player[i].numwaypoints>1)) ||
+                                                                                       player[i].stunned>0 ||
+                                                                                       (player[i].pause && (player[i].damage > player[i].superpermanentdamage)))
+                                                                               {
+                                                                                       if(/*player[i].aitype==attacktypecutoff&&*/player[i].pause)player[i].lastseentime=1;
+                                                                                       player[i].targetrotation=player[i].rotation;
+                                                                                       player[i].forwardkeydown=0;
+                                                                                       player[i].leftkeydown=0;
+                                                                                       player[i].backkeydown=0;
+                                                                                       player[i].rightkeydown=0;
+                                                                                       player[i].jumpkeydown=0;
+                                                                                       player[i].attackkeydown=0;
+                                                                                       player[i].crouchkeydown=0;
+                                                                                       player[i].throwkeydown=0;
+                                                                               }
+
+
+                                                                               facing=0;
+                                                                               facing.z=-1;
+
+                                                                               flatfacing=DoRotation(facing,0,player[i].rotation+180,0);
+                                                                               facing=flatfacing;
+
+                                                                               if(player[i].aitype==attacktypecutoff){
+                                                                                       rotatetarget=player[0].coords-player[i].coords;
+                                                                                       Normalise(&rotatetarget);
+                                                                                       player[i].targetheadrotation=-asin(0-rotatetarget.x);
+                                                                                       player[i].targetheadrotation*=360/6.28;
+                                                                                       if(rotatetarget.z<0)player[i].targetheadrotation=180-player[i].targetheadrotation;
+
+                                                                                       player[i].targetheadrotation*=-1;
+                                                                                       player[i].targetheadrotation+=180;
+                                                                                       //player[i].targetheadrotation2=0;
+                                                                                       player[i].targetheadrotation2=-asin(rotatetarget.y)*360/6.28;
+                                                                               }
+                                                                               else if(player[i].howactive>=typesleeping){
+                                                                                       player[i].targetheadrotation=player[i].targetrotation;
+                                                                                       player[i].targetheadrotation2=0;
+                                                                               }
+                                                                               else {
+                                                                                       if(player[i].interestdelay<=0){
+                                                                                               player[i].interestdelay=.7+(float)(abs(Random()%100))/100;
+                                                                                               player[i].headtarget=player[i].coords;
+                                                                                               player[i].headtarget.x+=(float)(abs(Random()%200)-100)/100;
+                                                                                               player[i].headtarget.z+=(float)(abs(Random()%200)-100)/100;
+                                                                                               player[i].headtarget.y+=(float)(abs(Random()%200)-100)/300;
+                                                                                               player[i].headtarget+=player[i].facing*1.5;
+                                                                                       }
+                                                                                       rotatetarget=player[i].headtarget-player[i].coords;
+                                                                                       Normalise(&rotatetarget);
+                                                                                       player[i].targetheadrotation=-asin(0-rotatetarget.x);
+                                                                                       player[i].targetheadrotation*=360/6.28;
+                                                                                       if(rotatetarget.z<0)player[i].targetheadrotation=180-player[i].targetheadrotation;
+
+                                                                                       player[i].targetheadrotation*=-1;
+                                                                                       player[i].targetheadrotation+=180;
+                                                                                       player[i].targetheadrotation2=-asin(rotatetarget.y)*360/6.28;
+                                                                               }
+                                                                               //if(whichlevel==2)player[i].jumpkeydown=0;
+                                                                       }
+                                                                       if(animation[player[i].targetanimation].attack==reversed){
+                                                                               //player[i].targetrotation=player[i].rotation;
+                                                                               player[i].forwardkeydown=0;
+                                                                               player[i].leftkeydown=0;
+                                                                               player[i].backkeydown=0;
+                                                                               player[i].rightkeydown=0;
+                                                                               player[i].jumpkeydown=0;
+                                                                               player[i].attackkeydown=0;
+                                                                               //player[i].crouchkeydown=0;
+                                                                               player[i].throwkeydown=0;
+                                                                       }
+
+                                                                       if(indialogue!=-1){
+                                                                               player[i].forwardkeydown=0;
+                                                                               player[i].leftkeydown=0;
+                                                                               player[i].backkeydown=0;
+                                                                               player[i].rightkeydown=0;
+                                                                               player[i].jumpkeydown=0;
+                                                                               player[i].crouchkeydown=0;
+                                                                               player[i].drawkeydown=0;
+                                                                               player[i].throwkeydown=0;
+                                                                       }
+
+                                                                       if(player[i].collided<-.3)player[i].collided=-.3;
+                                                                       if(player[i].collided>1)player[i].collided=1;
+                                                                       player[i].collided-=multiplier*4;
+                                                                       player[i].whichdirectiondelay-=multiplier;
+                                                                       if(player[i].avoidcollided<-.3||player[i].whichdirectiondelay<=0){
+                                                                               player[i].avoidcollided=-.3;
+                                                                               player[i].whichdirection=abs(Random()%2);
+                                                                               player[i].whichdirectiondelay=.4;
+                                                                       }
+                                                                       if(player[i].avoidcollided>1)player[i].avoidcollided=1;
+                                                                       player[i].avoidcollided-=multiplier/4;
+                                                                       if(!player[i].skeleton.free)player[i].stunned-=multiplier;
+                                                                       if(!player[i].skeleton.free)player[i].surprised-=multiplier;
+                                                                       if(player[i].surprised<=0&&player[i].aitype==attacktypecutoff&&i!=0&&!player[i].dead&&!player[i].skeleton.free&&animation[player[i].targetanimation].attack==neutral)numresponded=1;
+
+                                                                       if(!player[i].throwkeydown){
+                                                                               player[i].throwtogglekeydown=0;
+                                                                       }
+                                                                       if(player[i].throwkeydown&&!player[i].throwtogglekeydown){
+                                                                               if(player[i].weaponactive==-1&&player[i].num_weapons<2&&(player[i].isIdle()||player[i].isCrouch()||player[i].targetanimation==sneakanim||player[i].targetanimation==rollanim||player[i].targetanimation==backhandspringanim||player[i].isFlip()||player[i].isFlip()||player[i].aitype!=playercontrolled)){
+                                                                                       for(j=0;j<weapons.numweapons;j++){
+                                                                                               if(((weapons.velocity[j].x==0&&weapons.velocity[j].y==0&&weapons.velocity[j].z==0)||player[i].aitype==playercontrolled)&&weapons.owner[j]==-1&&player[i].weaponactive==-1)
+                                                                                                       if(findDistancefastflat(&player[i].coords,&weapons.position[j])<2){
+                                                                                                               if(findDistancefast(&player[i].coords,&weapons.position[j])<2){
+                                                                                                                       if(player[i].isCrouch()||player[i].targetanimation==sneakanim||player[i].isRun()||player[i].isIdle()||player[i].aitype!=playercontrolled){
+                                                                                                                               player[i].throwtogglekeydown=1;
+                                                                                                                               player[i].targetanimation=crouchremoveknifeanim;
+                                                                                                                               player[i].target=0;
+                                                                                                                               player[i].targetframe=0;
+                                                                                                                               rotatetarget=weapons.position[j]-player[i].coords;
+                                                                                                                               Normalise(&rotatetarget);
+                                                                                                                               player[i].targetrotation=-asin(0-rotatetarget.x);
+                                                                                                                               player[i].targetrotation*=360/6.28;
+                                                                                                                               if(rotatetarget.z<0)player[i].targetrotation=180-player[i].targetrotation;
+                                                                                                                               player[i].hasvictim=0;
+                                                                                                                       }
+                                                                                                                       if(player[i].targetanimation==rollanim||player[i].targetanimation==backhandspringanim){
+                                                                                                                               player[i].throwtogglekeydown=1;
+                                                                                                                               player[i].hasvictim=0;
+
+                                                                                                                               //for(i=0;i<weapons.numweapons;i++){
+                                                                                                                               if((((weapons.velocity[j].x==0&&weapons.velocity[j].y==0&&weapons.velocity[j].z==0)||player[i].aitype==playercontrolled)&&weapons.owner[j]==-1)||(player[i].victim&&weapons.owner[j]==player[i].victim->id))
+                                                                                                                                       if(findDistancefastflat(&player[i].coords,&weapons.position[j])<2&&player[i].weaponactive==-1){
+                                                                                                                                               if(findDistancefast(&player[i].coords,&weapons.position[j])<1||player[i].victim){
+                                                                                                                                                       float gLoc[3];
+                                                                                                                                                       float vel[3];
+                                                                                                                                                       gLoc[0]=player[i].coords.x;
+                                                                                                                                                       gLoc[1]=player[i].coords.y;
+                                                                                                                                                       gLoc[2]=player[i].coords.z;
+                                                                                                                                                       vel[0]=player[i].velocity.x;
+                                                                                                                                                       vel[1]=player[i].velocity.y;
+                                                                                                                                                       vel[2]=player[i].velocity.z;
+                                                                                                                                                       if(weapons.type[j]!=staff){
+                                                                                                                                                               PlaySoundEx( knifedrawsound, samp[knifedrawsound], NULL, TRUE);
+                                                                                                                                                               FSOUND_3D_SetAttributes(channels[knifedrawsound], gLoc, vel);
+                                                                                                                                                               FSOUND_SetVolume(channels[knifedrawsound], 128);
+                                                                                                                                                               FSOUND_SetPaused(channels[knifedrawsound], FALSE);
+                                                                                                                                                       }
+
+                                                                                                                                                       player[i].weaponactive=0;
+                                                                                                                                                       weapons.owner[j]=player[i].id;
+                                                                                                                                                       if(player[i].num_weapons>0){
+                                                                                                                                                               player[i].weaponids[player[i].num_weapons]=player[i].weaponids[0];
+                                                                                                                                                       }
+                                                                                                                                                       player[i].num_weapons++;
+                                                                                                                                                       player[i].weaponids[0]=j;
+                                                                                                                                               }
+                                                                                                                                       }
+                                                                                                                                       //}
+                                                                                                                       }
+                                                                                                               }
+                                                                                                               else if ((player[i].isIdle()||player[i].isFlip()||player[i].aitype!=playercontrolled)&&findDistancefast(&player[i].coords,&weapons.position[j])<5&&player[i].coords.y<weapons.position[j].y){
+                                                                                                                       if(!player[i].isFlip()){
+                                                                                                                               player[i].throwtogglekeydown=1;
+                                                                                                                               player[i].targetanimation=removeknifeanim;
+                                                                                                                               player[i].target=0;
+                                                                                                                               player[i].targetframe=0;
+                                                                                                                               rotatetarget=weapons.position[j]-player[i].coords;
+                                                                                                                               Normalise(&rotatetarget);
+                                                                                                                               player[i].targetrotation=-asin(0-rotatetarget.x);
+                                                                                                                               player[i].targetrotation*=360/6.28;
+                                                                                                                               if(rotatetarget.z<0)player[i].targetrotation=180-player[i].targetrotation;
+                                                                                                                       }
+                                                                                                                       if(player[i].isFlip()){
+                                                                                                                               player[i].throwtogglekeydown=1;
+                                                                                                                               player[i].hasvictim=0;
+
+                                                                                                                               for(k=0;k<weapons.numweapons;k++){
+                                                                                                                                       if(player[i].weaponactive==-1)
+                                                                                                                                               if((((weapons.velocity[k].x==0&&weapons.velocity[k].y==0&&weapons.velocity[k].z==0)||player[i].aitype==playercontrolled)&&weapons.owner[k]==-1)||(player[i].victim&&weapons.owner[k]==player[i].victim->id))
+                                                                                                                                                       if(findDistancefastflat(&player[i].coords,&weapons.position[k])<3&&player[i].weaponactive==-1){
+                                                                                                                                                               float gLoc[3];
+                                                                                                                                                               float vel[3];
+                                                                                                                                                               gLoc[0]=player[i].coords.x;
+                                                                                                                                                               gLoc[1]=player[i].coords.y;
+                                                                                                                                                               gLoc[2]=player[i].coords.z;
+                                                                                                                                                               vel[0]=player[i].velocity.x;
+                                                                                                                                                               vel[1]=player[i].velocity.y;
+                                                                                                                                                               vel[2]=player[i].velocity.z;
+                                                                                                                                                               if(weapons.type[k]!=staff){
+                                                                                                                                                                       PlaySoundEx( knifedrawsound, samp[knifedrawsound], NULL, TRUE);
+                                                                                                                                                                       FSOUND_3D_SetAttributes(channels[knifedrawsound], gLoc, vel);
+                                                                                                                                                                       FSOUND_SetVolume(channels[knifedrawsound], 128);
+                                                                                                                                                                       FSOUND_SetPaused(channels[knifedrawsound], FALSE);
+                                                                                                                                                               }
+
+                                                                                                                                                               player[i].weaponactive=0;
+                                                                                                                                                               weapons.owner[k]=player[i].id;
+                                                                                                                                                               if(player[i].num_weapons>0){
+                                                                                                                                                                       player[i].weaponids[player[i].num_weapons]=player[i].weaponids[0];
+                                                                                                                                                               }
+                                                                                                                                                               player[i].num_weapons++;
+                                                                                                                                                               player[i].weaponids[0]=k;
+                                                                                                                                                       }
+                                                                                                                               }
+                                                                                                                       }
+                                                                                                               }
+                                                                                                       }
+                                                                                       }
+                                                                                       if(player[i].isCrouch()||player[i].targetanimation==sneakanim||player[i].isRun()||player[i].isIdle()||player[i].targetanimation==rollanim||player[i].targetanimation==backhandspringanim){
+                                                                                               if(numplayers>1)
+                                                                                                       for(j=0;j<numplayers;j++){
+                                                                                                               if(player[i].weaponactive==-1)
+                                                                                                                       if(j!=i)
+                                                                                                                               if(player[j].num_weapons&&player[j].skeleton.free&&findDistancefast(&player[i].coords,&player[j].coords)<2/*&&player[j].dead*/&&(((player[j].skeleton.forward.y<0&&player[j].weaponstuckwhere==0)||(player[j].skeleton.forward.y>0&&player[j].weaponstuckwhere==1))||player[j].weaponstuck==-1||player[j].num_weapons>1)){
+                                                                                                                                       if(player[i].targetanimation!=rollanim&&player[i].targetanimation!=backhandspringanim){
+                                                                                                                                               player[i].throwtogglekeydown=1;
+                                                                                                                                               player[i].victim=&player[j];
+                                                                                                                                               player[i].hasvictim=1;
+                                                                                                                                               player[i].targetanimation=crouchremoveknifeanim;
+                                                                                                                                               player[i].target=0;
+                                                                                                                                               player[i].targetframe=0;
+                                                                                                                                               rotatetarget=player[j].coords-player[i].coords;
+                                                                                                                                               Normalise(&rotatetarget);
+                                                                                                                                               player[i].targetrotation=-asin(0-rotatetarget.x);
+                                                                                                                                               player[i].targetrotation*=360/6.28;
+                                                                                                                                               if(rotatetarget.z<0)player[i].targetrotation=180-player[i].targetrotation;
+                                                                                                                                       }
+                                                                                                                                       if(player[i].targetanimation==rollanim||player[i].targetanimation==backhandspringanim){
+                                                                                                                                               player[i].throwtogglekeydown=1;
+                                                                                                                                               player[i].victim=&player[j];
+                                                                                                                                               player[i].hasvictim=1;
+                                                                                                                                               int k = player[j].weaponids[0];
+                                                                                                                                               if(player[i].hasvictim){
+                                                                                                                                                       float gLoc[3];
+                                                                                                                                                       float vel[3];
+                                                                                                                                                       gLoc[0]=player[i].coords.x;
+                                                                                                                                                       gLoc[1]=player[i].coords.y;
+                                                                                                                                                       gLoc[2]=player[i].coords.z;
+                                                                                                                                                       vel[0]=player[i].velocity.x;
+                                                                                                                                                       vel[1]=player[i].velocity.y;
+                                                                                                                                                       vel[2]=player[i].velocity.z;
+                                                                                                                                                       bool fleshstuck;
+                                                                                                                                                       fleshstuck=0;
+                                                                                                                                                       if(player[i].victim->weaponstuck!=-1){
+                                                                                                                                                               if(player[i].victim->weaponids[player[i].victim->weaponstuck]==k){
+                                                                                                                                                                       fleshstuck=1;
+                                                                                                                                                               }
+                                                                                                                                                       }
+                                                                                                                                                       if(!fleshstuck){
+                                                                                                                                                               if(weapons.type[k]!=staff){
+                                                                                                                                                                       PlaySoundEx( knifedrawsound, samp[knifedrawsound], NULL, TRUE);
+                                                                                                                                                                       FSOUND_3D_SetAttributes(channels[knifedrawsound], gLoc, vel);
+                                                                                                                                                                       FSOUND_SetVolume(channels[knifedrawsound], 128);
+                                                                                                                                                                       FSOUND_SetPaused(channels[knifedrawsound], FALSE);
+                                                                                                                                                               }
+                                                                                                                                                       }
+                                                                                                                                                       if(fleshstuck){
+                                                                                                                                                               PlaySoundEx( fleshstabremovesound, samp[fleshstabremovesound], NULL, TRUE);
+                                                                                                                                                               FSOUND_3D_SetAttributes(channels[fleshstabremovesound], gLoc, vel);
+                                                                                                                                                               FSOUND_SetVolume(channels[fleshstabremovesound], 128);
+                                                                                                                                                               FSOUND_SetPaused(channels[fleshstabremovesound], FALSE);
+                                                                                                                                                       }
+
+                                                                                                                                                       player[i].weaponactive=0;
+                                                                                                                                                       if(weapons.owner[k]!=-1){
+                                                                                                                                                               if(player[i].victim->num_weapons==1)player[i].victim->num_weapons=0;
+                                                                                                                                                               else player[i].victim->num_weapons=1;
+
+                                                                                                                                                               player[i].victim->skeleton.longdead=0;
+                                                                                                                                                               player[i].victim->skeleton.free=1;
+                                                                                                                                                               player[i].victim->skeleton.broken=0;
+
+                                                                                                                                                               for(int l=0;l<player[i].victim->skeleton.num_joints;l++){
+                                                                                                                                                                       player[i].victim->skeleton.joints[l].velchange=0;
+                                                                                                                                                                       player[i].victim->skeleton.joints[l].locked=0;
+                                                                                                                                                               }
+
+                                                                                                                                                               XYZ relative;
+                                                                                                                                                               relative=0;
+                                                                                                                                                               relative.y=10;
+                                                                                                                                                               Normalise(&relative);
+                                                                                                                                                               XYZ footvel,footpoint;
+                                                                                                                                                               footvel=0;
+                                                                                                                                                               footpoint=weapons.position[k];
+                                                                                                                                                               if(player[i].victim->weaponstuck!=-1){
+                                                                                                                                                                       if(player[i].victim->weaponids[player[i].victim->weaponstuck]==k){
+                                                                                                                                                                               if(bloodtoggle)sprites.MakeSprite(cloudimpactsprite, footpoint,footvel, 1,0,0, .8, .3);
+                                                                                                                                                                               weapons.bloody[k]=2;
+                                                                                                                                                                               weapons.blooddrip[k]=5;
+                                                                                                                                                                               player[i].victim->weaponstuck=-1;
+                                                                                                                                                                               player[i].victim->bloodloss+=2000;
+                                                                                                                                                                               player[i].victim->DoDamage(2000);
+                                                                                                                                                                       }
+                                                                                                                                                               }
+                                                                                                                                                               if(player[i].victim->num_weapons>0){
+                                                                                                                                                                       if(player[i].victim->weaponstuck!=0&&player[i].victim->weaponstuck!=-1)player[i].victim->weaponstuck=0;
+                                                                                                                                                                       if(player[i].victim->weaponids[0]==k)
+                                                                                                                                                                               player[i].victim->weaponids[0]=player[i].victim->weaponids[player[i].victim->num_weapons];
+                                                                                                                                                               }
+
+                                                                                                                                                               player[i].victim->weaponactive=-1;
+
+                                                                                                                                                               player[i].victim->skeleton.joints[player[i].victim->skeleton.jointlabels[abdomen]].velocity+=relative*6;
+                                                                                                                                                               player[i].victim->skeleton.joints[player[i].victim->skeleton.jointlabels[neck]].velocity+=relative*6;
+                                                                                                                                                               player[i].victim->skeleton.joints[player[i].victim->skeleton.jointlabels[rightshoulder]].velocity+=relative*6;
+                                                                                                                                                               player[i].victim->skeleton.joints[player[i].victim->skeleton.jointlabels[leftshoulder]].velocity+=relative*6;
+                                                                                                                                                       }
+                                                                                                                                                       weapons.owner[k]=i;
+                                                                                                                                                       if(player[i].num_weapons>0){
+                                                                                                                                                               player[i].weaponids[player[i].num_weapons]=player[i].weaponids[0];
+                                                                                                                                                       }
+                                                                                                                                                       player[i].num_weapons++;
+                                                                                                                                                       player[i].weaponids[0]=k;
+                                                                                                                                               }
+                                                                                                                                       }
+                                                                                                                               }
+                                                                                                       }
+                                                                                       }
+                                                                               }
+                                                                               if(player[i].weaponactive!=-1&&player[i].aitype==playercontrolled){
+                                                                                       if(weapons.type[player[i].weaponids[0]]==knife){
+                                                                                               if(player[i].isIdle()||player[i].isRun()||player[i].isCrouch()||player[i].targetanimation==sneakanim||player[i].isFlip())
+                                                                                                       if(numplayers>1)
+                                                                                                               for(j=0;j<numplayers;j++){
+                                                                                                                       if(i!=j)
+                                                                                                                               if(tutoriallevel!=1||tutorialstage==49)
+                                                                                                                                       if(hostile)
+                                                                                                                                               if(normaldotproduct(player[i].facing,player[i].coords-player[j].coords)<0&&findDistancefast(&player[i].coords,&player[j].coords)<100&&findDistancefast(&player[i].coords,&player[j].coords)>1.5&&!player[j].skeleton.free&&-1==checkcollide(DoRotation(player[j].skeleton.joints[player[j].skeleton.jointlabels[head]].position,0,player[j].rotation,0)*player[j].scale+player[j].coords,DoRotation(player[i].skeleton.joints[player[i].skeleton.jointlabels[head]].position,0,player[i].rotation,0)*player[i].scale+player[i].coords)){
+                                                                                                                                                       if(!player[i].isFlip()){
+                                                                                                                                                               player[i].throwtogglekeydown=1;
+                                                                                                                                                               player[i].victim=&player[j];
+                                                                                                                                                               player[i].targetanimation=knifethrowanim;
+                                                                                                                                                               player[i].target=0;
+                                                                                                                                                               player[i].targetframe=0;
+                                                                                                                                                               rotatetarget=player[j].coords-player[i].coords;
+                                                                                                                                                               Normalise(&rotatetarget);
+                                                                                                                                                               player[i].targetrotation=-asin(0-rotatetarget.x);
+                                                                                                                                                               player[i].targetrotation*=360/6.28;
+                                                                                                                                                               if(rotatetarget.z<0)player[i].targetrotation=180-player[i].targetrotation;
+
+                                                                                                                                                               player[i].targettilt2=-asin(rotatetarget.y)*360/6.28;
+                                                                                                                                                       }
+                                                                                                                                                       if(player[i].isFlip()){
+                                                                                                                                                               if(player[i].weaponactive!=-1){
+                                                                                                                                                                       player[i].throwtogglekeydown=1;
+                                                                                                                                                                       player[i].victim=&player[j];
+                                                                                                                                                                       XYZ aim;
+                                                                                                                                                                       weapons.owner[player[i].weaponids[0]]=-1;
+                                                                                                                                                                       aim=player[i].victim->coords+DoRotation(player[i].victim->skeleton.joints[player[i].victim->skeleton.jointlabels[abdomen]].position,0,player[i].victim->rotation,0)*player[i].victim->scale+player[i].victim->velocity*findDistance(&player[i].victim->coords,&player[i].coords)/50-(player[i].coords+DoRotation(player[i].skeleton.joints[player[i].skeleton.jointlabels[righthand]].position,0,player[i].rotation,0)*player[i].scale);                                                
+                                                                                                                                                                       Normalise(&aim);
+
+                                                                                                                                                                       aim=DoRotation(aim,(float)abs(Random()%30)-15,(float)abs(Random()%30)-15,0);
+
+                                                                                                                                                                       weapons.velocity[player[i].weaponids[0]]=aim*50;
+                                                                                                                                                                       weapons.tipvelocity[player[i].weaponids[0]]=aim*50;
+                                                                                                                                                                       weapons.missed[player[i].weaponids[0]]=0;
+                                                                                                                                                                       weapons.freetime[player[i].weaponids[0]]=0;
+                                                                                                                                                                       weapons.firstfree[player[i].weaponids[0]]=1;
+                                                                                                                                                                       weapons.physics[player[i].weaponids[0]]=0;
+                                                                                                                                                                       player[i].num_weapons--;
+                                                                                                                                                                       if(player[i].num_weapons){
+                                                                                                                                                                               player[i].weaponids[0]=player[i].weaponids[player[i].num_weapons];
+                                                                                                                                                                       }
+                                                                                                                                                                       player[i].weaponactive=-1;
+                                                                                                                                                               }               
+                                                                                                                                                       }
+                                                                                                                                               }
+                                                                                                               }
+                                                                                       }
+                                                                               }
+                                                                               if(player[i].weaponactive!=-1&&player[i].aitype==playercontrolled){
+                                                                                       if(player[i].isCrouch()||player[i].targetanimation==sneakanim)
+                                                                                       {
+                                                                                               player[i].throwtogglekeydown=1;
+                                                                                               weapons.owner[player[i].weaponids[0]]=-1;
+                                                                                               weapons.velocity[player[i].weaponids[0]]=player[i].velocity*.2;
+                                                                                               if(weapons.velocity[player[i].weaponids[0]].x==0)weapons.velocity[player[i].weaponids[0]].x=.1;
+                                                                                               weapons.tipvelocity[player[i].weaponids[0]]=weapons.velocity[player[i].weaponids[0]];
+                                                                                               weapons.missed[player[i].weaponids[0]]=1;
+                                                                                               weapons.freetime[player[i].weaponids[0]]=0;
+                                                                                               weapons.firstfree[player[i].weaponids[0]]=1;
+                                                                                               weapons.physics[player[i].weaponids[0]]=1;
+                                                                                               player[i].num_weapons--;
+                                                                                               if(player[i].num_weapons){
+                                                                                                       player[i].weaponids[0]=player[i].weaponids[player[i].num_weapons];
+                                                                                                       if(player[i].weaponstuck==player[i].num_weapons)player[i].weaponstuck=0;
+                                                                                               }
+
+                                                                                               player[i].weaponactive=-1;
+                                                                                               for(j=0;j<numplayers;j++){
+                                                                                                       player[j].wentforweapon=0;
+                                                                                               }
+                                                                                       }
+                                                                               }
+
+                                                                       }
+
+                                                                       if(i==0||!player[0].dead||player[i].weaponactive!=-1)
+                                                                               if((player[i].drawkeydown&&!player[i].drawtogglekeydown)||(player[i].num_weapons==2&&player[i].weaponactive==-1&&player[i].isIdle())||(player[0].dead&&player[i].weaponactive!=-1&&i!=0)){
+                                                                                       //Setenvironment(1-environment);
+                                                                                       bool isgood;
+                                                                                       isgood=1;
+                                                                                       if(player[i].weaponactive!=-1){
+                                                                                               if(weapons.type[player[i].weaponids[player[i].weaponactive]]==staff)isgood=0;
+                                                                                       }
+                                                                                       if(/*(player[i].weaponactive==-1||player[i].num_weapons==1)&&*/isgood&&player[i].creature!=wolftype){
+                                                                                               if(player[i].isIdle()&&player[i].num_weapons&&weapons.type[player[i].weaponids[0]]==knife){
+                                                                                                       player[i].targetanimation=drawrightanim;
+                                                                                                       player[i].targetframe=0;
+                                                                                                       player[i].target=0;
+                                                                                                       player[i].drawtogglekeydown=1;
+                                                                                               }
+                                                                                               if((player[i].isIdle()||(player[i].aitype!=playercontrolled&&player[0].weaponactive!=-1&&player[i].isRun()))&&player[i].num_weapons&&weapons.type[player[i].weaponids[0]]==sword){
+                                                                                                       player[i].targetanimation=drawleftanim;
+                                                                                                       player[i].targetframe=0;
+                                                                                                       player[i].target=0;
+                                                                                                       player[i].drawtogglekeydown=1;
+                                                                                               }
+                                                                                               if(player[i].isCrouch()&&player[i].num_weapons&&weapons.type[player[i].weaponids[0]]==knife){
+                                                                                                       player[i].targetanimation=crouchdrawrightanim;
+                                                                                                       player[i].targetframe=0;
+                                                                                                       player[i].target=0;
+                                                                                                       player[i].drawtogglekeydown=1;
+                                                                                               }
+                                                                                       }                        
+                                                                               }
+                                                                               if(player[i].isCrouch()&&weapons.bloody[player[i].weaponids[player[i].weaponactive]]&&bloodtoggle&&player[i].onterrain&&player[i].num_weapons&&player[i].weaponactive!=-1&&player[i].attackkeydown){
+                                                                                       if(weapons.bloody[player[i].weaponids[player[i].weaponactive]]&&player[i].onterrain&&bloodtoggle&&musictype!=stream_music2){
+                                                                                               if(weapons.type[player[i].weaponids[player[i].weaponactive]]==knife)player[i].targetanimation=crouchstabanim;
+                                                                                               if(weapons.type[player[i].weaponids[player[i].weaponactive]]==sword)player[i].targetanimation=swordgroundstabanim;
+                                                                                               player[i].targetframe=0;
+                                                                                               player[i].target=0;
+                                                                                               player[i].hasvictim=0;
+                                                                                               //player[i].attacktogglekeydown=1;
+                                                                                       }
+                                                                               }
+
+                                                                               if(!player[i].drawkeydown){
+                                                                                       player[i].drawtogglekeydown=0;
+                                                                               }
+
+                                                                               if(i==0){
+                                                                                       absflatfacing=0;
+                                                                                       absflatfacing.z=-1;
+
+                                                                                       absflatfacing=DoRotation(absflatfacing,0,-rotation,0);
+                                                                               }
+                                                                               else absflatfacing=flatfacing;
+
+                                                                               if(indialogue!=-1){
+                                                                                       player[i].forwardkeydown=0;
+                                                                                       player[i].leftkeydown=0;
+                                                                                       player[i].backkeydown=0;
+                                                                                       player[i].rightkeydown=0;
+                                                                                       player[i].jumpkeydown=0;
+                                                                                       player[i].crouchkeydown=0;
+                                                                                       player[i].drawkeydown=0;
+                                                                                       player[i].throwkeydown=0;
+                                                                               }
+                                                                               movekey=0;
+                                                                               //Do controls
+                                                                               if(!animation[player[i].targetanimation].attack&&player[i].targetanimation!=staggerbackhighanim&&player[i].targetanimation!=staggerbackhardanim&&player[i].targetanimation!=backhandspringanim&&player[i].targetanimation!=dodgebackanim){
+                                                                                       if(!player[i].forwardkeydown){
+                                                                                               player[i].forwardstogglekeydown=0;
+                                                                                       }
+                                                                                       if(player[i].crouchkeydown){
+                                                                                               //Crouch
+                                                                                               target=-2;
+                                                                                               if(i==0){
+                                                                                                       player[i].superruntoggle=1;
+                                                                                                       if(numplayers>1)
+                                                                                                               for(j=0;j<numplayers;j++){
+                                                                                                                       if(j!=i&&!player[j].skeleton.free&&player[j].aitype==passivetype){
+                                                                                                                               if(findDistancefast(&player[j].coords,&player[i].coords)<16){
+                                                                                                                                       player[i].superruntoggle=0;
+                                                                                                                               }
+                                                                                                                       }
+                                                                                                               }
+                                                                                               }
+
+                                                                                               if(numplayers>1)
+                                                                                                       for(j=0;j<numplayers;j++){
+                                                                                                               if(j!=i&&!player[j].skeleton.free&&player[j].victim&&player[i].lowreversaldelay<=0){
+                                                                                                                       if(findDistancefast(&player[j].coords,&player[j].victim->coords)<3&&player[j].victim==&player[i]&&(player[j].targetanimation==sweepanim||player[j].targetanimation==upunchanim||player[j].targetanimation==wolfslapanim||((player[j].targetanimation==swordslashanim||player[j].targetanimation==knifeslashstartanim||player[j].targetanimation==staffhitanim||player[j].targetanimation==staffspinhitanim)&&findDistancefast(&player[j].coords,&player[i].coords)<2))){
+                                                                                                                               if(target>=0)target=-1;
+                                                                                                                               else target=j;
+                                                                                                                       }
+                                                                                                               }
+                                                                                                       }
+                                                                                                       if(target>=0)player[target].Reverse();
+                                                                                                       player[i].lowreversaldelay=.5;
+
+                                                                                                       if(player[i].isIdle()){
+                                                                                                               player[i].targetanimation=player[i].getCrouch();
+                                                                                                               player[i].target=0;
+                                                                                                               player[i].targetframe=0;
+                                                                                                               player[i].transspeed=10;
+                                                                                                       }
+                                                                                                       if(player[i].isRun()||(player[i].isStop()&&(player[i].leftkeydown||player[i].rightkeydown||player[i].forwardkeydown||player[i].backkeydown))){
+                                                                                                               player[i].targetanimation=rollanim;
+                                                                                                               player[i].target=0;
+                                                                                                               player[i].targetframe=0;
+                                                                                                               player[i].transspeed=20;
+                                                                                                       }
+                                                                                       }
+                                                                                       if(!player[i].crouchkeydown){
+                                                                                               //Uncrouch
+                                                                                               if(!player[i].isRun()&&player[i].targetanimation!=sneakanim&&i==0)player[i].superruntoggle=0;
+                                                                                               target=-2;
+                                                                                               if(player[i].isCrouch()){
+                                                                                                       if(numplayers>1)
+                                                                                                               for(j=0;j<numplayers;j++){
+                                                                                                                       if(j!=i&&!player[j].skeleton.free&&player[j].victim&&player[i].highreversaldelay<=0){
+                                                                                                                               if(findDistancefast(&player[j].coords,&player[j].victim->coords)<3&&player[j].victim==&player[i]&&(player[j].targetanimation==spinkickanim)&&player[i].isCrouch()){
+                                                                                                                                       if(target>=0)target=-1;
+                                                                                                                                       else target=j;
+                                                                                                                               }
+                                                                                                                       }
+                                                                                                               }
+                                                                                                               if(target>=0)player[target].Reverse();
+                                                                                                               player[i].highreversaldelay=.5;
+
+                                                                                                               if(player[i].isCrouch()){                                               
+                                                                                                                       if(!player[i].wasCrouch()){
+                                                                                                                               player[i].currentanimation=player[i].getCrouch();
+                                                                                                                               player[i].currentframe=0;
+                                                                                                                       }
+                                                                                                                       player[i].target=0;
+                                                                                                                       player[i].targetanimation=player[i].getIdle();
+                                                                                                                       player[i].targetframe=0;
+                                                                                                                       player[i].transspeed=10;
+                                                                                                               }
+                                                                                               }
+                                                                                               if(player[i].targetanimation==sneakanim){
+                                                                                                       player[i].targetanimation=player[i].getIdle();
+                                                                                                       player[i].target=0;
+                                                                                                       player[i].targetframe=0;
+                                                                                                       player[i].transspeed=10;
+                                                                                               }
+                                                                                       }
+                                                                                       if(player[i].forwardkeydown){
+                                                                                               if(player[i].isIdle()||(player[i].isStop()&&player[i].targetrotation==player[i].rotation)||(player[i].isLanding()&&player[i].targetframe>0&&!player[i].jumpkeydown)||(player[i].isLandhard()&&player[i].targetframe>0&&!player[i].jumpkeydown&&player[i].crouchkeydown)){
+                                                                                                       if(player[i].aitype==passivetype)player[i].targetanimation=walkanim;
+                                                                                                       else player[i].targetanimation=player[i].getRun();
+                                                                                                       player[i].target=0;
+                                                                                                       player[i].targetframe=0;
+                                                                                               }
+                                                                                               if(player[i].isCrouch()){
+                                                                                                       player[i].targetanimation=sneakanim;
+                                                                                                       if(player[i].wasCrouch())player[i].target=0;
+                                                                                                       player[i].targetframe=0;
+                                                                                               }
+                                                                                               if(player[i].targetanimation==hanganim/*&&(!player[i].forwardstogglekeydown||player[i].aitype!=playercontrolled)*/){
+                                                                                                       player[i].targetanimation=climbanim;
+                                                                                                       player[i].target=0;
+                                                                                                       player[i].targetframe=1;
+                                                                                                       player[i].jumpclimb=1;
+                                                                                               }
+                                                                                               if(player[i].targetanimation==jumpupanim||player[i].targetanimation==jumpdownanim||player[i].isFlip()){
+                                                                                                       player[i].velocity+=absflatfacing*5*multiplier;
+                                                                                               }
+                                                                                               player[i].forwardstogglekeydown=1;
+                                                                                               movekey=1;
+                                                                                       }
+                                                                                       if (player[i].rightkeydown){
+                                                                                               if(player[i].isIdle()||(player[i].isStop()&&player[i].targetrotation==player[i].rotation)||(player[i].isLanding()&&player[i].targetframe>0&&!player[i].jumpkeydown)||(player[i].isLandhard()&&player[i].targetframe>0&&!player[i].jumpkeydown&&player[i].crouchkeydown)){
+                                                                                                       player[i].targetanimation=player[i].getRun();
+                                                                                                       player[i].target=0;
+                                                                                                       player[i].targetframe=0;
+                                                                                               }
+                                                                                               if(player[i].isCrouch()){
+                                                                                                       player[i].targetanimation=sneakanim;
+                                                                                                       if(player[i].wasCrouch()) player[i].target=0;
+                                                                                                       player[i].targetframe=0;
+                                                                                               }
+                                                                                               if(player[i].targetanimation==jumpupanim||player[i].targetanimation==jumpdownanim||player[i].isFlip()){
+                                                                                                       player[i].velocity+=DoRotation(absflatfacing*5*multiplier,0,-90,0);
+                                                                                               }
+                                                                                               player[i].targetrotation-=90;
+                                                                                               if(player[i].forwardkeydown)player[i].targetrotation+=45;
+                                                                                               if(player[i].backkeydown)player[i].targetrotation-=45;
+                                                                                               movekey=1;
+                                                                                       }
+                                                                                       if ( player[i].leftkeydown){
+                                                                                               if(player[i].isIdle()||(player[i].isStop()&&player[i].targetrotation==player[i].rotation)||(player[i].isLanding()&&player[i].targetframe>0&&!player[i].jumpkeydown)||(player[i].isLandhard()&&player[i].targetframe>0&&!player[i].jumpkeydown&&player[i].crouchkeydown)){
+                                                                                                       player[i].targetanimation=player[i].getRun();
+                                                                                                       player[i].target=0;
+                                                                                                       player[i].targetframe=0;
+                                                                                               }
+                                                                                               if(player[i].isCrouch()){
+                                                                                                       player[i].targetanimation=sneakanim;
+                                                                                                       if(player[i].wasCrouch())player[i].target=0;
+                                                                                                       player[i].targetframe=0;
+                                                                                               }
+                                                                                               if(player[i].targetanimation==jumpupanim||player[i].targetanimation==jumpdownanim||player[i].isFlip()){
+                                                                                                       player[i].velocity-=DoRotation(absflatfacing*5*multiplier,0,-90,0);
+                                                                                               }
+                                                                                               player[i].targetrotation+=90;
+                                                                                               if(player[i].forwardkeydown)player[i].targetrotation-=45;
+                                                                                               if(player[i].backkeydown)player[i].targetrotation+=45;
+                                                                                               movekey=1;
+                                                                                       }
+                                                                                       if(player[i].backkeydown){
+                                                                                               if(player[i].isIdle()||(player[i].isStop()&&player[i].targetrotation==player[i].rotation)||(player[i].isLanding()&&player[i].targetframe>0&&!player[i].jumpkeydown)||(player[i].isLandhard()&&player[i].targetframe>0&&!player[i].jumpkeydown&&player[i].crouchkeydown)){
+                                                                                                       player[i].targetanimation=player[i].getRun();
+                                                                                                       player[i].target=0;
+                                                                                                       player[i].targetframe=0;
+                                                                                               }
+                                                                                               if(player[i].isCrouch()){
+                                                                                                       player[i].targetanimation=sneakanim;
+                                                                                                       if(player[i].wasCrouch())player[i].target=0;
+                                                                                                       player[i].targetframe=0;
+                                                                                               }
+                                                                                               if(player[i].targetanimation==jumpupanim||player[i].targetanimation==jumpdownanim||player[i].isFlip()){
+                                                                                                       player[i].velocity-=absflatfacing*5*multiplier;
+                                                                                               }
+                                                                                               if(player[i].targetanimation==hanganim){
+                                                                                                       player[i].currentanimation=jumpdownanim;
+                                                                                                       player[i].targetanimation=jumpdownanim;
+                                                                                                       player[i].target=0;
+                                                                                                       player[i].currentframe=0;
+                                                                                                       player[i].targetframe=1;
+                                                                                                       player[i].velocity=0;
+                                                                                                       player[i].velocity.y+=gravity;
+                                                                                                       player[i].coords.y-=1.4;
+                                                                                                       player[i].grabdelay=1;
+                                                                                               }
+                                                                                               if ( !player[i].leftkeydown&&!player[i].rightkeydown)
+                                                                                                       player[i].targetrotation+=180;
+                                                                                               movekey=1;
+                                                                                       }
+                                                                                       if((player[i].jumpkeydown&&!player[i].jumpclimb)||player[i].jumpstart){
+                                                                                               if((((player[i].isLanding()&&player[i].targetframe>=3)||player[i].isRun()||player[i].targetanimation==walkanim||player[i].isCrouch()||player[i].targetanimation==sneakanim)&&player[i].jumppower>1)&&((player[i].targetanimation!=rabbitrunninganim&&player[i].targetanimation!=wolfrunninganim)||i!=0)){
+                                                                                                       player[i].jumpstart=0;
+                                                                                                       player[i].targetanimation=jumpupanim;
+                                                                                                       player[i].target=0;
+                                                                                                       player[i].targetframe=0;
+                                                                                                       player[i].rotation=player[i].targetrotation;
+                                                                                                       player[i].transspeed=20;
+                                                                                                       player[i].FootLand(0,1);
+                                                                                                       player[i].FootLand(1,1);
+
+                                                                                                       facing=0;
+                                                                                                       facing.z=-1;
+                                                                                                       flatfacing=DoRotation(facing,0,player[i].targetrotation+180,0);
+
+                                                                                                       if(movekey)player[i].velocity=flatfacing*player[i].speed*45*player[i].scale;
+                                                                                                       if(!movekey)player[i].velocity=0;
+
+                                                                                                       //Dodge sweep?
+                                                                                                       target=-2;
+                                                                                                       if(numplayers>1)
+                                                                                                               for(j=0;j<numplayers;j++){
+                                                                                                                       if(j!=i&&!player[j].skeleton.free&&player[j].victim){
+                                                                                                                               if(findDistancefast(&player[j].coords,&player[j].victim->coords)<3&&player[j].victim==&player[i]&&(player[j].targetanimation==sweepanim)){
+                                                                                                                                       if(target>=0)target=-1;
+                                                                                                                                       else target=j;
+                                                                                                                               }
+                                                                                                                       }
+                                                                                                               }
+                                                                                                               if(target>=0)player[i].velocity.y=1;
+                                                                                                               else if(player[i].crouchkeydown||player[i].aitype!=playercontrolled){
+                                                                                                                       player[i].velocity.y=7;
+                                                                                                                       player[i].crouchtogglekeydown=1;
+                                                                                                               }
+                                                                                                               else player[i].velocity.y=5;
+
+                                                                                                               if(mousejump&&i==0&&debugmode){
+                                                                                                                       if(!player[i].isLanding())player[i].tempdeltav=deltav;
+                                                                                                                       if(player[i].tempdeltav<0)player[i].velocity.y-=(float)(player[i].tempdeltav)/multiplier/1000;
+                                                                                                               }
+
+                                                                                                               player[i].coords.y+=.2;
+                                                                                                               player[i].jumppower-=1;
+
+                                                                                                               static float gLoc[3];
+                                                                                                               static float vel[3];
+                                                                                                               gLoc[0]=player[i].coords.x;
+                                                                                                               gLoc[1]=player[i].coords.y;
+                                                                                                               gLoc[2]=player[i].coords.z;
+                                                                                                               vel[0]=player[i].velocity.x;
+                                                                                                               vel[1]=player[i].velocity.y;
+                                                                                                               vel[2]=player[i].velocity.z;
+
+                                                                                                               if(i==0){
+                                                                                                                       PlaySoundEx( whooshsound, samp[whooshsound], NULL, TRUE);
+                                                                                                                       FSOUND_3D_SetAttributes(channels[whooshsound], gLoc, vel);
+                                                                                                                       FSOUND_SetVolume(channels[whooshsound], 128);
+                                                                                                                       FSOUND_SetPaused(channels[whooshsound], FALSE);
+                                                                                                               }
+
+                                                                                                               PlaySoundEx( jumpsound, samp[jumpsound], NULL, TRUE);
+                                                                                                               FSOUND_3D_SetAttributes(channels[jumpsound], gLoc, vel);
+                                                                                                               FSOUND_SetVolume(channels[jumpsound], 128);
+                                                                                                               FSOUND_SetPaused(channels[jumpsound], FALSE);
+                                                                                               }               
+                                                                                               if((player[i].isIdle())&&player[i].jumppower>1){
+                                                                                                       player[i].targetanimation=player[i].getLanding();
+                                                                                                       player[i].landhard=0;
+                                                                                                       player[i].target=0;
+                                                                                                       player[i].targetframe=2;
+                                                                                                       player[i].jumpstart=1;
+                                                                                                       player[i].tempdeltav=deltav;
+                                                                                               }               
+                                                                                               if(player[i].targetanimation==jumpupanim&&(((!floatjump&&!editorenabled)||!debugmode)||player[i].aitype!=playercontrolled)){
+                                                                                                       if(player[i].jumppower>multiplier*6){
+                                                                                                               player[i].velocity.y+=multiplier*6;
+                                                                                                               player[i].jumppower-=multiplier*6;
+                                                                                                       }
+                                                                                                       if(player[i].jumppower<=multiplier*6){
+                                                                                                               player[i].velocity.y+=player[i].jumppower;
+                                                                                                               player[i].jumppower=0;
+                                                                                                       }
+                                                                                               }
+                                                                                               if(((floatjump||editorenabled)&&debugmode)&&i==0)player[i].velocity.y+=multiplier*30;           
+                                                                                       }
+
+                                                                                       if(!movekey){
+                                                                                               if(player[i].isRun()||player[i].targetanimation==walkanim){
+                                                                                                       player[i].targetanimation=player[i].getStop();
+                                                                                                       player[i].target=0;
+                                                                                                       player[i].targetframe=0;
+                                                                                               }
+                                                                                               if(player[i].targetanimation==sneakanim){
+                                                                                                       player[i].targetanimation=player[i].getCrouch();
+                                                                                                       if(player[i].currentanimation==sneakanim)player[i].target=0;
+                                                                                                       player[i].targetframe=0;
+                                                                                               }
+                                                                                       }
+                                                                                       if(player[i].targetanimation==walkanim&&(player[i].aitype==attacktypecutoff||player[i].aitype==searchtype||(player[i].aitype==passivetype&&player[i].numwaypoints<=1))){
+                                                                                               player[i].targetanimation=player[i].getStop();
+                                                                                               player[i].target=0;
+                                                                                               player[i].targetframe=0;
+                                                                                       }
+                                                                                       if(player[i].isRun()&&(player[i].aitype==passivetype)){
+                                                                                               player[i].targetanimation=player[i].getStop();
+                                                                                               player[i].target=0;
+                                                                                               player[i].targetframe=0;
+                                                                                       }
+                                                                               }
+                                                               }
+                                                               if(player[i].targetanimation==rollanim)player[i].targetrotation=oldtargetrotation;
+                                                       }
+
+                                                       //Rotation
+                                                       for(k=0;k<numplayers;k++){
+                                                               if(abs(player[k].rotation-player[k].targetrotation)>180){
+                                                                       if(player[k].rotation>player[k].targetrotation)player[k].rotation-=360;
+                                                                       else player[k].rotation+=360;
+                                                               }
+
+                                                               if(abs(player[k].rotation-player[k].targetrotation)>90&&(player[k].isRun()||player[k].targetanimation==walkanim)){
+                                                                       player[k].targetanimation=player[k].getStop();
+                                                                       player[k].targetframe=0;
+                                                                       player[k].target=0;
+                                                               }
+
+                                                               if(player[k].targetanimation==backhandspringanim||player[k].targetanimation==dodgebackanim){
+                                                                       player[k].targettilt=0;
+                                                               }
+                                                               if(player[k].targetanimation!=jumpupanim&&player[k].targetanimation!=backhandspringanim&&player[k].targetanimation!=jumpdownanim&&!player[k].isFlip()){
+                                                                       player[k].targettilt=0;
+                                                                       if(player[k].jumppower<0&&!player[k].jumpkeydown)player[k].jumppower=0;
+                                                                       player[k].jumppower+=multiplier*7;
+                                                                       if(player[k].isCrouch())player[k].jumppower+=multiplier*7;
+                                                                       //*(1-(player[k].damage/player[k].damagetolerance))
+                                                                       if(player[k].jumppower>5)player[k].jumppower=5;
+                                                               }
+
+                                                               if(player[k].isRun()){
+                                                                       player[k].targettilt=(player[k].rotation-player[k].targetrotation)/4;
+                                                               }
+
+                                                               if(abs(player[k].tilt-player[k].targettilt)<multiplier*150)player[k].tilt=player[k].targettilt;
+                                                               else if(player[k].tilt>player[k].targettilt){
+                                                                       player[k].tilt-=multiplier*150;
+                                                               }
+                                                               else if(player[k].tilt<player[k].targettilt){
+                                                                       player[k].tilt+=multiplier*150;
+                                                               }
+
+                                                               player[k].grabdelay-=multiplier;
+                                                       }
+
+                                                       for(k=0;k<numplayers;k++){
+                                                               player[k].DoAnimations();
+                                                               player[k].whichpatchx=player[k].coords.x/(terrain.size/subdivision*terrain.scale*terraindetail);
+                                                               player[k].whichpatchz=player[k].coords.z/(terrain.size/subdivision*terrain.scale*terraindetail);
+                                                       }
+
+                                                       objects.DoStuff();
+                                                       /*
+                                                       player[0].righthandmorphstart=0;
+                                                       player[0].righthandmorphend=1;
+                                                       player[0].lefthandmorphstart=0;
+                                                       player[0].lefthandmorphend=1;
+                                                       player[0].headmorphstart=0;
+                                                       player[0].headmorphend=2;*/
+
+                                                       /*
+                                                       if(IsKeyDown( theKeyMap, MAC_P_KEY )){
+                                                       if(player[0].righthandmorphend!=1)player[0].righthandmorphness=0;
+                                                       player[0].righthandmorphend=1;
+                                                       player[0].targetrighthandmorphness=1;
+
+                                                       if(player[0].lefthandmorphend!=0)player[0].lefthandmorphness=0;
+                                                       player[0].lefthandmorphend=0;
+                                                       player[0].targetlefthandmorphness=1;
+
+                                                       if(player[0].headmorphend!=2)player[0].headmorphness=0;
+                                                       player[0].headmorphend=2;
+                                                       player[0].targetheadmorphness=1;
+                                                       }
+                                                       if(IsKeyDown( theKeyMap, MAC_L_KEY )){
+                                                       if(player[0].righthandmorphend!=0)player[0].righthandmorphness=0;
+                                                       player[0].righthandmorphend=0;
+                                                       player[0].targetrighthandmorphness=1;
+
+                                                       if(player[0].lefthandmorphend!=1)player[0].lefthandmorphness=0;
+                                                       player[0].lefthandmorphend=1;
+                                                       player[0].targetlefthandmorphness=1;
+
+                                                       if(player[0].headmorphend!=0)player[0].headmorphness=0;
+                                                       player[0].headmorphend=0;
+                                                       player[0].targetheadmorphness=1;
+                                                       }
+                                                       */
+                                                       if(numenvsounds!=0)
+                                                               for(j=numenvsounds-1;j>=0;j--){
+                                                                       envsoundlife[j]-=multiplier;
+                                                                       if(envsoundlife[j]<0){
+                                                                               numenvsounds--;
+                                                                               envsoundlife[j]=envsoundlife[numenvsounds];
+                                                                               envsound[j]=envsound[numenvsounds];
+                                                                       }
+                                                               }
+                                                               if(!slomo)FSOUND_SetFrequency(FSOUND_ALL, 22050);
+                                                               if(slomo)FSOUND_SetFrequency(FSOUND_ALL, slomofreq);
+
+                                                               if(tutoriallevel==1){
+                                                                       XYZ temp;
+                                                                       XYZ temp2;
+                                                                       XYZ temp3;
+                                                                       XYZ oldtemp;
+                                                                       XYZ oldtemp2;
+                                                                       temp.x=1011;
+                                                                       temp.y=84;
+                                                                       temp.z=491;
+                                                                       temp2.x=1025;
+                                                                       temp2.y=75;
+                                                                       temp2.z=447;
+                                                                       temp3.x=1038;
+                                                                       temp3.y=76;
+                                                                       temp3.z=453;
+                                                                       oldtemp=temp;
+                                                                       oldtemp2=temp2;
+                                                                       if(tutorialstage>=51)
+                                                                               if(findDistancefast(&temp,&player[0].coords)>=findDistancefast(&temp,&temp2)-1||findDistancefast(&temp3,&player[0].coords)<4){
+                                                                                       FSOUND_SetFrequency(FSOUND_ALL, 0.001);
+
+                                                                                       PlayStreamEx( stream_music3, strm[stream_music3], NULL, TRUE);
+                                                                                       FSOUND_SetPaused(channels[stream_music3], FALSE);
+                                                                                       FSOUND_SetVolume(channels[stream_music3], 256);
+
+                                                                                       gameon=0;
+                                                                                       mainmenu=5;
+
+                                                                                       float gLoc[3]={0,0,0};
+                                                                                       float vel[3]={0,0,0};
+                                                                                       FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                                                                                       PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[fireendsound], 256);
+                                                                                       FSOUND_SetPaused(channels[fireendsound], FALSE);
+                                                                                       FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                                                                                       flashr=1;
+                                                                                       flashg=0;
+                                                                                       flashb=0;
+                                                                                       flashamount=1;
+                                                                                       flashdelay=1;
+                                                                               }
+                                                                               if(tutorialstage<51)
+                                                                                       if(findDistancefast(&temp,&player[0].coords)>=findDistancefast(&temp,&temp2)-1||findDistancefast(&temp3,&player[0].coords)<4){
+                                                                                               float gLoc[3];
+                                                                                               float vel[3];
+                                                                                               gLoc[0]=player[0].coords.x;
+                                                                                               gLoc[1]=player[0].coords.y;
+                                                                                               gLoc[2]=player[0].coords.z;
+                                                                                               vel[0]=0;
+                                                                                               vel[1]=0;
+                                                                                               vel[2]=0;
+                                                                                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[fireendsound], 256);
+                                                                                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+
+                                                                                               player[0].coords=(oldtemp+oldtemp2)/2;
+
+                                                                                               flashr=1;
+                                                                                               flashg=1;
+                                                                                               flashb=1;
+                                                                                               flashamount=1;
+                                                                                               flashdelay=1;
+                                                                                       }
+                                                                                       if(tutorialstage>=14&&tutorialstage<50)
+                                                                                               if(findDistancefast(&temp,&player[1].coords)>=findDistancefast(&temp,&temp2)-1||findDistancefast(&temp3,&player[1].coords)<4){
+                                                                                                       float gLoc[3];
+                                                                                                       float vel[3];
+                                                                                                       gLoc[0]=player[1].coords.x;
+                                                                                                       gLoc[1]=player[1].coords.y;
+                                                                                                       gLoc[2]=player[1].coords.z;
+                                                                                                       vel[0]=0;
+                                                                                                       vel[1]=0;
+                                                                                                       vel[2]=0;
+                                                                                                       PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                                                                                                       FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                                                                                                       FSOUND_SetVolume(channels[fireendsound], 256);
+                                                                                                       FSOUND_SetPaused(channels[fireendsound], FALSE);
+
+                                                                                                       for(int i=0;i<player[1].skeleton.num_joints;i++){
+                                                                                                               if(Random()%2==0){
+                                                                                                                       if(!player[1].skeleton.free)temp2=(player[1].coords-player[1].oldcoords)/multiplier/2;//velocity/2;
+                                                                                                                       if(player[1].skeleton.free)temp2=player[1].skeleton.joints[i].velocity*player[1].scale/2;
+                                                                                                                       if(!player[1].skeleton.free)temp=DoRotation(DoRotation(DoRotation(player[1].skeleton.joints[i].position,0,0,player[1].tilt),player[1].tilt2,0,0),0,player[1].rotation,0)*player[1].scale+player[1].coords;
+                                                                                                                       if(player[1].skeleton.free)temp=player[1].skeleton.joints[i].position*player[1].scale+player[1].coords;
+                                                                                                                       sprites.MakeSprite(breathsprite, temp,temp2, 1,1,1, .6+(float)abs(Random()%100)/200-.25, 1);
+                                                                                                               }
+                                                                                                       }
+
+                                                                                                       player[1].coords=(oldtemp+oldtemp2)/2;
+                                                                                                       for(int i=0;i<player[1].skeleton.num_joints;i++){
+                                                                                                               player[1].skeleton.joints[i].velocity=0;
+                                                                                                               if(Random()%2==0){
+                                                                                                                       if(!player[1].skeleton.free)temp2=(player[1].coords-player[1].oldcoords)/multiplier/2;//velocity/2;
+                                                                                                                       if(player[1].skeleton.free)temp2=player[1].skeleton.joints[i].velocity*player[1].scale/2;
+                                                                                                                       if(!player[1].skeleton.free)temp=DoRotation(DoRotation(DoRotation(player[1].skeleton.joints[i].position,0,0,player[1].tilt),player[1].tilt2,0,0),0,player[1].rotation,0)*player[1].scale+player[1].coords;
+                                                                                                                       if(player[1].skeleton.free)temp=player[1].skeleton.joints[i].position*player[1].scale+player[1].coords;
+                                                                                                                       sprites.MakeSprite(breathsprite, temp,temp2, 1,1,1, .6+(float)abs(Random()%100)/200-.25, 1);
+                                                                                                               }
+                                                                                                       }
+                                                                                               }
+                                                               }
+
+
+                                                               //3d sound
+                                                               static float gLoc[3];
+                                                               gLoc[0]=viewer.x;
+                                                               gLoc[1]=viewer.y;
+                                                               gLoc[2]=viewer.z;
+                                                               static float vel[3];
+                                                               vel[0]=(viewer.x-oldviewer.x)/multiplier;
+                                                               vel[1]=(viewer.y-oldviewer.y)/multiplier;
+                                                               vel[2]=(viewer.z-oldviewer.z)/multiplier;
+
+                                                               //Set orientation with forward and up vectors
+                                                               static XYZ upvector;
+                                                               upvector=0;
+                                                               upvector.z=-1;
+
+                                                               upvector=DoRotation(upvector,-rotation2+90,0,0);
+                                                               upvector=DoRotation(upvector,0,0-rotation,0);
+
+                                                               facing=0;
+                                                               facing.z=-1;
+                                                               
+                                                               facing=DoRotation(facing,-rotation2,0,0);
+                                                               facing=DoRotation(facing,0,0-rotation,0);
+               
+               
+                                                               static float ori[6];
+                                                               ori[0] = -facing.x;
+                                                               ori[1] = facing.y;
+                                                               ori[2] = -facing.z;
+                                                               ori[3] = -upvector.x;
+                                                               ori[4] = upvector.y;
+                                                               ori[5] = -upvector.z;
+
+                                                               FSOUND_3D_Listener_SetAttributes(&gLoc[0], &vel[0], ori[0], ori[1], ori[2], ori[3], ori[4], ori[5]);
+                                                               FSOUND_Update();
+
+                                                               oldviewer=viewer;
+               }
+       }
+
+       if(IsKeyDown(theKeyMap, MAC_F1_KEY)&&!freezetogglekeydown){
+               Screenshot();
+               freezetogglekeydown=1;
+       }
+}
+
+void   Game::TickOnce(){
+       //if(!console){
+       if(!mainmenu)
+               if(directing||indialogue==-1){
+                       rotation+=deltah*.7;
+                       if(!invertmouse)rotation2+=deltav*.7;
+                       if(invertmouse)rotation2-=deltav*.7;
+                       if(rotation2>90)rotation2=90;
+                       if(rotation2<-70)rotation2=-70;
+               }
+               if(mainmenu)rotation+=multiplier*5;
+               if(!mainmenu&&!indemo&&!registered){
+                       FSOUND_SetFrequency(FSOUND_ALL, 0.001);         
+                       PlayStreamEx( stream_music3, strm[stream_music3], NULL, TRUE);
+                       FSOUND_SetPaused(channels[stream_music3], FALSE);
+                       FSOUND_SetVolume(channels[stream_music3], 256);
+
+                       gameon=0;
+                       mainmenu=12;
+
+                       float gLoc[3]={0,0,0};
+                       float vel[3]={0,0,0};
+                       FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                       PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                       FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                       FSOUND_SetVolume(channels[fireendsound], 256);
+                       FSOUND_SetPaused(channels[fireendsound], FALSE);
+                       FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                       flashr=1;
+                       flashg=0;
+                       flashb=0;
+                       flashamount=1;
+                       flashdelay=1;
+               }
+
+               if(tryquit==1&&!registered&&mainmenu!=12){
+                       FSOUND_SetFrequency(FSOUND_ALL, 0.001);         
+                       PlayStreamEx( stream_music3, strm[stream_music3], NULL, TRUE);
+                       FSOUND_SetPaused(channels[stream_music3], FALSE);
+                       FSOUND_SetVolume(channels[stream_music3], 256);
+
+                       gameon=0;
+                       mainmenu=12;
+
+                       float gLoc[3]={0,0,0};
+                       float vel[3]={0,0,0};
+                       FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                       PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                       FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                       FSOUND_SetVolume(channels[fireendsound], 256);
+                       FSOUND_SetPaused(channels[fireendsound], FALSE);
+                       FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                       flashr=1;
+                       flashg=0;
+                       flashb=0;
+                       flashamount=1;
+                       flashdelay=1;
+               }
+               //}
+}
+
+void   Game::TickOnceAfter(){
+       static XYZ colviewer;
+       static XYZ coltarget;
+       static XYZ target;
+       static XYZ col;
+       static float brotate;
+       static XYZ facing;
+       static int i,j;
+       static float changedelay;
+       static bool alldead;
+       static float unseendelay;
+       static float cameraspeed;
+
+       if(!mainmenu){
+
+               if(environment==snowyenvironment)music1=stream_music1snow;
+               if(environment==grassyenvironment)music1=stream_music1grass;
+               if(environment==desertenvironment)music1=stream_music1desert;
+
+               realthreat=0;
+
+               musictype=music1;
+               for(i=0;i<numplayers;i++){
+                       if((player[i].aitype==attacktypecutoff||player[i].aitype==getweapontype||player[i].aitype==gethelptype||player[i].aitype==searchtype)&&!player[i].dead/*&&player[i].surprised<=0*/&&(player[i].targetanimation!=sneakattackedanim&&player[i].targetanimation!=knifesneakattackedanim&&player[i].targetanimation!=swordsneakattackedanim)){
+                               musictype=stream_music2;
+                               realthreat=1;
+                       }
+               }
+               if(player[0].dead)musictype=stream_music3;
+
+
+               if(musictype==stream_music2){
+                       unseendelay=1;
+               }
+
+               if(oldmusictype==stream_music2&&musictype!=stream_music2){
+                       unseendelay-=multiplier;
+                       if(unseendelay>0){
+                               musictype=stream_music2;
+                       }
+               }
+
+
+               if(loading==2){
+                       musictype=stream_music3;
+                       musicvolume[2]=512;
+                       musicvolume[0]=0;
+                       musicvolume[1]=0;
+                       musicvolume[3]=0;
+               }       
+
+               if(musictoggle){                        
+                       if(musictype!=oldmusictype&&musictype==stream_music2){
+                               static float gLoc[3];
+                               static float vel[3];
+                               gLoc[0]=cameraloc.x;
+                               gLoc[1]=cameraloc.y;
+                               gLoc[2]=cameraloc.z;
+                               vel[0]=0;
+                               vel[1]=0;
+                               vel[2]=0;
+                               PlaySoundEx( alarmsound, samp[alarmsound], NULL, TRUE);
+                               FSOUND_SetVolume(channels[alarmsound], 512);
+                               FSOUND_SetPaused(channels[alarmsound], FALSE);
+
+                       }
+               }
+               musicselected=musictype;
+
+               if(musicselected==music1)musicvolume[0]+=multiplier*450;
+               else musicvolume[0]-=multiplier*450;
+               if(musicselected==stream_music2)musicvolume[1]+=multiplier*450;
+               else musicvolume[1]-=multiplier*450;
+               if(musicselected==stream_music3)musicvolume[2]+=multiplier*450;
+               else musicvolume[2]-=multiplier*450;
+               /*
+               if(musicselected==music1)musicvolume[0]+=multiplier*100;
+               else musicvolume[0]-=multiplier*450;
+               if(musicselected==music2)musicvolume[1]+=multiplier*150;
+               else if(player[0].dead)musicvolume[1]-=multiplier*450;
+               else musicvolume[1]-=multiplier*100;
+               if(musicselected==music3)musicvolume[2]+=multiplier*450;
+               else musicvolume[2]-=multiplier*450;*/
+
+               for(i=0;i<3;i++){
+                       if(musicvolume[i]<0)musicvolume[i]=0;
+                       if(musicvolume[i]>512)musicvolume[i]=512;
+               }
+
+               if(musicvolume[2]>128&&!loading&&!mainmenu)musicvolume[2]=128;
+
+               if(musictoggle){                
+                       if(musicvolume[0]>0&&oldmusicvolume[0]<=0){
+                               PlayStreamEx( music1, strm[music1], NULL, TRUE);
+                               FSOUND_SetPaused(channels[music1], FALSE);
+                       }
+                       if(musicvolume[1]>0&&oldmusicvolume[1]<=0){
+                               PlayStreamEx( stream_music2, strm[stream_music2], NULL, TRUE);
+                               FSOUND_SetPaused(channels[stream_music2], FALSE);
+                       }
+                       if(musicvolume[2]>0&&oldmusicvolume[2]<=0){
+                               PlayStreamEx( stream_music3, strm[stream_music3], NULL, TRUE);
+                               FSOUND_SetPaused(channels[stream_music3], FALSE);
+                       }
+               }
+
+               if(!musictoggle){               
+                       FSOUND_SetPaused(channels[music1], TRUE);
+                       FSOUND_SetPaused(channels[stream_music2], TRUE);
+                       FSOUND_SetPaused(channels[stream_music3], TRUE);
+
+                       for(i=0;i<4;i++){
+                               oldmusicvolume[i]=0;
+                               musicvolume[i]=0;
+                       }
+               }
+
+               if(musictoggle){                
+                       if(musicvolume[0]<=0&&oldmusicvolume[0]>0){
+                               FSOUND_SetPaused(channels[music1], TRUE);
+                       }
+                       if(musicvolume[1]<=0&&oldmusicvolume[1]>0){
+                               FSOUND_SetPaused(channels[stream_music2], TRUE);
+                       }
+                       if(musicvolume[2]<=0&&oldmusicvolume[2]>0){
+                               FSOUND_SetPaused(channels[stream_music3], TRUE);
+                       }
+
+                       if(musicvolume[0]!=oldmusicvolume[0]){
+                               FSOUND_SetVolume(channels[music1], musicvolume[0]);
+                       }
+                       if(musicvolume[1]!=oldmusicvolume[1]){
+                               FSOUND_SetVolume(channels[stream_music2], musicvolume[1]);
+                       }
+                       if(musicvolume[2]!=oldmusicvolume[2]){
+                               FSOUND_SetVolume(channels[stream_music3], musicvolume[2]);
+                       }
+
+                       for(i=0;i<3;i++){
+                               oldmusicvolume[i]=musicvolume[i];
+                       }
+               }
+
+               killhotspot=2;
+               if(numhotspots)
+                       for(i=0;i<numhotspots;i++){
+                               if(hotspottype[i]>10&&hotspottype[i]<20){
+                                       if(player[hotspottype[i]-10].dead==0){
+                                               killhotspot=0;
+                                       }
+                                       else if(killhotspot==2)
+                                               killhotspot=1;
+                               }
+                       }
+                       if(killhotspot==2)killhotspot=0;
+
+
+                       winhotspot=0;
+                       if(numhotspots)
+                               for(i=0;i<numhotspots;i++){
+                                       if(hotspottype[i]==-1){
+                                               if(findDistancefast(&player[0].coords,&hotspot[i])<hotspotsize[i])
+                                                       winhotspot=1;
+                                       }
+                               }
+
+                               int numalarmed=0;
+                               if(numplayers>1)
+                                       for(i=1;i<numplayers;i++){              
+                                               if(!player[i].dead&&player[i].aitype==attacktypecutoff&&player[i].surprised<=0)numalarmed++;
+                                       }
+                                       if(numalarmed>maxalarmed)maxalarmed=numalarmed;
+
+                                       if(changedelay<=0&&!loading&&!editorenabled&&gameon&&!tutoriallevel&&changedelay!=-999&&!won){          
+                                               if(player[0].dead&&changedelay<=0){
+                                                       changedelay=1;
+                                                       targetlevel=whichlevel;
+                                               }
+                                               alldead=1;
+                                               if(numplayers>1)
+                                                       for(i=1;i<numplayers;i++){              
+                                                               if(!player[i].dead&&player[i].howactive<typedead1)alldead=0;
+                                                       }
+
+
+                                                       if(alldead&&!player[0].dead&&maptype==mapkilleveryone){
+                                                               changedelay=1;
+                                                               targetlevel=whichlevel+1;
+                                                               if(targetlevel>numchallengelevels-1)targetlevel=0;
+                                                       }
+                                                       if(winhotspot||windialogue){
+                                                               changedelay=0.1;
+                                                               targetlevel=whichlevel+1;
+                                                               if(targetlevel>numchallengelevels-1)targetlevel=0;
+                                                       }
+
+
+                                                       if(killhotspot){
+                                                               changedelay=1;
+                                                               targetlevel=whichlevel+1;
+                                                               if(targetlevel>numchallengelevels-1)targetlevel=0;
+                                                       }
+
+                                                       if(changedelay>0&&!player[0].dead&&!won){
+                                                               //high scores, awards, win
+                                                               if(campaign){
+                                                                       won=1;
+                                                                       accountcampaignchoices[accountactive][accountcampaignchoicesmade[accountactive]]=whichchoice;
+                                                                       accountcampaignchoicesmade[accountactive]++;
+                                                                       accountcampaignscore[accountactive]+=bonustotal;
+                                                                       scoreadded=1;
+                                                                       accountcampaigntime[accountactive]+=leveltime;
+                                                                       if(accountcampaignscore[accountactive]>accountcampaignhighscore[accountactive])accountcampaignhighscore[accountactive]=accountcampaignscore[accountactive];
+
+                                                                       //if(accountprogress[accountactive]<whichlevel+1)accountprogress[accountactive]=whichlevel+1;
+                                                               }
+                                                               else
+                                                               {
+                                                                       won=1;
+                                                                       if(!debugmode){
+                                                                               if(bonustotal-startbonustotal>accounthighscore[accountactive][whichlevel])accounthighscore[accountactive][whichlevel]=bonustotal-startbonustotal;
+                                                                               if(accountfasttime[accountactive][whichlevel]==0||leveltime<accountfasttime[accountactive][whichlevel])accountfasttime[accountactive][whichlevel]=leveltime;            
+                                                                       }
+                                                                       if(accountprogress[accountactive]<whichlevel+1)accountprogress[accountactive]=whichlevel+1;
+
+                                                               }
+                                                       }
+                                       }
+
+                                       if(!winfreeze){
+
+                                               if(leveltime<1){
+                                                       loading=0;
+                                                       changedelay=.1;
+                                                       alldead=0;
+                                                       winhotspot=0;
+                                                       killhotspot=0;
+                                               }
+
+                                               if(!editorenabled&&gameon&&!mainmenu){
+                                                       if(changedelay!=-999)changedelay-=multiplier/7;
+                                                       if(player[0].dead)targetlevel=whichlevel;
+                                                       if(loading==2&&!campaign){
+                                                               flashr=1;
+                                                               flashg=0;
+                                                               flashb=0;
+                                                               flashamount=1;
+                                                               flashdelay=1;
+                                                               loadtime=0;
+
+                                                               float gLoc[3]={0,0,0};
+                                                               float vel[3]={0,0,0};
+                                                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                                                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[firestartsound], 256);
+                                                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                                                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                                                               if(!player[0].dead&&targetlevel!=whichlevel){
+                                                                       startbonustotal=bonustotal;
+                                                               }
+                                                               if(!player[0].dead)Loadlevel(targetlevel);
+                                                               if(player[0].dead)Loadlevel(whichlevel);
+
+                                                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                                                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[fireendsound], 256);
+                                                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                                                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                                                               loading=3;
+                                                       }
+                                                       if(loading==2&&targetlevel==whichlevel){
+                                                               flashr=1;
+                                                               flashg=0;
+                                                               flashb=0;
+                                                               flashamount=1;
+                                                               flashdelay=1;
+                                                               loadtime=0;
+
+                                                               float gLoc[3]={0,0,0};
+                                                               float vel[3]={0,0,0};
+                                                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                                                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[firestartsound], 256);
+                                                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                                                               FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                                                               for(i=0;i<255;i++){
+                                                                       mapname[i]='\0';
+                                                               }
+                                                               mapname[0]=':';
+                                                               mapname[1]='D';
+                                                               mapname[2]='a';
+                                                               mapname[3]='t';
+                                                               mapname[4]='a';
+                                                               mapname[5]=':';
+                                                               mapname[6]='M';
+                                                               mapname[7]='a';
+                                                               mapname[8]='p';
+                                                               mapname[9]='s';
+                                                               mapname[10]=':';
+                                                               strcat(mapname,campaignmapname[levelorder[accountcampaignchoicesmade[accountactive]]]);//[campaignchoicewhich[whichchoice]]);
+                                                               Loadlevel(mapname);
+
+                                                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                                                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[fireendsound], 256);
+                                                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                                                               FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                                                               loading=3;
+                                                       }
+                                                       if(changedelay<=-999&&whichlevel!=-2&&!loading&&(player[0].dead||(alldead&&maptype==mapkilleveryone)||(winhotspot)||(killhotspot))&&!winfreeze)loading=1;
+                                                       if((player[0].dead||(alldead&&maptype==mapkilleveryone)||(winhotspot)||(windialogue)||(killhotspot))&&changedelay<=0){
+                                                               if(accountprogress[accountactive]>3&&!registered){
+                                                                       FSOUND_SetFrequency(FSOUND_ALL, 0.001);         
+                                                                       PlayStreamEx( stream_music3, strm[stream_music3], NULL, TRUE);
+                                                                       FSOUND_SetPaused(channels[stream_music3], FALSE);
+                                                                       FSOUND_SetVolume(channels[stream_music3], 256);
+
+                                                                       gameon=0;
+                                                                       mainmenu=12;
+                                                                       accountprogress[accountactive]=3;
+
+                                                                       float gLoc[3]={0,0,0};
+                                                                       float vel[3]={0,0,0};
+                                                                       FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 9999.0f, 99999.0f); 
+                                                                       PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[fireendsound], 256);
+                                                                       FSOUND_SetPaused(channels[fireendsound], FALSE);
+                                                                       FSOUND_Sample_SetMinMaxDistance(samp[fireendsound], 8.0f, 2000.0f);     
+
+                                                                       flashr=1;
+                                                                       flashg=0;
+                                                                       flashb=0;
+                                                                       flashamount=1;
+                                                                       flashdelay=1;
+                                                               }
+                                                               else{
+                                                                       if(whichlevel!=-2&&!loading&&!player[0].dead){
+                                                                               winfreeze=1;
+                                                                               changedelay=-999;
+                                                                       }
+                                                                       if(player[0].dead)loading=1;
+                                                               }
+                                                       }
+                                               }
+
+                                               if(campaign)
+                                                       if(mainmenu==0&&winfreeze&&(campaignchoosenext[campaignchoicewhich[whichchoice]])==1){
+                                                               if(campaignnumnext[campaignchoicewhich[whichchoice]]==0){
+                                                                       endgame=1;
+                                                               }
+                                                       }
+                                                       else if(mainmenu==0&&winfreeze){
+                                                               if(campaignchoosenext[campaignchoicewhich[whichchoice]]==2)
+                                                                       stealthloading=1;
+                                                               else stealthloading=0;
+
+                                                               if(!stealthloading){
+                                                                       float gLoc[3]={0,0,0};
+                                                                       float vel[3]={0,0,0};
+                                                                       FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 9999.0f, 99999.0f);       
+                                                                       PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[firestartsound], 256);
+                                                                       FSOUND_SetPaused(channels[firestartsound], FALSE);
+                                                                       FSOUND_Sample_SetMinMaxDistance(samp[firestartsound], 8.0f, 2000.0f);   
+
+                                                                       flashr=1;
+                                                                       flashg=0;
+                                                                       flashb=0;
+                                                                       flashamount=1;
+                                                                       flashdelay=1;
+                                                               }
+
+                                                               startbonustotal=0;
+
+                                                               //              ifstream ipstream(":Data:Campaigns:main.txt");  
+                                                               ifstream ipstream("./Data/Campaigns/main.txt"); 
+                                                               //campaignnumlevels=0;
+                                                               //accountcampaignchoicesmade[accountactive]=0;
+                                                               ipstream.ignore(256,':');
+                                                               ipstream >> campaignnumlevels;
+                                                               for(i=0;i<campaignnumlevels;i++){
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream.ignore(256,' ');
+                                                                       ipstream >> campaignmapname[i];
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream >> campaigndescription[i];
+                                                                       for(j=0;j<256;j++){
+                                                                               if(campaigndescription[i][j]=='_')campaigndescription[i][j]=' ';
+                                                                       }
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream >> campaignchoosenext[i];
+                                                                       ipstream.ignore(256,':');
+                                                                       ipstream >> campaignnumnext[i];
+                                                                       if(campaignnumnext[i])
+                                                                               for(j=0;j<campaignnumnext[i];j++){
+                                                                                       ipstream.ignore(256,':');
+                                                                                       ipstream >> campaignnextlevel[i][j];
+                                                                                       campaignnextlevel[i][j]-=1;
+                                                                               }
+                                                                               ipstream.ignore(256,':');
+                                                                               ipstream >> campaignlocationx[i];
+                                                                               ipstream.ignore(256,':');
+                                                                               ipstream >> campaignlocationy[i];
+                                                               }
+                                                               ipstream.close();
+
+                                                               for(i=0;i<campaignnumlevels;i++){
+                                                                       levelvisible[i]=0;
+                                                                       levelhighlight[i]=0;
+                                                               }
+
+
+                                                               for(i=0;i<campaignnumlevels;i++){
+                                                                       levelvisible[i]=0;
+                                                                       levelhighlight[i]=0;
+                                                               }
+
+                                                               levelorder[0]=0;
+                                                               levelvisible[0]=1;
+                                                               if(accountcampaignchoicesmade[accountactive])
+                                                                       for(i=0;i<accountcampaignchoicesmade[accountactive];i++){
+                                                                               levelorder[i+1]=campaignnextlevel[levelorder[i]][accountcampaignchoices[accountactive][i]];
+                                                                               levelvisible[levelorder[i+1]]=1;
+                                                                       }
+                                                                       int whichlevelstart;
+                                                                       whichlevelstart=accountcampaignchoicesmade[accountactive]-1;
+                                                                       if(whichlevelstart<0){
+                                                                               campaignchoicenum=1;
+                                                                               campaignchoicewhich[0]=0;
+                                                                       }
+                                                                       else
+                                                                       {
+                                                                               campaignchoicenum=campaignnumnext[levelorder[whichlevelstart]];
+                                                                               if(campaignchoicenum)
+                                                                                       for(i=0;i<campaignchoicenum;i++){
+                                                                                               campaignchoicewhich[i]=campaignnextlevel[levelorder[whichlevelstart]][i];
+                                                                                               levelvisible[campaignnextlevel[levelorder[whichlevelstart]][i]]=1;
+                                                                                               levelhighlight[campaignnextlevel[levelorder[whichlevelstart]][i]]=1;
+                                                                                       }
+                                                                       }
+
+                                                                       loading=2;
+                                                                       loadtime=0;
+                                                                       targetlevel=7;
+                                                                       //if(firstload)TickOnceAfter();
+                                                                       if(!firstload)LoadStuff();
+                                                                       //else {
+                                                                       for(i=0;i<255;i++){
+                                                                               mapname[i]='\0';
+                                                                       }
+                                                                       mapname[0]=':';
+                                                                       mapname[1]='D';
+                                                                       mapname[2]='a';
+                                                                       mapname[3]='t';
+                                                                       mapname[4]='a';
+                                                                       mapname[5]=':';
+                                                                       mapname[6]='M';
+                                                                       mapname[7]='a';
+                                                                       mapname[8]='p';
+                                                                       mapname[9]='s';
+                                                                       mapname[10]=':';
+
+                                                                       //accountcampaignchoices[accountactive][accountcampaignchoicesmade[accountactive]]=whichchoice;
+                                                                       //accountcampaignchoicesmade[accountactive]++;
+
+
+                                                                       strcat(mapname,campaignmapname[campaignchoicewhich[0]]);
+                                                                       whichchoice=0;
+                                                                       visibleloading=1;
+                                                                       stillloading=1;
+                                                                       Loadlevel(mapname);
+                                                                       campaign=1;
+                                                                       mainmenu=0;
+                                                                       gameon=1;
+                                                                       FSOUND_SetPaused(channels[stream_music3], TRUE);
+
+                                                                       stealthloading=0;
+                                                       }
+
+                                                       if(loading==3)loading=0;
+
+                                       }
+
+                                       oldmusictype=musictype;
+       }
+
+       facing=0;
+       facing.z=-1;
+
+       facing=DoRotation(facing,-rotation2,0,0);
+       facing=DoRotation(facing,0,0-rotation,0);
+       viewerfacing=facing;
+
+       brotate=0;
+       if(!cameramode){
+               if((animation[player[0].targetanimation].attack!=3&&animation[player[0].currentanimation].attack!=3)||player[0].skeleton.free)target=player[0].coords+player[0].currentoffset*(1-player[0].target)*player[0].scale+player[0].targetoffset*player[0].target*player[0].scale-player[0].facing*.05;
+               else target=player[0].oldcoords+player[0].currentoffset*(1-player[0].target)*player[0].scale+player[0].targetoffset*player[0].target*player[0].scale-player[0].facing*.05;
+               target.y+=.1;
+               if(player[0].skeleton.free){
+                       for(i=0;i<player[0].skeleton.num_joints;i++){
+                               if(player[0].skeleton.joints[i].position.y*player[0].scale+player[0].coords.y>target.y)                         
+                                       target.y=player[0].skeleton.joints[i].position.y*player[0].scale+player[0].coords.y;
+                       }
+                       target.y+=.1;
+               }
+               if(player[0].skeleton.free!=2&&!autocam){
+                       cameraspeed=20;
+                       if(findLengthfast(&player[0].velocity)>400){
+                               cameraspeed=20+(findLength(&player[0].velocity)-20)*.96;
+                       }
+                       if(player[0].skeleton.free==0&&player[0].targetanimation!=hanganim&&player[0].targetanimation!=climbanim)target.y+=1.4;
+                       coltarget=target-cameraloc;
+                       if(findLengthfast(&coltarget)<multiplier*multiplier*400)cameraloc=target;
+                       else {
+                               Normalise(&coltarget);
+                               if(player[0].targetanimation!=hanganim&&player[0].targetanimation!=climbanim&&player[0].currentanimation!=climbanim&&player[0].currentoffset.x==0)cameraloc=cameraloc+coltarget*multiplier*cameraspeed;
+                               else cameraloc=cameraloc+coltarget*multiplier*8;
+                       }
+                       if(editorenabled)cameraloc=target;
+                       cameradist+=multiplier*5;
+                       if(cameradist>2.3)cameradist=2.3;
+                       viewer=cameraloc-facing*cameradist;
+                       colviewer=viewer;
+                       coltarget=cameraloc;
+                       objects.SphereCheckPossible(&colviewer, findDistance(&colviewer,&coltarget));
+                       if(terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz])
+                               for(j=0;j<terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz];j++){
+                                       i=terrain.patchobjects[player[0].whichpatchx][player[0].whichpatchz][j];
+                                       colviewer=viewer;
+                                       coltarget=cameraloc;
+                                       if(objects.model[i].LineCheckPossible(&colviewer,&coltarget,&col,&objects.position[i],&objects.rotation[i])!=-1)viewer=col;     
+                               }
+                               if(terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz])
+                                       for(j=0;j<terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz];j++){
+                                               i=terrain.patchobjects[player[0].whichpatchx][player[0].whichpatchz][j];
+                                               colviewer=viewer;
+                                               if(objects.model[i].SphereCheck(&colviewer,.15,&col,&objects.position[i],&objects.rotation[i])!=-1){
+                                                       viewer=colviewer;
+                                               }
+                                       }
+                                       cameradist=findDistance(&viewer,&target);
+                                       if(viewer.y<terrain.getHeight(viewer.x,viewer.z)+.6){
+                                               viewer.y=terrain.getHeight(viewer.x,viewer.z)+.6;
+                                       }
+                                       if(cameraloc.y<terrain.getHeight(cameraloc.x,cameraloc.z)){
+                                               cameraloc.y=terrain.getHeight(cameraloc.x,cameraloc.z);
+                                       }
+               }
+               if(player[0].skeleton.free!=2&&autocam){
+                       cameraspeed=20;
+                       if(findLengthfast(&player[0].velocity)>400){
+                               cameraspeed=20+(findLength(&player[0].velocity)-20)*.96;
+                       }
+                       if(player[0].skeleton.free==0&&player[0].targetanimation!=hanganim&&player[0].targetanimation!=climbanim)target.y+=1.4;
+                       cameradist+=multiplier*5;
+                       if(cameradist>3.3)cameradist=3.3;
+                       coltarget=target-cameraloc;
+                       if(findLengthfast(&coltarget)<multiplier*multiplier*400)cameraloc=target;
+                       else if(findLengthfast(&coltarget)>1)
+                       {
+                               Normalise(&coltarget);
+                               if(player[0].targetanimation!=hanganim&&player[0].targetanimation!=climbanim&&player[0].currentanimation!=climbanim&&player[0].currentoffset.x==0)cameraloc=cameraloc+coltarget*multiplier*cameraspeed;
+                               else cameraloc=cameraloc+coltarget*multiplier*8;
+                       }
+                       if(editorenabled)cameraloc=target;
+                       viewer=cameraloc;
+                       colviewer=viewer;
+                       coltarget=cameraloc;
+                       objects.SphereCheckPossible(&colviewer, findDistance(&colviewer,&coltarget));
+                       if(terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz])
+                               for(j=0;j<terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz];j++){
+                                       i=terrain.patchobjects[player[0].whichpatchx][player[0].whichpatchz][j];
+                                       colviewer=viewer;
+                                       coltarget=cameraloc;
+                                       if(objects.model[i].LineCheckPossible(&colviewer,&coltarget,&col,&objects.position[i],&objects.rotation[i])!=-1)viewer=col;     
+                               }
+                               if(terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz])
+                                       for(j=0;j<terrain.patchobjectnum[player[0].whichpatchx][player[0].whichpatchz];j++){
+                                               i=terrain.patchobjects[player[0].whichpatchx][player[0].whichpatchz][j];
+                                               colviewer=viewer;
+                                               if(objects.model[i].SphereCheck(&colviewer,.15,&col,&objects.position[i],&objects.rotation[i])!=-1){
+                                                       viewer=colviewer;
+                                               }
+                                       }
+                                       cameradist=findDistance(&viewer,&target);
+                                       if(viewer.y<terrain.getHeight(viewer.x,viewer.z)+.6){
+                                               viewer.y=terrain.getHeight(viewer.x,viewer.z)+.6;
+                                       }
+                                       if(cameraloc.y<terrain.getHeight(cameraloc.x,cameraloc.z)){
+                                               cameraloc.y=terrain.getHeight(cameraloc.x,cameraloc.z);
+                                       }
+               }
+               if(camerashake>.8)camerashake=.8;
+               //if(woozy>10)woozy=10;
+               //woozy+=multiplier;
+               woozy+=multiplier;
+               if(player[0].dead)camerashake=0;
+               if(player[0].dead)woozy=0;
+               camerashake-=multiplier*2;
+               blackout-=multiplier*2;
+               //if(player[0].isCrouch())woozy-=multiplier*8;
+               if(camerashake<0)camerashake=0;
+               if(blackout<0)blackout=0;
+               //if(woozy<0)woozy=0;
+               if(camerashake){
+                       viewer.x+=(float)(Random()%100)*.0005*camerashake;
+                       viewer.y+=(float)(Random()%100)*.0005*camerashake;
+                       viewer.z+=(float)(Random()%100)*.0005*camerashake;
+               }
+       }
+}
\ No newline at end of file
diff --git a/Source/Globals.cpp b/Source/Globals.cpp
new file mode 100644 (file)
index 0000000..0a4c6d2
--- /dev/null
@@ -0,0 +1,250 @@
+#include "gl.h"
+#include "Quaternions.h"
+#include "Lights.h"
+#include "Skeleton.h"
+#include "fmod.h"
+#include "Terrain.h"
+#include "Sprites.h"
+//#include <agl.h>
+#include "Frustum.h"
+#include "Objects.h"
+#include "Weapons.h"
+#include "Person.h"
+#include "TGALoader.h"
+
+#include "Constants.h"
+
+bool visibleloading = 0;
+FSOUND_SAMPLE  *samp[100] = {0};
+FSOUND_STREAM * strm[20] = {0};
+int channels[100] = {0};
+
+float volume = 0;bool buttons[3] = {0};
+bool oldbuttons[3] = {0};
+bool ismotionblur = 0;
+float usermousesensitivity = 0;
+bool floatjump = 0;
+bool cellophane = 0;
+bool autoslomo = 0;
+bool decals = 0;
+bool invertmouse = 0;
+bool texttoggle = 0;
+float blurness = 0;
+float targetblurness = 0;
+float windvar = 0;
+float precipdelay = 0;
+float gamespeed = 0;
+float oldgamespeed = 0;
+float tintr = 0,tintg = 0,tintb = 0;
+int difficulty = 0;
+float multiplier = 0;
+float realmultiplier = 0;
+float screenwidth = 0,screenheight = 0;
+float viewdistance = 0;
+XYZ viewer;
+XYZ viewerfacing;
+XYZ lightlocation;
+float fadestart = 0;
+int environment = 0;
+float texscale = 0;
+float gravity = 0;
+Light light;
+Animation animation[animation_count];
+Skeleton testskeleton;
+int numsounds = 0;
+Terrain terrain;
+Sprites sprites;
+float sps = 0;
+#ifdef WIN32
+HDC hDC;
+#else
+AGLContext gaglContext;
+#endif
+int kTextureSize = 0;
+int detail = 0;
+FRUSTUM frustum;
+float texdetail = 0;
+float realtexdetail = 0;
+float terraindetail = 0;
+float playerdist = 0;
+Objects objects;
+int slomo = 0;
+float slomodelay = 0;
+GLubyte bloodText[512*512*3] = {0};
+GLubyte wolfbloodText[512*512*3] = {0};
+float colors[3] = {0};
+int bloodtoggle = 0;
+bool osx = 0;
+float camerashake = 0;
+float woozy = 0;
+float blackout = 0;
+bool foliage = 0;
+bool musictoggle = 0;
+bool trilinear;
+Weapons weapons;
+bool damageeffects = 0;
+//apvector<Person> player(maxplayers);
+Person player[maxplayers];
+int numplayers = 0;
+bool ambientsound = 0;
+bool mousejump = 0;
+bool freeze = 0;
+bool winfreeze = 0;
+float flashamount = 0,flashr = 0,flashg = 0,flashb = 0;
+int flashdelay = 0;
+bool vblsync = 0;
+float motionbluramount = 0;
+bool keyboardfrozen = 0;
+int newnetmessages = 0;
+char netmessages[256] = {0};
+char mapname[256] = {0};
+bool loadingstuff = 0;
+bool stillloading = 0;
+bool showpoints = 0;
+bool alwaysblur = 0;
+bool immediate = 0;
+bool velocityblur = 0;
+int test = 0;
+XYZ windvector;
+short vRefNum = 0;
+long dirID = 0;
+int mainmenu = 0;
+int oldmainmenu = 0;
+GLubyte texturearray[512*512*3] = {0};
+int loadscreencolor = 0;
+int whichjointstartarray[26] = {0};
+int whichjointendarray[26] = {0};
+int kBitsPerPixel = 0;
+
+int numhotspots = 0;
+XYZ hotspot[40];
+int hotspottype[40] = {0};
+float hotspotsize[40] = {0};
+char hotspottext[40][256] = {0};
+int currenthotspot = 0;        
+int winhotspot = 0;
+int windialogue = 0;
+int killhotspot = 0;
+
+float menupulse = 0;
+
+int numdialogues = 0;
+int numdialogueboxes[max_dialogues] = {0};
+int dialoguetype[max_dialogues] = {0};
+int dialogueboxlocation[max_dialogues][max_dialoguelength] = {0};
+float dialogueboxcolor[max_dialogues][max_dialoguelength][3] = {0};
+int dialogueboxsound[max_dialogues][max_dialoguelength] = {0};
+char dialoguetext[max_dialogues][max_dialoguelength][128] = {0};
+char dialoguename[max_dialogues][max_dialoguelength][64] = {0};
+XYZ dialoguecamera[max_dialogues][max_dialoguelength] = {0};
+XYZ participantlocation[max_dialogues][10] = {0};
+int participantfocus[max_dialogues][max_dialoguelength] = {0};
+int participantaction[max_dialogues][max_dialoguelength] = {0};
+float participantrotation[max_dialogues][10] = {0};
+XYZ participantfacing[max_dialogues][max_dialoguelength][10] = {0};
+float dialoguecamerarotation[max_dialogues][max_dialoguelength] = {0};
+float dialoguecamerarotation2[max_dialogues][max_dialoguelength] = {0};
+int indialogue = 0;
+int whichdialogue = 0;
+int directing = 0;
+float dialoguetime = 0;
+int dialoguegonethrough[20] = {0};
+
+float smoketex = 0;
+
+float slomospeed = 0;
+float slomofreq = 0;
+
+int tutoriallevel = 0;
+int tutorialstage = 0;
+float tutorialstagetime = 0;
+float tutorialmaxtime = 0;
+float tutorialsuccess = 0;
+
+bool againbonus = 0;
+
+float damagedealt = 0;
+float damagetaken = 0;
+
+int maptype = 0;
+
+int editoractive = 0;
+int editorpathtype = 0;
+
+bool reversaltrain = 0;
+bool cananger = 0;
+bool canattack = 0;
+
+bool skyboxtexture = 0;
+float skyboxr = 0;
+float skyboxg = 0;
+float skyboxb = 0;
+float skyboxlightr = 0;
+float skyboxlightg = 0;
+float skyboxlightb = 0;
+
+float bonusnum[100] = {0};
+
+int hostile = 0;
+float hostiletime = 0;
+
+XYZ envsound[30] = {0};
+float envsoundvol[30] = {0};
+float envsoundlife[30] = {0};
+int numenvsounds;
+
+
+bool tilt2weird = 0;
+bool tiltweird = 0;
+bool midweird = 0;
+bool proportionweird = 0;
+bool vertexweird[6] = {0};
+TGAImageRec texture;
+bool debugmode = 0;
+
+int oldbonus = 0;
+int bonus = 0;
+float bonusvalue = 0;
+float bonustotal = 0;
+float startbonustotal = 0;
+float bonustime = 0;
+
+int numaccounts = 0;
+int accountactive = 0;
+int accountdifficulty[10] = {0};
+int accountprogress[10] = {0};
+float accountpoints[10] = {0};
+float accounthighscore[10][50] = {0};
+float accountfasttime[10][50] = {0};
+bool accountunlocked[10][60] = {0};
+char accountname[10][256] = {0};
+float accountcampaignhighscore[10] = {0};
+float accountcampaignfasttime[10] = {0};
+float accountcampaignscore[10] = {0};
+float accountcampaigntime[10] = {0};
+int accountcampaignchoicesmade[10] = {0};int accountcampaignchoices[10][5000] = {0};
+bool won = 0;
+
+
+bool campaign = 0;
+
+int numfalls = 0;
+int numflipfail = 0;
+int numseen = 0;
+int numresponded = 0;
+int numstaffattack = 0;
+int numswordattack = 0;
+int numknifeattack = 0;
+int numunarmedattack = 0;
+int numescaped = 0;
+int numflipped = 0;
+int numwallflipped = 0;
+int numthrowkill = 0;
+int numafterkill = 0;
+int numreversals = 0;
+int numattacks = 0;
+int maxalarmed = 0;
+
+bool gamestarted = 0;
+
+//TextureList textures;
diff --git a/Source/Lights.cpp b/Source/Lights.cpp
new file mode 100644 (file)
index 0000000..63d1a7c
--- /dev/null
@@ -0,0 +1,125 @@
+/**> HEADER FILES <**/
+#include "Lights.h"
+
+void SetUpLight(Light* whichsource, int whichlight){
+       static float qattenuation[]={0.0002f};
+       static float cattenuation[]={1.5f};
+       static float lattenuation[]={0.5f};
+       static float zattenuation[]={0.0f};
+
+       //Initialize lights
+
+       if(whichlight==0){
+               GLfloat LightAmbient[]=         { whichsource->ambient[0], whichsource->ambient[1], whichsource->ambient[2], 1.0f};
+               GLfloat LightDiffuse[]=         { whichsource->color[0], whichsource->color[1], whichsource->color[2], 1.0f };
+               GLfloat LightPosition[]=        { whichsource->location.x, whichsource->location.y, whichsource->location.z, 0.0f };
+
+               //glLightfv(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, qattenuation);
+               glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
+               glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);         
+               glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);         
+               glEnable(GL_LIGHT0);    
+       }
+
+       if(whichlight==1){
+               GLfloat LightAmbient[]=         { 0, 0, 0, 1.0f};
+               GLfloat LightDiffuse[]=         { whichsource->color[0], whichsource->color[1], whichsource->color[2], 1.0f };
+               GLfloat LightPosition[]=        { whichsource->location.x, whichsource->location.y, whichsource->location.z, 1.0f };
+
+               glLightfv(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, qattenuation);
+               glLightfv(GL_LIGHT1, GL_POSITION, LightPosition);
+               glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);         
+               glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);         
+               glEnable(GL_LIGHT1);    
+       }
+
+       if(whichlight==2){
+               GLfloat LightAmbient[]=         { 0, 0, 0, 1.0f};
+               GLfloat LightDiffuse[]=         { whichsource->color[0], whichsource->color[1], whichsource->color[2], 1.0f };
+               GLfloat LightPosition[]=        { whichsource->location.x, whichsource->location.y, whichsource->location.z, 1.0f };
+
+               glLightfv(GL_LIGHT2, GL_QUADRATIC_ATTENUATION, qattenuation);
+               glLightfv(GL_LIGHT2, GL_POSITION, LightPosition);
+               glLightfv(GL_LIGHT2, GL_AMBIENT, LightAmbient);         
+               glLightfv(GL_LIGHT2, GL_DIFFUSE, LightDiffuse);         
+               glEnable(GL_LIGHT2);    
+       }
+
+       if(whichlight==3){
+               GLfloat LightAmbient[]=         { 0, 0, 0, 1.0f};
+               GLfloat LightDiffuse[]=         { whichsource->color[0], whichsource->color[1], whichsource->color[2], 1.0f };
+               GLfloat LightPosition[]=        { whichsource->location.x, whichsource->location.y, whichsource->location.z, 1.0f };
+
+               glLightfv(GL_LIGHT3, GL_QUADRATIC_ATTENUATION, qattenuation);
+               glLightfv(GL_LIGHT3, GL_POSITION, LightPosition);
+               glLightfv(GL_LIGHT3, GL_AMBIENT, LightAmbient);         
+               glLightfv(GL_LIGHT3, GL_DIFFUSE, LightDiffuse);         
+               glEnable(GL_LIGHT3);    
+       }
+
+       if(whichlight==4){
+               GLfloat LightAmbient[]=         { 0, 0, 0, 1.0f};
+               GLfloat LightDiffuse[]=         { whichsource->color[0], whichsource->color[1], whichsource->color[2], 1.0f };
+               GLfloat LightPosition[]=        { whichsource->location.x, whichsource->location.y, whichsource->location.z, 1.0f };
+
+               glLightfv(GL_LIGHT4, GL_QUADRATIC_ATTENUATION, qattenuation);
+               glLightfv(GL_LIGHT4, GL_POSITION, LightPosition);
+               glLightfv(GL_LIGHT4, GL_AMBIENT, LightAmbient);         
+               glLightfv(GL_LIGHT4, GL_DIFFUSE, LightDiffuse);         
+               glEnable(GL_LIGHT4);    
+       }
+
+       if(whichlight==5){
+               GLfloat LightAmbient[]=         { 0, 0, 0, 1.0f};
+               GLfloat LightDiffuse[]=         { whichsource->color[0], whichsource->color[1], whichsource->color[2], 1.0f };
+               GLfloat LightPosition[]=        { whichsource->location.x, whichsource->location.y, whichsource->location.z, 1.0f };
+
+               glLightfv(GL_LIGHT5, GL_QUADRATIC_ATTENUATION, qattenuation);
+               glLightfv(GL_LIGHT5, GL_POSITION, LightPosition);
+               glLightfv(GL_LIGHT5, GL_AMBIENT, LightAmbient);         
+               glLightfv(GL_LIGHT5, GL_DIFFUSE, LightDiffuse);         
+               glEnable(GL_LIGHT5);    
+       }
+
+       if(whichlight==6){
+               GLfloat LightAmbient[]=         { 0, 0, 0, 1.0f};
+               GLfloat LightDiffuse[]=         { whichsource->color[0], whichsource->color[1], whichsource->color[2], 1.0f };
+               GLfloat LightPosition[]=        { whichsource->location.x, whichsource->location.y, whichsource->location.z, 1.0f };
+
+               glLightfv(GL_LIGHT6, GL_QUADRATIC_ATTENUATION, qattenuation);
+               glLightfv(GL_LIGHT6, GL_POSITION, LightPosition);
+               glLightfv(GL_LIGHT6, GL_AMBIENT, LightAmbient);         
+               glLightfv(GL_LIGHT6, GL_DIFFUSE, LightDiffuse);         
+               glEnable(GL_LIGHT6);    
+       }
+
+       if(whichlight==7){
+               GLfloat LightAmbient[]=         { 0, 0, 0, 1.0f};
+               GLfloat LightDiffuse[]=         { whichsource->color[0], whichsource->color[1], whichsource->color[2], 1.0f };
+               GLfloat LightPosition[]=        { whichsource->location.x, whichsource->location.y, whichsource->location.z, 1.0f };
+
+               glLightfv(GL_LIGHT7, GL_QUADRATIC_ATTENUATION, qattenuation);
+               glLightfv(GL_LIGHT7, GL_POSITION, LightPosition);
+               glLightfv(GL_LIGHT7, GL_AMBIENT, LightAmbient);         
+               glLightfv(GL_LIGHT7, GL_DIFFUSE, LightDiffuse);         
+               glEnable(GL_LIGHT7);    
+       }
+}
+
+void SetUpMainLight(Light* whichsource, int whichlight, float ambientr, float ambientg, float ambientb){
+       static float qattenuation[]={0.0f};
+
+       //Initialize lights
+
+       if(whichlight==0){
+               GLfloat LightAmbient[]=         { ambientr, ambientg, ambientb, 1.0f};
+               GLfloat LightDiffuse[]=         { whichsource->color[0], whichsource->color[1], whichsource->color[2], 1.0f };
+               GLfloat LightPosition[]=        { whichsource->location.x, whichsource->location.y, whichsource->location.z, 1.0f };
+
+               glLightfv(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, qattenuation);
+               glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);
+               glLightfv(GL_LIGHT0, GL_AMBIENT, LightAmbient);         
+               glLightfv(GL_LIGHT0, GL_DIFFUSE, LightDiffuse);         
+               glEnable(GL_LIGHT0);    
+       }
+}
\ No newline at end of file
diff --git a/Source/Lights.h b/Source/Lights.h
new file mode 100644 (file)
index 0000000..32d9f56
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _LIGHTS_H_
+#define _LIGHTS_H_
+
+
+/**> HEADER FILES <**/
+#include "gl.h"
+#include "Quaternions.h"
+
+class Light{
+public:
+       GLint type;
+       GLfloat color[3];
+       GLfloat ambient[3];
+       int attach;
+       XYZ location;
+};
+
+void SetUpMainLight(Light* whichsource, int whichlight, float ambientr, float ambientg, float ambientb);
+void SetUpLight(Light* whichsource, int whichlight);
+
+#endif
\ No newline at end of file
diff --git a/Source/LinkedList.h b/Source/LinkedList.h
new file mode 100644 (file)
index 0000000..6bf5337
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Portions Copyright (c) 1999-2002 Apple Computer, Inc.  All Rights
+ * Reserved.  This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.1 (the "License").  You may not use this file
+ * except in compliance with the License.  Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ *
+ * Modified: $Date: 2002/04/27 20:52:48 $
+ * Revision: $Id: LinkedList.h,v 1.3 2002/04/27 20:52:48 lane Exp $
+ */
+
+
+/*
+       File:           LinkedList.h
+
+       Contains:
+
+*/
+
+#ifndef __LINKEDLIST__
+#define __LINKEDLIST__
+
+
+//we cant just use "macintosh_build" - the mac macho_build is designated as "posix_build" but may 
+//include open transport in some cases
+#ifndef __OPENTRANSPORT__
+//#if (!macintosh_build)
+
+#include <stddef.h>            //for OTGetLinkObject replacement
+
+#include "OPUtils.h"   //for true/false
+
+#if (windows_build)
+
+// ECF 010928 win32 syncronization routines for safe critical sections.  We can't simply use TryEnterCriticalSection()
+// to return a true/false value because it's not available in win95 and 98
+class OSCriticalSection
+{
+       public:
+               NMBoolean locked;
+               OSCriticalSection() {locked = false; InitializeCriticalSection(&theCriticalSection);}
+               ~OSCriticalSection() {DeleteCriticalSection(&theCriticalSection);}
+               NMBoolean       acquire()       {       if (locked == true) return false; //dont have to wait in this case      
+                                                               EnterCriticalSection(&theCriticalSection);
+                                                               if (locked) {LeaveCriticalSection(&theCriticalSection); return false;}
+                                                               else {locked = true; LeaveCriticalSection(&theCriticalSection); return true;}}
+               void    release()       {       EnterCriticalSection(&theCriticalSection);
+                                                               locked = false; LeaveCriticalSection(&theCriticalSection);}
+
+       CRITICAL_SECTION theCriticalSection;
+};
+#endif //windows_build
+
+#if (posix_build)
+#include <pthread.h>
+class OSCriticalSection
+{
+       public:
+               OSCriticalSection() {pthread_mutex_init(&theMutex,NULL);}
+               ~OSCriticalSection() {pthread_mutex_destroy(&theMutex);}
+               NMBoolean       acquire()       {       int error = pthread_mutex_trylock(&theMutex);
+                                                                       if (error) return false; else return true;}
+               void    release()       {       pthread_mutex_unlock(&theMutex);}
+
+               pthread_mutex_t theMutex;
+};
+
+#endif //(posix_build)
+
+/*     -------------------------------------------------------------------------
+       ** OTLIFO
+       **
+       ** These are functions to implement a LIFO list that is interrupt-safe.
+       ** The only function which is not is OTReverseList.  Normally, you create
+       ** a LIFO list, populate it at interrupt time, and then use OTLIFOStealList
+       ** to atomically remove the list, and OTReverseList to flip the list so that
+       ** it is a FIFO list, which tends to be more useful.
+       ------------------------------------------------------------------------- */
+
+       class OTLink;
+       class OTLIFO;
+
+       class OTLink
+       {
+               public:
+                       OTLink* fNext;
+                       void    Init()
+                                               { fNext = NULL; }
+       };
+
+       class OTLIFO
+       {
+               public:
+                       OSCriticalSection theLock;
+                       OTLink* fHead;
+               
+                       void    Init()  
+                                       { fHead = NULL; }
+               
+                       void    Enqueue(OTLink* link)
+                                                       { 
+                                                               while (true) {if (theLock.acquire()) break;}
+                                                               link->fNext = fHead;
+                                                               fHead = link;   
+                                                               theLock.release();              
+                                                       }
+                                       
+
+                       OTLink* Dequeue()
+                                                       {
+                                                               while (true) {if (theLock.acquire()) break;}                                            
+                                                               OTLink *origHead = fHead;
+                                                               fHead = fHead->fNext;
+                                                               theLock.release();                                                                      
+                                                               return origHead;
+                                                       }
+
+                                               
+                       OTLink* StealList()
+                                                       {       
+                                                               while (true) {if (theLock.acquire()) break;}
+                                                               OTLink *origHead = fHead;
+                                                               fHead = NULL;
+                                                               theLock.release();
+                                                               return origHead;
+                                                       }
+                                               
+                                               
+                       NMBoolean       IsEmpty()
+                                                       {
+                                                               return fHead == NULL;
+                                                       }
+       };
+
+/*     -------------------------------------------------------------------------
+       ** OTList
+       **
+       ** An OTList is a non-interrupt-safe list, but has more features than the
+       ** OTLIFO list. It is a standard singly-linked list.
+       ------------------------------------------------------------------------- */
+
+       typedef struct OTList   OTList;
+
+               typedef NMBoolean (*OTListSearchProcPtr)(const void* ref, OTLink* linkToCheck);
+               //
+               // Remove the last link from the list
+               //
+       extern OTLink*          OTRemoveLast(OTList* pList);
+               //
+               // Return the first link from the list
+               //
+       extern OTLink*          OTGetFirst(OTList* pList);
+               //
+               // Return the last link from the list
+               //
+       extern OTLink*          OTGetLast(OTList* pList);
+               //
+               // Return true if the link is present in the list
+               //
+       extern NMBoolean                OTIsInList(OTList* pList, OTLink* link);
+               //
+               // Find a link in the list which matches the search criteria
+               // established by the search proc and the refPtr.  This is done
+               // by calling the search proc, passing it the refPtr and each
+               // link in the list, until the search proc returns true.
+               // NULL is returned if the search proc never returned true.
+               //
+       extern OTLink*          OTFindLink(OTList* pList, OTListSearchProcPtr proc, const void* refPtr);
+               //
+               // Remove the specified link from the list, returning true if it was found
+               //
+       extern NMBoolean                OTRemoveLink(OTList*, OTLink*);
+               //
+               // Similar to OTFindLink, but it also removes it from the list.
+               //
+       extern OTLink*          OTFindAndRemoveLink(OTList* pList, OTListSearchProcPtr proc, const void* refPtr);
+               //
+               // Return the "index"th link in the list
+               //
+       extern OTLink*          OTGetIndexedLink(OTList* pList, size_t index);
+
+       struct OTList
+       {
+               OTLink*         fHead;
+               
+               void            Init()  
+                                               { fHead = NULL; }
+               
+               NMBoolean               IsEmpty()
+                                               { return fHead == NULL; }
+                                               
+               void            AddFirst(OTLink* link)
+                                                       { 
+                                                               link->fNext = fHead;
+                                                               fHead = link;                   
+                                                       }
+
+               void            AddLast(OTLink* link)
+                                                       {
+                                                               if (fHead == NULL)
+                                                                       fHead = link->fNext;
+                                                               else
+                                                               {
+                                                                       OTLink *current = fHead;
+                                                                       
+                                                                       while (current->fNext != NULL)
+                                                                               current = current->fNext;
+                                                                               
+                                                                       current->fNext = link;
+                                                               }
+                                                               
+                                                               
+                                                               link->fNext = fHead;
+                                                               fHead = link;                   
+                                                       }
+
+               
+               OTLink*         GetFirst()
+                                               { return OTGetFirst(this); }
+               
+               OTLink*         GetLast()
+                                               { return OTGetLast(this); }
+               
+               OTLink*         RemoveFirst()
+                                                       {
+                                                               OTLink *origHead = fHead;
+                                                               fHead = fHead->fNext;
+                                                               return origHead;
+                                                       }
+                                                               
+               OTLink*         RemoveLast()
+                                               { return OTRemoveLast(this); }
+                                               
+               NMBoolean               IsInList(OTLink* link)
+                                               { return OTIsInList(this, link); }
+                                               
+               OTLink*         FindLink(OTListSearchProcPtr proc, const void* ref)
+                                               { return OTFindLink(this, proc, ref); }
+                                               
+               NMBoolean               RemoveLink(OTLink* link)
+                                               { return OTRemoveLink(this, link); }
+                                               
+               OTLink*         RemoveLink(OTListSearchProcPtr proc, const void* ref)
+                                               { return OTFindAndRemoveLink(this, proc, ref); }
+                                               
+               OTLink*         GetIndexedLink(size_t index)
+                                               { return OTGetIndexedLink(this, index); }
+       };
+       
+       
+//FIXME!!  this is a recursive function and will crash and burn on large lists
+static OTLink* OTReverseList(OTLink *headRef)
+{
+       OTLink  *first;
+       OTLink  *rest;
+
+       if (headRef == NULL) return NULL;
+       
+       first = headRef;
+       rest = (OTLink *) first->fNext;
+       
+       if (rest == NULL) return headRef;
+       
+       rest = OTReverseList(rest);
+       
+       first->fNext->fNext = first;
+       first->fNext = NULL;
+       
+       return rest;
+}
+       
+
+       #define OTGetLinkObject(link, struc, field)     \
+               ((struc*)((char*)(link) - offsetof(struc, field)))
+
+#endif //!macintosh_build
+#endif /* __LINKEDLIST__ */
+
diff --git a/Source/MD5.CC b/Source/MD5.CC
new file mode 100644 (file)
index 0000000..7a18e9f
--- /dev/null
@@ -0,0 +1,544 @@
+// MD5.CC - source code for the C++/object oriented translation and 
+//          modification of MD5.
+
+// Translation and modification (c) 1995 by Mordechai T. Abzug 
+
+// This translation/ modification is provided "as is," without express or 
+// implied warranty of any kind.
+
+// The translator/ modifier does not claim (1) that MD5 will do what you think 
+// it does; (2) that this translation/ modification is accurate; or (3) that 
+// this software is "merchantible."  (Language for this disclaimer partially 
+// copied from the disclaimer below).
+
+/* based on:
+
+MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+MDDRIVER.C - test driver for MD2, MD4 and MD5
+
+
+Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+
+*/
+
+
+
+
+
+
+#include "md5.h"
+
+#include <assert.h>
+//#include <strings.h>
+#include <iostream>
+
+
+
+
+// MD5 simple initialization method
+
+MD5::MD5(){
+
+       init();
+
+}
+
+
+
+
+// MD5 block update operation. Continues an MD5 message-digest
+// operation, processing another message block, and updating the
+// context.
+
+void MD5::update (uint1 *input, uint4 input_length) {
+
+       uint4 input_index, buffer_index;
+       uint4 buffer_space;                // how much space is left in buffer
+
+       if (finalized){  // so we can't update!
+               cerr << "MD5::update:  Can't update a finalized digest!" << endl;
+               return;
+       }
+
+       // Compute number of bytes mod 64
+       buffer_index = (unsigned int)((count[0] >> 3) & 0x3F);
+
+       // Update number of bits
+       if (  (count[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) )
+               count[1]++;
+
+       count[1] += ((uint4)input_length >> 29);
+
+
+       buffer_space = 64 - buffer_index;  // how much space is left in buffer
+
+       // Transform as many times as possible.
+       if (input_length >= buffer_space) { // ie. we have enough to fill the buffer
+               // fill the rest of the buffer and transform
+               memcpy (buffer + buffer_index, input, buffer_space);
+               transform (buffer);
+
+               // now, transform each 64-byte piece of the input, bypassing the buffer
+               for (input_index = buffer_space; input_index + 63 < input_length; 
+                       input_index += 64)
+                       transform (input+input_index);
+
+               buffer_index = 0;  // so we can buffer remaining
+       }
+       else
+               input_index=0;     // so we can buffer the whole input
+
+
+       // and here we do the buffering:
+       memcpy(buffer+buffer_index, input+input_index, input_length-input_index);
+}
+
+
+
+// MD5 update for files.
+// Like above, except that it works on files (and uses above as a primitive.)
+
+void MD5::update(FILE *file){
+
+       unsigned char buffer[1024];
+       int len;
+
+       while (len=fread(buffer, 1, 1024, file))
+               update(buffer, len);
+
+       fclose (file);
+
+}
+
+
+
+
+
+
+// MD5 update for istreams.
+// Like update for files; see above.
+
+void MD5::update(istream& stream){
+
+       unsigned char buffer[1024];
+       int len;
+
+       while (stream.good()){
+               stream.read((char *)buffer, (long)1024); // note that return value of read is unusable.
+               len=stream.gcount();
+               update(buffer, len);
+       }
+
+}
+
+
+
+
+
+
+// MD5 update for ifstreams.
+// Like update for files; see above.
+
+void MD5::update(ifstream& stream){
+
+       unsigned char buffer[1024];
+       int len;
+
+       while (stream.good()){
+               stream.read((char *)buffer, (long)1024); // note that return value of read is unusable.
+               len=stream.gcount();
+               update(buffer, len);
+       }
+
+}
+
+
+
+
+
+
+// MD5 finalization. Ends an MD5 message-digest operation, writing the
+// the message digest and zeroizing the context.
+
+
+void MD5::finalize (){
+
+       unsigned char bits[8];
+       unsigned int index, padLen;
+       static uint1 PADDING[64]={
+               0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+       };
+
+       if (finalized){
+               cerr << "MD5::finalize:  Already finalized this digest!" << endl;
+               return;
+       }
+
+       // Save number of bits
+       encode (bits, count, 8);
+
+       // Pad out to 56 mod 64.
+       index = (uint4) ((count[0] >> 3) & 0x3f);
+       padLen = (index < 56) ? (56 - index) : (120 - index);
+       update (PADDING, padLen);
+
+       // Append length (before padding)
+       update (bits, 8);
+
+       // Store state in digest
+       encode (digest, state, 16);
+
+       // Zeroize sensitive information
+       memset (buffer, 0, sizeof(*buffer));
+
+       finalized=1;
+
+}
+
+
+
+
+MD5::MD5(FILE *file){
+
+       init();  // must be called be all constructors
+       update(file);
+       finalize ();
+}
+
+
+
+
+MD5::MD5(istream& stream){
+
+       init();  // must called by all constructors
+       update (stream);
+       finalize();
+}
+
+
+
+MD5::MD5(ifstream& stream){
+
+       init();  // must called by all constructors
+       update (stream);
+       finalize();
+}
+
+
+
+unsigned char *MD5::raw_digest(){
+
+       uint1 *s = new uint1[16];
+
+       if (!finalized){
+               cerr << "MD5::raw_digest:  Can't get digest if you haven't "<<
+                       "finalized the digest!" <<endl;
+               return ( (unsigned char*) "");
+       }
+
+       memcpy(s, digest, 16);
+       return s;
+}
+
+
+
+char *MD5::hex_digest(){
+
+       int i;
+       char *s= new char[33];
+
+       if (!finalized){
+               cerr << "MD5::hex_digest:  Can't get digest if you haven't "<<
+                       "finalized the digest!" <<endl;
+               return "";
+       }
+
+       for (i=0; i<16; i++)
+               sprintf(s+i*2, "%02x", digest[i]);
+
+       s[32]='\0';
+
+       return s;
+}
+
+
+
+
+
+ostream& operator<<(ostream &stream, MD5 context){
+
+       stream << context.hex_digest();
+       return stream;
+}
+
+
+
+
+// PRIVATE METHODS:
+
+
+
+void MD5::init(){
+       finalized=0;  // we just started!
+
+       // Nothing counted, so count=0
+       count[0] = 0;
+       count[1] = 0;
+
+       // Load magic initialization constants.
+       state[0] = 0x67452301;
+       state[1] = 0xefcdab89;
+       state[2] = 0x98badcfe;
+       state[3] = 0x10325476;
+}
+
+
+
+// Constants for MD5Transform routine.
+// Although we could use C++ style constants, defines are actually better,
+// since they let us easily evade scope clashes.
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+
+
+
+// MD5 basic transformation. Transforms state based on block.
+void MD5::transform (uint1 block[64]){
+
+       uint4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+       decode (x, block, 64);
+
+       assert(!finalized);  // not just a user error, since the method is private
+
+       /* Round 1 */
+       FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+       FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+       FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+       FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+       FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+       FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+       FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+       FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+       FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+       FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+       FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+       FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+       FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+       FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+       FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+       FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+       /* Round 2 */
+       GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+       GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+       GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+       GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+       GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+       GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+       GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+       GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+       GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+       GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+       GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+       GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+       GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+       GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+       GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+       GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+       /* Round 3 */
+       HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+       HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+       HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+       HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+       HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+       HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+       HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+       HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+       HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+       HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+       HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+       HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+       HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+       HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+       HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+       HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+       /* Round 4 */
+       II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+       II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+       II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+       II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+       II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+       II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+       II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+       II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+       II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+       II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+       II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+       II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+       II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+       II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+       II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+       II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+       state[0] += a;
+       state[1] += b;
+       state[2] += c;
+       state[3] += d;
+
+       // Zeroize sensitive information.
+       memset ( (uint1 *) x, 0, sizeof(x));
+
+}
+
+
+
+// Encodes input (UINT4) into output (unsigned char). Assumes len is
+// a multiple of 4.
+void MD5::encode (uint1 *output, uint4 *input, uint4 len) {
+
+       unsigned int i, j;
+
+       for (i = 0, j = 0; j < len; i++, j += 4) {
+               output[j]   = (uint1)  (input[i] & 0xff);
+               output[j+1] = (uint1) ((input[i] >> 8) & 0xff);
+               output[j+2] = (uint1) ((input[i] >> 16) & 0xff);
+               output[j+3] = (uint1) ((input[i] >> 24) & 0xff);
+       }
+}
+
+
+
+
+// Decodes input (unsigned char) into output (UINT4). Assumes len is
+// a multiple of 4.
+void MD5::decode (uint4 *output, uint1 *input, uint4 len){
+
+       unsigned int i, j;
+
+       for (i = 0, j = 0; j < len; i++, j += 4)
+               output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) |
+               (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24);
+}
+
+
+
+
+
+// Note: Replace "for loop" with standard memcpy if possible.
+void MD5::memcpy (uint1 *output, uint1 *input, uint4 len){
+
+       unsigned int i;
+
+       for (i = 0; i < len; i++)
+               output[i] = input[i];
+}
+
+
+
+// Note: Replace "for loop" with standard memset if possible.
+void MD5::memset (uint1 *output, uint1 value, uint4 len){
+
+       unsigned int i;
+
+       for (i = 0; i < len; i++)
+               output[i] = value;
+}
+
+
+
+// ROTATE_LEFT rotates x left n bits.
+
+inline unsigned int MD5::rotate_left  (uint4 x, uint4 n){
+       return (x << n) | (x >> (32-n))  ;
+}
+
+
+
+
+// F, G, H and I are basic MD5 functions.
+
+inline unsigned int MD5::F            (uint4 x, uint4 y, uint4 z){
+       return (x & y) | (~x & z);
+}
+
+inline unsigned int MD5::G            (uint4 x, uint4 y, uint4 z){
+       return (x & z) | (y & ~z);
+}
+
+inline unsigned int MD5::H            (uint4 x, uint4 y, uint4 z){
+       return x ^ y ^ z;
+}
+
+inline unsigned int MD5::I            (uint4 x, uint4 y, uint4 z){
+       return y ^ (x | ~z);
+}
+
+
+
+// FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+// Rotation is separate from addition to prevent recomputation.
+
+
+inline void MD5::FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
+                                       uint4  s, uint4 ac){
+                                               a += F(b, c, d) + x + ac;
+                                               a = rotate_left (a, s) +b;
+                                       }
+
+                                       inline void MD5::GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
+                                               uint4 s, uint4 ac){
+                                                       a += G(b, c, d) + x + ac;
+                                                       a = rotate_left (a, s) +b;
+                                               }
+
+                                               inline void MD5::HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
+                                                       uint4 s, uint4 ac){
+                                                               a += H(b, c, d) + x + ac;
+                                                               a = rotate_left (a, s) +b;
+                                                       }
+
+                                                       inline void MD5::II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
+                                                               uint4 s, uint4 ac){
+                                                                       a += I(b, c, d) + x + ac;
+                                                                       a = rotate_left (a, s) +b;
+                                                               }
diff --git a/Source/MacInput.cpp b/Source/MacInput.cpp
new file mode 100644 (file)
index 0000000..9b9f909
--- /dev/null
@@ -0,0 +1,803 @@
+/**> HEADER FILES <**/
+#include "MacInput.h"
+#include "String.h"
+
+extern bool keyboardfrozen;
+
+/********************> IsKeyDown() <*****/
+Boolean        IsKeyDown( unsigned char *keyMap, unsigned short theKey )
+{
+       if(keyboardfrozen)return 0;
+
+       static long     keyMapIndex;
+       static Boolean  isKeyDown;
+       static short    bitToCheck;
+       
+       // Calculate the key map index
+       keyMapIndex = keyMap[theKey/8];
+       
+       // Calculate the individual bit to check
+       bitToCheck = theKey%8;
+       
+       // Check the status of the key
+       isKeyDown = ( keyMapIndex >> bitToCheck ) & 0x01;
+       
+       // Return the status of the key
+       return isKeyDown;
+       
+}
+
+unsigned short         CharToKey(char* which)
+{
+       if(!strcmp(which,"a")){
+               return MAC_A_KEY;
+       }
+       if(!strcmp(which,"b")){
+               return MAC_B_KEY;
+       }
+       if(!strcmp(which,"c")){
+               return MAC_C_KEY;
+       }
+       if(!strcmp(which,"d")){
+               return MAC_D_KEY;
+       }
+       if(!strcmp(which,"e")){
+               return MAC_E_KEY;
+       }
+       if(!strcmp(which,"f")){
+               return MAC_F_KEY;
+       }
+       if(!strcmp(which,"g")){
+               return MAC_G_KEY;
+       }
+       if(!strcmp(which,"h")){
+               return MAC_H_KEY;
+       }
+       if(!strcmp(which,"i")){
+               return MAC_I_KEY;
+       }
+       if(!strcmp(which,"j")){
+               return MAC_J_KEY;
+       }
+       if(!strcmp(which,"k")){
+               return MAC_K_KEY;
+       }
+       if(!strcmp(which,"l")){
+               return MAC_L_KEY;
+       }
+       if(!strcmp(which,"m")){
+               return MAC_M_KEY;
+       }
+       if(!strcmp(which,"n")){
+               return MAC_N_KEY;
+       }
+       if(!strcmp(which,"o")){
+               return MAC_O_KEY;
+       }
+       if(!strcmp(which,"p")){
+               return MAC_P_KEY;
+       }
+       if(!strcmp(which,"q")){
+               return MAC_Q_KEY;
+       }
+       if(!strcmp(which,"r")){
+               return MAC_R_KEY;
+       }
+       if(!strcmp(which,"s")){
+               return MAC_S_KEY;
+       }
+       if(!strcmp(which,"t")){
+               return MAC_T_KEY;
+       }
+       if(!strcmp(which,"u")){
+               return MAC_U_KEY;
+       }
+       if(!strcmp(which,"v")){
+               return MAC_V_KEY;
+       }
+       if(!strcmp(which,"w")){
+               return MAC_W_KEY;
+       }
+       if(!strcmp(which,"x")){
+               return MAC_X_KEY;
+       }
+       if(!strcmp(which,"y")){
+               return MAC_Y_KEY;
+       }
+       if(!strcmp(which,"z")){
+               return MAC_Z_KEY;
+       }
+       if(!strcmp(which,"0")){
+               return MAC_NUMPAD_0_KEY;
+       }
+       if(!strcmp(which,"1")){
+               return MAC_NUMPAD_1_KEY;
+       }
+       if(!strcmp(which,"2")){
+               return MAC_NUMPAD_2_KEY;
+       }
+       if(!strcmp(which,"3")){
+               return MAC_NUMPAD_3_KEY;
+       }
+       if(!strcmp(which,"4")){
+               return MAC_NUMPAD_4_KEY;
+       }
+       if(!strcmp(which,"5")){
+               return MAC_NUMPAD_5_KEY;
+       }
+       if(!strcmp(which,"6")){
+               return MAC_NUMPAD_6_KEY;
+       }
+       if(!strcmp(which,"7")){
+               return MAC_NUMPAD_7_KEY;
+       }
+       if(!strcmp(which,"8")){
+               return MAC_NUMPAD_8_KEY;
+       }
+       if(!strcmp(which,"9")){
+               return MAC_NUMPAD_9_KEY;
+       }
+       if(!strcmp(which,"enter")){
+               return MAC_ENTER_KEY;
+       }
+       if(!strcmp(which,"control")){
+               return MAC_CONTROL_KEY;
+       }
+       if(!strcmp(which,"return")){
+               return MAC_RETURN_KEY;
+       }
+       if(!strcmp(which,"space")){
+               return MAC_SPACE_KEY;
+       }
+       if(!strcmp(which,"shift")){
+               return MAC_SHIFT_KEY;
+       }
+       if(!strcmp(which,"uparrow")){
+               return MAC_ARROW_UP_KEY;
+       }
+       if(!strcmp(which,"downarrow")){
+               return MAC_ARROW_DOWN_KEY;
+       }
+       if(!strcmp(which,"leftarrow")){
+               return MAC_ARROW_LEFT_KEY;
+       }
+       if(!strcmp(which,"rightarrow")){
+               return MAC_ARROW_RIGHT_KEY;
+       }
+}
+
+char*  KeyToChar(unsigned short which)
+{
+       static int i;
+       
+       if(which==MAC_A_KEY){
+               return "a";
+       }
+       if(which==MAC_B_KEY){
+               return "b";
+       }
+       if(which==MAC_C_KEY){
+               return "c";
+       }
+       if(which==MAC_D_KEY){
+               return "d";
+       }
+       if(which==MAC_E_KEY){
+               return "e";
+       }
+       if(which==MAC_F_KEY){
+               return "f";
+       }
+       if(which==MAC_G_KEY){
+               return "g";
+       }
+       if(which==MAC_H_KEY){
+               return "h";
+       }
+       if(which==MAC_I_KEY){
+               return "i";
+       }
+       if(which==MAC_J_KEY){
+               return "j";
+       }
+       if(which==MAC_K_KEY){
+               return "k";
+       }
+       if(which==MAC_L_KEY){
+               return "l";
+       }
+       if(which==MAC_M_KEY){
+               return "m";
+       }
+       if(which==MAC_N_KEY){
+               return "n";
+       }
+       if(which==MAC_O_KEY){
+               return "o";
+       }
+       if(which==MAC_P_KEY){
+               return "p";
+       }
+       if(which==MAC_Q_KEY){
+               return "q";
+       }
+       if(which==MAC_R_KEY){
+               return "r";
+       }
+       if(which==MAC_S_KEY){
+               return "s";
+       }
+       if(which==MAC_T_KEY){
+               return "t";
+       }
+       if(which==MAC_U_KEY){
+               return "u";
+       }
+       if(which==MAC_V_KEY){
+               return "v";
+       }
+       if(which==MAC_W_KEY){
+               return "w";
+       }
+       if(which==MAC_X_KEY){
+               return "x";
+       }
+       if(which==MAC_Y_KEY){
+               return "y";
+       }
+       if(which==MAC_Z_KEY){
+               return "z";
+       }
+       if(which==MAC_NUMPAD_1_KEY){
+               return "1";
+       }
+       if(which==MAC_NUMPAD_2_KEY){
+               return "2";
+       }
+       if(which==MAC_NUMPAD_3_KEY){
+               return "3";
+       }
+       if(which==MAC_NUMPAD_4_KEY){
+               return "4";
+       }
+       if(which==MAC_NUMPAD_5_KEY){
+               return "5";
+       }
+       if(which==MAC_NUMPAD_6_KEY){
+               return "6";
+       }
+       if(which==MAC_NUMPAD_7_KEY){
+               return "7";
+       }
+       if(which==MAC_NUMPAD_8_KEY){
+               return "8";
+       }
+       if(which==MAC_NUMPAD_9_KEY){
+               return "9";
+       }
+       if(which==MAC_ENTER_KEY){
+               return "enter";
+       }
+       if(which==MAC_NUMPAD_0_KEY){
+               return "0";
+       }
+       if(which==MAC_1_KEY){
+               return "1";
+       }
+       if(which==MAC_2_KEY){
+               return "2";
+       }
+       if(which==MAC_3_KEY){
+               return "3";
+       }
+       if(which==MAC_4_KEY){
+               return "4";
+       }
+       if(which==MAC_5_KEY){
+               return "5";
+       }
+       if(which==MAC_6_KEY){
+               return "6";
+       }
+       if(which==MAC_7_KEY){
+               return "7";
+       }
+       if(which==MAC_8_KEY){
+               return "8";
+       }
+       if(which==MAC_9_KEY){
+               return "9";
+       }
+       if(which==MAC_0_KEY){
+               return "0";
+       }
+       if(which==MAC_F1_KEY){
+               return "F1";
+       }
+       if(which==MAC_F2_KEY){
+               return "F2";
+       }
+       if(which==MAC_F3_KEY){
+               return "F3";
+       }
+       if(which==MAC_F4_KEY){
+               return "F4";
+       }
+       if(which==MAC_F5_KEY){
+               return "F5";
+       }
+       if(which==MAC_F6_KEY){
+               return "F6";
+       }
+       if(which==MAC_F7_KEY){
+               return "F7";
+       }
+       if(which==MAC_F8_KEY){
+               return "F8";
+       }
+       if(which==MAC_F9_KEY){
+               return "F9";
+       }
+       if(which==MAC_F10_KEY){
+               return "F10";
+       }
+       if(which==MAC_F11_KEY){
+               return "F11";
+       }
+       if(which==MAC_F12_KEY){
+               return "F12";
+       }
+       if(which==MAC_ESCAPE_KEY){
+               return "escape";
+       }
+       if(which==MAC_DELETE_KEY){
+               return "backspace";
+       }
+       if(which==MAC_TAB_KEY){
+               return "tab";
+       }
+       if(which==MAC_TILDE_KEY){
+               return "`";
+       }
+       if(which==MAC_CAPS_LOCK_KEY){
+               return "caps lock";
+       }
+       if(which==MAC_COMMAND_KEY){
+               return "command";
+       }
+       if(which==MAC_OPTION_KEY){
+               return "option";
+       }
+       if(which==MAC_DEL_KEY){
+               return "delete";
+       }
+       if(which==MAC_INSERT_KEY){
+               return "insert";
+       }
+       if(which==MAC_HOME_KEY){
+               return "home";
+       }
+       if(which==MAC_END_KEY){
+               return "end";
+       }
+       if(which==MAC_PAGE_UP_KEY){
+               return "page up";
+       }
+       if(which==MAC_PAGE_DOWN_KEY){
+               return "page down";
+       }
+       if(which==MAC_NUMPAD_CLEAR_KEY){
+               return "clear";
+       }
+       if(which==MAC_CONTROL_KEY){
+               return "control";
+       }
+       if(which==MAC_SPACE_KEY){
+               return "space";
+       }
+       if(which==MAC_RETURN_KEY){
+               return "return";
+       }
+       if(which==MAC_SHIFT_KEY){
+               return "shift";
+       }
+       if(which==MAC_ARROW_UP_KEY){
+               return "uparrow";
+       }
+       if(which==MAC_ARROW_DOWN_KEY){
+               return "downarrow";
+       }
+       if(which==MAC_ARROW_LEFT_KEY){
+               return "leftarrow";
+       }
+       if(which==MAC_ARROW_RIGHT_KEY){
+               return "rightarrow";
+       }
+       if(which==MAC_MINUS_KEY||which==MAC_NUMPAD_MINUS_KEY){
+               return "-";
+       }
+       if(which==MAC_PLUS_KEY||which==MAC_NUMPAD_EQUALS_KEY){
+               return "=";
+       }
+       if(which==MAC_NUMPAD_PLUS_KEY){
+               return "+";
+       }
+       if(which==MAC_NUMPAD_ASTERISK_KEY){
+               return "*";
+       }
+       if(which==MAC_SLASH_KEY||which==MAC_NUMPAD_SLASH_KEY){
+               return "/";
+       }
+       if(which==MAC_BACKSLASH_KEY){
+               return "\\";
+       }
+       if(which==MAC_LEFTBRACKET_KEY){
+               return "[";
+       }
+       if(which==MAC_RIGHTBRACKET_KEY){
+               return "]";
+       }
+       if(which==MAC_PERIOD_KEY||which==MAC_NUMPAD_PERIOD_KEY){
+               return ".";
+       }
+       if(which==MAC_COMMA_KEY){
+               return ",";
+       }
+       if(which==MAC_APOSTROPHE_KEY){
+               return "\"";
+       }
+       if(which==MAC_SEMICOLON_KEY){
+               return ";";
+       }
+       return "unknown";
+}
+
+char   KeyToSingleChar(unsigned short which)
+{
+       static int i;
+       
+       if(which==MAC_A_KEY){
+               return 'a';
+       }
+       if(which==MAC_B_KEY){
+               return 'b';
+       }
+       if(which==MAC_C_KEY){
+               return 'c';
+       }
+       if(which==MAC_D_KEY){
+               return 'd';
+       }
+       if(which==MAC_E_KEY){
+               return 'e';
+       }
+       if(which==MAC_F_KEY){
+               return 'f';
+       }
+       if(which==MAC_G_KEY){
+               return 'g';
+       }
+       if(which==MAC_H_KEY){
+               return 'h';
+       }
+       if(which==MAC_I_KEY){
+               return 'i';
+       }
+       if(which==MAC_J_KEY){
+               return 'j';
+       }
+       if(which==MAC_K_KEY){
+               return 'k';
+       }
+       if(which==MAC_L_KEY){
+               return 'l';
+       }
+       if(which==MAC_M_KEY){
+               return 'm';
+       }
+       if(which==MAC_N_KEY){
+               return 'n';
+       }
+       if(which==MAC_O_KEY){
+               return 'o';
+       }
+       if(which==MAC_P_KEY){
+               return 'p';
+       }
+       if(which==MAC_Q_KEY){
+               return 'q';
+       }
+       if(which==MAC_R_KEY){
+               return 'r';
+       }
+       if(which==MAC_S_KEY){
+               return 's';
+       }
+       if(which==MAC_T_KEY){
+               return 't';
+       }
+       if(which==MAC_U_KEY){
+               return 'u';
+       }
+       if(which==MAC_V_KEY){
+               return 'v';
+       }
+       if(which==MAC_W_KEY){
+               return 'w';
+       }
+       if(which==MAC_X_KEY){
+               return 'x';
+       }
+       if(which==MAC_Y_KEY){
+               return 'y';
+       }
+       if(which==MAC_Z_KEY){
+               return 'z';
+       }
+       if(which==MAC_NUMPAD_1_KEY){
+               return '1';
+       }
+       if(which==MAC_NUMPAD_2_KEY){
+               return '2';
+       }
+       if(which==MAC_NUMPAD_3_KEY){
+               return '3';
+       }
+       if(which==MAC_NUMPAD_4_KEY){
+               return '4';
+       }
+       if(which==MAC_NUMPAD_5_KEY){
+               return '5';
+       }
+       if(which==MAC_NUMPAD_6_KEY){
+               return '6';
+       }
+       if(which==MAC_NUMPAD_7_KEY){
+               return '7';
+       }
+       if(which==MAC_NUMPAD_8_KEY){
+               return '8';
+       }
+       if(which==MAC_NUMPAD_9_KEY){
+               return '9';
+       }
+       if(which==MAC_NUMPAD_0_KEY){
+               return '0';
+       }
+       if(which==MAC_1_KEY){
+               return '1';
+       }
+       if(which==MAC_2_KEY){
+               return '2';
+       }
+       if(which==MAC_3_KEY){
+               return '3';
+       }
+       if(which==MAC_4_KEY){
+               return '4';
+       }
+       if(which==MAC_5_KEY){
+               return '5';
+       }
+       if(which==MAC_6_KEY){
+               return '6';
+       }
+       if(which==MAC_7_KEY){
+               return '7';
+       }
+       if(which==MAC_8_KEY){
+               return '8';
+       }
+       if(which==MAC_9_KEY){
+               return '9';
+       }
+       if(which==MAC_0_KEY){
+               return '0';
+       }
+       if(which==MAC_SPACE_KEY){
+               return ' ';
+       }
+       if(which==MAC_MINUS_KEY||which==MAC_NUMPAD_MINUS_KEY){
+               return '-';
+       }
+       if(which==MAC_PLUS_KEY||which==MAC_NUMPAD_EQUALS_KEY){
+               return '=';
+       }
+       if(which==MAC_NUMPAD_PLUS_KEY){
+               return '+';
+       }
+       if(which==MAC_NUMPAD_ASTERISK_KEY){
+               return '*';
+       }
+       if(which==MAC_SLASH_KEY||which==MAC_NUMPAD_SLASH_KEY){
+               return '/';
+       }
+       if(which==MAC_BACKSLASH_KEY){
+               return '\\';
+       }
+       if(which==MAC_LEFTBRACKET_KEY){
+               return '[';
+       }
+       if(which==MAC_RIGHTBRACKET_KEY){
+               return ']';
+       }
+       if(which==MAC_PERIOD_KEY||which==MAC_NUMPAD_PERIOD_KEY){
+               return '.';
+       }
+       if(which==MAC_COMMA_KEY){
+               return ',';
+       }
+       if(which==MAC_APOSTROPHE_KEY){
+               return '\'';
+       }
+       if(which==MAC_SEMICOLON_KEY){
+               return ';';
+       }
+       return '\0';
+}
+
+char   Shift(char which)
+{
+       static int i;
+       
+       if(which=='a'){
+               return 'A';
+       }
+       if(which=='b'){
+               return 'B';
+       }
+       if(which=='c'){
+               return 'C';
+       }
+       if(which=='d'){
+               return 'D';
+       }
+       if(which=='e'){
+               return 'E';
+       }
+       if(which=='f'){
+               return 'F';
+       }
+       if(which=='g'){
+               return 'G';
+       }
+       if(which=='h'){
+               return 'H';
+       }
+       if(which=='e'){
+               return 'E';
+       }
+       if(which=='f'){
+               return 'F';
+       }
+       if(which=='g'){
+               return 'G';
+       }
+       if(which=='h'){
+               return 'H';
+       }
+       if(which=='i'){
+               return 'I';
+       }
+       if(which=='j'){
+               return 'J';
+       }
+       if(which=='k'){
+               return 'K';
+       }
+       if(which=='l'){
+               return 'L';
+       }
+       if(which=='m'){
+               return 'M';
+       }
+       if(which=='n'){
+               return 'N';
+       }
+       if(which=='o'){
+               return 'O';
+       }
+       if(which=='p'){
+               return 'P';
+       }
+       if(which=='q'){
+               return 'Q';
+       }
+       if(which=='r'){
+               return 'R';
+       }
+       if(which=='s'){
+               return 'S';
+       }
+       if(which=='t'){
+               return 'T';
+       }
+       if(which=='u'){
+               return 'U';
+       }
+       if(which=='v'){
+               return 'V';
+       }
+       if(which=='w'){
+               return 'W';
+       }
+       if(which=='x'){
+               return 'X';
+       }
+       if(which=='y'){
+               return 'Y';
+       }
+       if(which=='z'){
+               return 'Z';
+       }
+       if(which=='1'){
+               return '!';
+       }
+       if(which=='2'){
+               return '@';
+       }
+       if(which=='3'){
+               return '#';
+       }
+       if(which=='4'){
+               return '$';
+       }
+       if(which=='5'){
+               return '%';
+       }
+       if(which=='6'){
+               return '^';
+       }
+       if(which=='7'){
+               return '&';
+       }
+       if(which=='8'){
+               return '*';
+       }
+       if(which=='9'){
+               return '(';
+       }
+       if(which=='0'){
+               return ')';
+       }
+       if(which=='-'){
+               return '_';
+       }
+       if(which=='='){
+               return '+';
+       }
+       if(which=='['){
+               return '{';
+       }
+       if(which==']'){
+               return '}';
+       }
+       if(which=='\\'){
+               return '|';
+       }
+       if(which=='.'){
+               return '>';
+       }
+       if(which==','){
+               return '<';
+       }
+       if(which=='/'){
+               return '?';
+       }
+       if(which==';'){
+               return ':';
+       }
+       if(which=='\''){
+               return '\"';
+       }
+       return which;
+}
+
+bool   Compare(char *thestring, char *tocompare, int start, int end)
+{
+       static int i;
+       for(i=start;i<=end;i++){
+               if(thestring[i]!=tocompare[i-start]&&thestring[i]!=tocompare[i-start]+'A'-'a')return 0;
+       }
+       return 1;
+}
\ No newline at end of file
diff --git a/Source/MacInput.h b/Source/MacInput.h
new file mode 100644 (file)
index 0000000..64db734
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef _MACINPUT_H_
+#define _MACINPUT_H_
+
+/**> HEADER FILES <**/
+#include <stdlib.h>
+#include <stdio.h>
+#include <CursorDevices.h> //Mouse
+
+/**> CONSTANT DECLARATIONS <**/
+// Mac Keyboard Codes
+#define        MAC_1_KEY                               0x12
+#define        MAC_2_KEY                               0x13
+#define        MAC_3_KEY                               0x14
+#define        MAC_4_KEY                               0x15
+#define        MAC_5_KEY                               0x17
+#define        MAC_6_KEY                               0x16
+#define        MAC_7_KEY                               0x1A
+#define        MAC_8_KEY                               0x1C
+#define        MAC_9_KEY                               0x19
+#define        MAC_0_KEY                               0x1D
+#define        MAC_NUMPAD_1_KEY                0x53
+#define        MAC_NUMPAD_2_KEY                0x54
+#define        MAC_NUMPAD_3_KEY                0x55
+#define        MAC_NUMPAD_4_KEY                0x56
+#define        MAC_NUMPAD_5_KEY                0x57
+#define        MAC_NUMPAD_6_KEY                0x58
+#define        MAC_NUMPAD_7_KEY                0x59
+#define        MAC_NUMPAD_8_KEY                0x5B
+#define        MAC_NUMPAD_9_KEY                0x5C
+#define        MAC_NUMPAD_0_KEY                0x52
+#define        MAC_A_KEY                               0x00
+#define        MAC_B_KEY                               0x0B
+#define        MAC_C_KEY                               0x08
+#define        MAC_D_KEY                               0x02
+#define        MAC_E_KEY                               0x0E
+#define        MAC_F_KEY                               0x03
+#define        MAC_G_KEY                               0x05
+#define        MAC_H_KEY                               0x04
+#define        MAC_I_KEY                               0x22
+#define        MAC_J_KEY                               0x26
+#define        MAC_K_KEY                               0x28
+#define        MAC_L_KEY                               0x25
+#define        MAC_M_KEY                               0x2E
+#define        MAC_N_KEY                               0x2D
+#define        MAC_O_KEY                               0x1F
+#define        MAC_P_KEY                               0x23
+#define        MAC_Q_KEY                               0x0C
+#define        MAC_R_KEY                               0x0F
+#define        MAC_S_KEY                               0x01
+#define        MAC_T_KEY                               0x11
+#define        MAC_U_KEY                               0x20
+#define        MAC_V_KEY                               0x09
+#define        MAC_W_KEY                               0x0D
+#define        MAC_X_KEY                               0x07
+#define        MAC_Y_KEY                               0x10
+#define        MAC_Z_KEY                               0x06
+#define        MAC_F1_KEY                              0x7A
+#define        MAC_F2_KEY                              0x78
+#define        MAC_F3_KEY                              0x63
+#define        MAC_F4_KEY                              0x76
+#define        MAC_F5_KEY                              0x60
+#define        MAC_F6_KEY                              0x61
+#define        MAC_F7_KEY                              0x62
+#define        MAC_F8_KEY                              0x64
+#define        MAC_F9_KEY                              0x65
+#define        MAC_F10_KEY                             0x6D
+#define        MAC_F11_KEY                             0x67
+#define        MAC_F12_KEY                             0x6F
+#define        MAC_RETURN_KEY                  0x24
+#define        MAC_ENTER_KEY                   0x4C
+#define        MAC_TAB_KEY                             0x30
+#define        MAC_SPACE_KEY                   0x31
+#define        MAC_DELETE_KEY                  0x33
+#define        MAC_ESCAPE_KEY                  0x35
+#define        MAC_COMMAND_KEY                 0x37
+#define        MAC_SHIFT_KEY                   0x38
+#define        MAC_CAPS_LOCK_KEY               0x39
+#define        MAC_OPTION_KEY                  0x3A
+#define        MAC_CONTROL_KEY                 0x3B
+#define        MAC_PAGE_UP_KEY                 0x74
+#define        MAC_PAGE_DOWN_KEY               0x79
+#define        MAC_INSERT_KEY                  0x72
+#define        MAC_DEL_KEY                             0x75
+#define        MAC_HOME_KEY                    0x73
+#define        MAC_END_KEY                             0x77
+#define        MAC_LEFT_BRACKET_KEY    0x21
+#define        MAC_RIGHT_BRACKET_KEY   0x1E
+#define        MAC_ARROW_UP_KEY                0x7E
+#define        MAC_ARROW_DOWN_KEY              0x7D
+#define        MAC_ARROW_LEFT_KEY              0x7B
+#define        MAC_ARROW_RIGHT_KEY             0x7C
+#define        MAC_TILDE_KEY                   0x32
+#define MAC_MINUS_KEY                  0x1B
+#define MAC_PLUS_KEY                   0x18
+#define MAC_SLASH_KEY                  0x2C
+#define MAC_PERIOD_KEY                 0x2F
+#define MAC_COMMA_KEY                  0x2B
+#define MAC_BACKSLASH_KEY              0x2A
+#define MAC_LEFTBRACKET_KEY            0x21
+#define MAC_RIGHTBRACKET_KEY   0x1E
+#define MAC_NUMPAD_CLEAR_KEY   0x47#define MAC_NUMPAD_MINUS_KEY        0x4E
+#define MAC_NUMPAD_EQUALS_KEY  0x51
+#define MAC_NUMPAD_PLUS_KEY            0x45
+#define MAC_NUMPAD_SLASH_KEY   0x4B
+#define MAC_NUMPAD_ASTERISK_KEY        0x43
+#define MAC_NUMPAD_ENTER_KEY   0x4C
+#define MAC_NUMPAD_PERIOD_KEY  0x41
+#define MAC_SEMICOLON_KEY              0x29
+#define MAC_APOSTROPHE_KEY             0x27
+
+/**> FUNCTION PROTOTYPES <**/
+Boolean        IsKeyDown( unsigned char *keyMap, unsigned short theKey );
+void   InitMouse();
+void   MoveMouse(int xcoord, int ycoord, Point *mouseloc);
+void   RefreshMouse(Point *mouseloc);
+void   DisposeMouse();
+unsigned short         CharToKey(char* which);
+char*  KeyToChar(unsigned short which);
+char   KeyToSingleChar(unsigned short which);
+char   Shift(char which);
+bool   Compare(char *thestring, char *tocompare, int start, int end);
+
+#endif
\ No newline at end of file
diff --git a/Source/Models.cpp b/Source/Models.cpp
new file mode 100644 (file)
index 0000000..b1be7f5
--- /dev/null
@@ -0,0 +1,1529 @@
+#include "Models.h"
+//#include "altivec.h"
+#include "Game.h"
+
+extern float multiplier;
+extern float viewdistance;
+extern XYZ viewer;
+extern float fadestart;
+extern float texdetail;
+extern bool decals;
+extern int loadscreencolor;
+
+#include "Game.h"
+extern Game * pgame;
+extern bool visibleloading;
+//Functions
+void *allocate_aligned(size_t pointer_size, size_t byte_alignment)
+{
+       uintptr_t pointer = (uintptr_t)malloc(pointer_size + byte_alignment + 1);
+       uintptr_t aligned_pointer = (pointer + byte_alignment + 1);
+       aligned_pointer -= (aligned_pointer % byte_alignment);
+       *(uint8_t *)(aligned_pointer - 1) = (aligned_pointer - pointer);
+       return (void *)aligned_pointer;
+}
+
+void free_aligned(void *aligned_pointer)
+{
+       free((uint8_t *)(aligned_pointer) - *((uint8_t *)(aligned_pointer) - 1));
+}
+
+void dealloc(void* param){
+       free(param);
+       param=0;
+}
+
+int Model::LineCheck(XYZ *p1,XYZ *p2, XYZ *p, XYZ *move, float *rotate)
+{
+       static int j;
+       static float distance;
+       static float olddistance;
+       static int intersecting;
+       static int firstintersecting;
+       static XYZ point;
+
+       *p1=*p1-*move;
+       *p2=*p2-*move;
+       if(*rotate)*p1=DoRotation(*p1,0,-*rotate,0);
+       if(*rotate)*p2=DoRotation(*p2,0,-*rotate,0);
+       if(!sphere_line_intersection(p1,p2,&boundingspherecenter,
+               &boundingsphereradius))return -1;
+       firstintersecting=-1;
+
+       for (j=0;j<TriangleNum;j++){
+               intersecting=LineFacetd(p1,p2,&vertex[Triangles[j].vertex[0]],&vertex[Triangles[j].vertex[1]],&vertex[Triangles[j].vertex[2]],&facenormals[j],&point);
+               distance=(point.x-p1->x)*(point.x-p1->x)+(point.y-p1->y)*(point.y-p1->y)+(point.z-p1->z)*(point.z-p1->z);
+               if((distance<olddistance||firstintersecting==-1)&&intersecting){olddistance=distance; firstintersecting=j; *p=point;}
+       }
+
+       if(*rotate)*p=DoRotation(*p,0,*rotate,0);
+       *p=*p+*move;
+       return firstintersecting;
+}
+
+int Model::LineCheckSlide(XYZ *p1,XYZ *p2, XYZ *p, XYZ *move, float *rotate)
+{
+       static int j;
+       static float distance;
+       static float olddistance;
+       static int intersecting;
+       static int firstintersecting;
+       static XYZ point;
+
+       *p1=*p1-*move;
+       *p2=*p2-*move;
+       if(!sphere_line_intersection(p1,p2,&boundingspherecenter,
+               &boundingsphereradius))return -1;
+       firstintersecting=-1;
+       if(*rotate)*p1=DoRotation(*p1,0,-*rotate,0);
+       if(*rotate)*p2=DoRotation(*p2,0,-*rotate,0);
+
+       for (j=0;j<TriangleNum;j++){
+               intersecting=LineFacetd(p1,p2,&vertex[Triangles[j].vertex[0]],&vertex[Triangles[j].vertex[1]],&vertex[Triangles[j].vertex[2]],&facenormals[j],&point);
+               distance=(point.x-p1->x)*(point.x-p1->x)+(point.y-p1->y)*(point.y-p1->y)+(point.z-p1->z)*(point.z-p1->z);
+               if((distance<olddistance||firstintersecting==-1)&&intersecting){olddistance=distance; firstintersecting=j;}
+       }
+
+       distance=abs((facenormals[firstintersecting].x*p2->x)+(facenormals[firstintersecting].y*p2->y)+(facenormals[firstintersecting].z*p2->z)-((facenormals[firstintersecting].x*vertex[Triangles[firstintersecting].vertex[0]].x)+(facenormals[firstintersecting].y*vertex[Triangles[firstintersecting].vertex[0]].y)+(facenormals[firstintersecting].z*vertex[Triangles[firstintersecting].vertex[0]].z)));
+       *p2-=facenormals[firstintersecting]*distance;
+
+       if(*rotate)*p2=DoRotation(*p2,0,*rotate,0);
+       *p2=*p2+*move;
+       return firstintersecting;
+}
+
+int Model::LineCheckPossible(XYZ *p1,XYZ *p2, XYZ *p, XYZ *move, float *rotate)
+{
+       static int j;
+       static float distance;
+       static float olddistance;
+       static int intersecting;
+       static int firstintersecting;
+       static XYZ point;
+
+       *p1=*p1-*move;
+       *p2=*p2-*move;
+       if(!sphere_line_intersection(p1,p2,&boundingspherecenter,
+               &boundingsphereradius))return -1;
+       firstintersecting=-1;
+       if(*rotate)*p1=DoRotation(*p1,0,-*rotate,0);
+       if(*rotate)*p2=DoRotation(*p2,0,-*rotate,0);
+
+       if(numpossible>0&&numpossible<TriangleNum)
+               for (j=0;j<numpossible;j++){
+                       if(possible[j]>=0&&possible[j]<TriangleNum){
+                               intersecting=LineFacetd(p1,p2,&vertex[Triangles[possible[j]].vertex[0]],&vertex[Triangles[possible[j]].vertex[1]],&vertex[Triangles[possible[j]].vertex[2]],&facenormals[possible[j]],&point);
+                               distance=(point.x-p1->x)*(point.x-p1->x)+(point.y-p1->y)*(point.y-p1->y)+(point.z-p1->z)*(point.z-p1->z);
+                               if((distance<olddistance||firstintersecting==-1)&&intersecting){olddistance=distance; firstintersecting=possible[j]; *p=point;}
+                       }
+               }
+
+               if(*rotate)*p=DoRotation(*p,0,*rotate,0);
+               *p=*p+*move;
+               return firstintersecting;
+}
+
+int Model::LineCheckSlidePossible(XYZ *p1,XYZ *p2, XYZ *p, XYZ *move, float *rotate)
+{
+       static int j;
+       static float distance;
+       static float olddistance;
+       static int intersecting;
+       static int firstintersecting;
+       static XYZ point;
+
+       *p1=*p1-*move;
+       *p2=*p2-*move;
+       if(!sphere_line_intersection(p1,p2,&boundingspherecenter,
+               &boundingsphereradius))return -1;
+       firstintersecting=-1;
+       if(*rotate)*p1=DoRotation(*p1,0,-*rotate,0);
+       if(*rotate)*p2=DoRotation(*p2,0,-*rotate,0);
+
+       if(numpossible)
+               for (j=0;j<numpossible;j++){
+                       if(possible[j]>=0&&possible[j]<TriangleNum){
+                               intersecting=LineFacetd(p1,p2,&vertex[Triangles[possible[j]].vertex[0]],&vertex[Triangles[possible[j]].vertex[1]],&vertex[Triangles[possible[j]].vertex[2]],&facenormals[possible[j]],&point);
+                               distance=(point.x-p1->x)*(point.x-p1->x)+(point.y-p1->y)*(point.y-p1->y)+(point.z-p1->z)*(point.z-p1->z);
+                               if((distance<olddistance||firstintersecting==-1)&&intersecting){olddistance=distance; firstintersecting=possible[j];}
+                       }
+               }
+
+               if(firstintersecting>0){
+                       distance=abs((facenormals[firstintersecting].x*p2->x)+(facenormals[firstintersecting].y*p2->y)+(facenormals[firstintersecting].z*p2->z)-((facenormals[firstintersecting].x*vertex[Triangles[firstintersecting].vertex[0]].x)+(facenormals[firstintersecting].y*vertex[Triangles[firstintersecting].vertex[0]].y)+(facenormals[firstintersecting].z*vertex[Triangles[firstintersecting].vertex[0]].z)));
+                       *p2-=facenormals[firstintersecting]*distance;
+               }
+
+               if(*rotate)*p2=DoRotation(*p2,0,*rotate,0);
+               *p2=*p2+*move;
+               return firstintersecting;
+}
+
+int Model::SphereCheck(XYZ *p1,float radius, XYZ *p, XYZ *move, float *rotate)
+{
+       static int i,j;
+       static float distance;
+       static float olddistance;
+       static int intersecting;
+       static int firstintersecting;
+       static XYZ point;
+       static XYZ oldp1;
+       static XYZ start,end;
+
+       firstintersecting=-1;
+
+       oldp1=*p1;
+       *p1=*p1-*move;
+       if(*rotate)*p1=DoRotation(*p1,0,-*rotate,0);
+       if(findDistancefast(p1,&boundingspherecenter)>radius*radius+boundingsphereradius*boundingsphereradius)return -1;
+
+       for(i=0;i<4;i++){
+               for (j=0;j<TriangleNum;j++){
+                       intersecting=0;
+                       distance=abs((facenormals[j].x*p1->x)+(facenormals[j].y*p1->y)+(facenormals[j].z*p1->z)-((facenormals[j].x*vertex[Triangles[j].vertex[0]].x)+(facenormals[j].y*vertex[Triangles[j].vertex[0]].y)+(facenormals[j].z*vertex[Triangles[j].vertex[0]].z)));
+                       if(distance<radius){
+                               point=*p1-facenormals[j]*distance;
+                               if(PointInTriangle( &point, facenormals[j], &vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]]))intersecting=1;
+                               if(!intersecting)intersecting=sphere_line_intersection(&vertex[Triangles[j].vertex[0]],
+                                       &vertex[Triangles[j].vertex[1]],
+                                       p1, &radius);
+                               if(!intersecting)intersecting=sphere_line_intersection(&vertex[Triangles[j].vertex[1]],
+                                       &vertex[Triangles[j].vertex[2]],
+                                       p1, &radius);
+                               if(!intersecting)intersecting=sphere_line_intersection(&vertex[Triangles[j].vertex[0]],
+                                       &vertex[Triangles[j].vertex[2]],
+                                       p1, &radius);
+                               if(intersecting){
+                                       *p1+=facenormals[j]*(distance-radius);
+                                       /*start=*p1;
+                                       end=*p1;
+                                       end.y-=radius;
+                                       if(LineFacetd(&start,&end,&vertex[Triangles[j].vertex[0]],&vertex[Triangles[j].vertex[1]],&vertex[Triangles[j].vertex[2]],&facenormals[j],&point)){
+                                       p1->y=point.y+radius;
+                                       }*/
+                               }
+                       }
+                       if((distance<olddistance||firstintersecting==-1)&&intersecting){olddistance=distance; firstintersecting=j; *p=point;}
+               }
+       }
+       if(*rotate)*p=DoRotation(*p,0,*rotate,0);
+       *p=*p+*move;
+       if(*rotate)*p1=DoRotation(*p1,0,*rotate,0);
+       *p1+=*move;
+       return firstintersecting;
+}
+
+int Model::SphereCheckPossible(XYZ *p1,float radius, XYZ *move, float *rotate)
+{
+       static int i,j;
+       static float distance;
+       static float olddistance;
+       static int intersecting;
+       static int firstintersecting;
+       static XYZ point;
+       static XYZ oldp1;
+       static XYZ start,end;
+
+       firstintersecting=-1;
+
+       oldp1=*p1;
+       *p1=*p1-*move;
+
+       numpossible=0;
+
+       if(*rotate)*p1=DoRotation(*p1,0,-*rotate,0);
+       if(findDistancefast(p1,&boundingspherecenter)>radius*radius+boundingsphereradius*boundingsphereradius){*p1=oldp1; return -1;}
+
+       for (j=0;j<TriangleNum;j++){
+               intersecting=0;
+               distance=abs((facenormals[j].x*p1->x)+(facenormals[j].y*p1->y)+(facenormals[j].z*p1->z)-((facenormals[j].x*vertex[Triangles[j].vertex[0]].x)+(facenormals[j].y*vertex[Triangles[j].vertex[0]].y)+(facenormals[j].z*vertex[Triangles[j].vertex[0]].z)));
+               if(distance<radius){
+                       point=*p1-facenormals[j]*distance;
+                       if(PointInTriangle( &point, facenormals[j], &vertex[Triangles[j].vertex[0]], &vertex[Triangles[j].vertex[1]], &vertex[Triangles[j].vertex[2]]))intersecting=1;
+                       if(!intersecting)intersecting=sphere_line_intersection(&vertex[Triangles[j].vertex[0]],
+                               &vertex[Triangles[j].vertex[1]],
+                               p1, &radius);
+                       if(!intersecting)intersecting=sphere_line_intersection(&vertex[Triangles[j].vertex[1]],
+                               &vertex[Triangles[j].vertex[2]],
+                               p1, &radius);
+                       if(!intersecting)intersecting=sphere_line_intersection(&vertex[Triangles[j].vertex[0]],
+                               &vertex[Triangles[j].vertex[2]],
+                               p1, &radius);
+                       if(intersecting){
+                               //if(j>=0&&j<TriangleNum)
+                               possible[numpossible]=j;
+                               numpossible++;
+                       }
+               }
+               if((distance<olddistance||firstintersecting==-1)&&intersecting){olddistance=distance; firstintersecting=j;}
+       }
+       if(*rotate)*p1=DoRotation(*p1,0,*rotate,0);
+       *p1+=*move;
+       return firstintersecting;
+}
+
+
+void Model::UpdateVertexArray(){
+       if(type!=normaltype&&type!=decalstype)return;
+       static int i;
+       static int j;
+       if(!flat)
+               for(i=0;i<TriangleNum;i++){
+                       j=i*24;
+                       vArray[j+0]=Triangles[i].gx[0];
+                       vArray[j+1]=Triangles[i].gy[0];
+                       vArray[j+2]=normals[Triangles[i].vertex[0]].x;
+                       vArray[j+3]=normals[Triangles[i].vertex[0]].y;
+                       vArray[j+4]=normals[Triangles[i].vertex[0]].z;
+                       vArray[j+5]=vertex[Triangles[i].vertex[0]].x;
+                       vArray[j+6]=vertex[Triangles[i].vertex[0]].y;
+                       vArray[j+7]=vertex[Triangles[i].vertex[0]].z;
+
+                       vArray[j+8]=Triangles[i].gx[1];
+                       vArray[j+9]=Triangles[i].gy[1];
+                       vArray[j+10]=normals[Triangles[i].vertex[1]].x;
+                       vArray[j+11]=normals[Triangles[i].vertex[1]].y;
+                       vArray[j+12]=normals[Triangles[i].vertex[1]].z;
+                       vArray[j+13]=vertex[Triangles[i].vertex[1]].x;
+                       vArray[j+14]=vertex[Triangles[i].vertex[1]].y;
+                       vArray[j+15]=vertex[Triangles[i].vertex[1]].z;
+
+                       vArray[j+16]=Triangles[i].gx[2];
+                       vArray[j+17]=Triangles[i].gy[2];
+                       vArray[j+18]=normals[Triangles[i].vertex[2]].x;
+                       vArray[j+19]=normals[Triangles[i].vertex[2]].y;
+                       vArray[j+20]=normals[Triangles[i].vertex[2]].z;
+                       vArray[j+21]=vertex[Triangles[i].vertex[2]].x;
+                       vArray[j+22]=vertex[Triangles[i].vertex[2]].y;
+                       vArray[j+23]=vertex[Triangles[i].vertex[2]].z;
+               }
+               if(flat)
+                       for(i=0;i<TriangleNum;i++){
+                               j=i*24;
+                               vArray[j+0]=Triangles[i].gx[0];
+                               vArray[j+1]=Triangles[i].gy[0];
+                               vArray[j+2]=facenormals[i].x*-1;
+                               vArray[j+3]=facenormals[i].y*-1;
+                               vArray[j+4]=facenormals[i].z*-1;
+                               vArray[j+5]=vertex[Triangles[i].vertex[0]].x;
+                               vArray[j+6]=vertex[Triangles[i].vertex[0]].y;
+                               vArray[j+7]=vertex[Triangles[i].vertex[0]].z;
+
+                               vArray[j+8]=Triangles[i].gx[1];
+                               vArray[j+9]=Triangles[i].gy[1];
+                               vArray[j+10]=facenormals[i].x*-1;
+                               vArray[j+11]=facenormals[i].y*-1;
+                               vArray[j+12]=facenormals[i].z*-1;
+                               vArray[j+13]=vertex[Triangles[i].vertex[1]].x;
+                               vArray[j+14]=vertex[Triangles[i].vertex[1]].y;
+                               vArray[j+15]=vertex[Triangles[i].vertex[1]].z;
+
+                               vArray[j+16]=Triangles[i].gx[2];
+                               vArray[j+17]=Triangles[i].gy[2];
+                               vArray[j+18]=facenormals[i].x*-1;
+                               vArray[j+19]=facenormals[i].y*-1;
+                               vArray[j+20]=facenormals[i].z*-1;
+                               vArray[j+21]=vertex[Triangles[i].vertex[2]].x;
+                               vArray[j+22]=vertex[Triangles[i].vertex[2]].y;
+                               vArray[j+23]=vertex[Triangles[i].vertex[2]].z;
+
+                       }
+}
+
+void Model::UpdateVertexArrayNoTex(){
+       if(type!=normaltype&&type!=decalstype)return;
+       static int i;
+       static int j;
+       if(!flat)
+               for(i=0;i<TriangleNum;i++){
+                       j=i*24;
+                       vArray[j+2]=normals[Triangles[i].vertex[0]].x;
+                       vArray[j+3]=normals[Triangles[i].vertex[0]].y;
+                       vArray[j+4]=normals[Triangles[i].vertex[0]].z;
+                       vArray[j+5]=vertex[Triangles[i].vertex[0]].x;
+                       vArray[j+6]=vertex[Triangles[i].vertex[0]].y;
+                       vArray[j+7]=vertex[Triangles[i].vertex[0]].z;
+
+                       vArray[j+10]=normals[Triangles[i].vertex[1]].x;
+                       vArray[j+11]=normals[Triangles[i].vertex[1]].y;
+                       vArray[j+12]=normals[Triangles[i].vertex[1]].z;
+                       vArray[j+13]=vertex[Triangles[i].vertex[1]].x;
+                       vArray[j+14]=vertex[Triangles[i].vertex[1]].y;
+                       vArray[j+15]=vertex[Triangles[i].vertex[1]].z;
+
+                       vArray[j+18]=normals[Triangles[i].vertex[2]].x;
+                       vArray[j+19]=normals[Triangles[i].vertex[2]].y;
+                       vArray[j+20]=normals[Triangles[i].vertex[2]].z;
+                       vArray[j+21]=vertex[Triangles[i].vertex[2]].x;
+                       vArray[j+22]=vertex[Triangles[i].vertex[2]].y;
+                       vArray[j+23]=vertex[Triangles[i].vertex[2]].z;
+               }
+               if(flat)
+                       for(i=0;i<TriangleNum;i++){
+                               j=i*24;
+                               vArray[j+2]=facenormals[i].x*-1;
+                               vArray[j+3]=facenormals[i].y*-1;
+                               vArray[j+4]=facenormals[i].z*-1;
+                               vArray[j+5]=vertex[Triangles[i].vertex[0]].x;
+                               vArray[j+6]=vertex[Triangles[i].vertex[0]].y;
+                               vArray[j+7]=vertex[Triangles[i].vertex[0]].z;
+
+                               vArray[j+10]=facenormals[i].x*-1;
+                               vArray[j+11]=facenormals[i].y*-1;
+                               vArray[j+12]=facenormals[i].z*-1;
+                               vArray[j+13]=vertex[Triangles[i].vertex[1]].x;
+                               vArray[j+14]=vertex[Triangles[i].vertex[1]].y;
+                               vArray[j+15]=vertex[Triangles[i].vertex[1]].z;
+
+                               vArray[j+18]=facenormals[i].x*-1;
+                               vArray[j+19]=facenormals[i].y*-1;
+                               vArray[j+20]=facenormals[i].z*-1;
+                               vArray[j+21]=vertex[Triangles[i].vertex[2]].x;
+                               vArray[j+22]=vertex[Triangles[i].vertex[2]].y;
+                               vArray[j+23]=vertex[Triangles[i].vertex[2]].z;
+                       }
+}
+
+void Model::UpdateVertexArrayNoTexNoNorm(){
+       if(type!=normaltype&&type!=decalstype)return;
+       static int i;
+       static int j;
+       for(i=0;i<TriangleNum;i++){
+               j=i*24;
+               vArray[j+5]=vertex[Triangles[i].vertex[0]].x;
+               vArray[j+6]=vertex[Triangles[i].vertex[0]].y;
+               vArray[j+7]=vertex[Triangles[i].vertex[0]].z;
+
+               vArray[j+13]=vertex[Triangles[i].vertex[1]].x;
+               vArray[j+14]=vertex[Triangles[i].vertex[1]].y;
+               vArray[j+15]=vertex[Triangles[i].vertex[1]].z;
+
+               vArray[j+21]=vertex[Triangles[i].vertex[2]].x;
+               vArray[j+22]=vertex[Triangles[i].vertex[2]].y;
+               vArray[j+23]=vertex[Triangles[i].vertex[2]].z;
+       }
+}
+
+bool Model::loadnotex(char *filename )
+{
+       FILE                    *tfile;
+       long                            i;
+
+       int oldvertexNum,oldTriangleNum;
+       oldvertexNum=vertexNum;
+       oldTriangleNum=TriangleNum;
+
+       type=notextype;
+       color=0;
+
+       tfile=fopen( filename, "rb" );
+       // read model settings
+
+       fseek(tfile, 0, SEEK_SET);
+       funpackf(tfile, "Bs Bs", &vertexNum, &TriangleNum);
+
+       // read the model data
+       /*if(owner)dealloc(owner);
+       if(possible)dealloc(possible);
+       if(vertex)dealloc(vertex);
+       if(normals)dealloc(normals);
+       if(facenormals)dealloc(facenormals);
+       if(Triangles)dealloc(Triangles);
+       if(vArray)dealloc(vArray);*/
+       deallocate();
+
+       numpossible=0;
+
+       owner = (int*)malloc(sizeof(int)*vertexNum);
+       possible = (int*)malloc(sizeof(int)*TriangleNum);
+       vertex = (XYZ*)malloc(sizeof(XYZ)*vertexNum);
+       Triangles = (TexturedTriangle*)malloc(sizeof(TexturedTriangle)*TriangleNum);
+       vArray = (GLfloat*)malloc(sizeof(GLfloat)*TriangleNum*24);
+
+       for(i=0;i<vertexNum;i++){
+               funpackf(tfile, "Bf Bf Bf", &vertex[i].x,&vertex[i].y,&vertex[i].z);
+       }
+
+       for(i=0;i<TriangleNum;i++){
+               //              funpackf(tfile, "Bi Bi Bi", &Triangles[i].vertex[0], &Triangles[i].vertex[1], &Triangles[i].vertex[2]);
+               short vertex[ 6];
+               funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[ 0], &vertex[ 1], &vertex[ 2], &vertex[ 3], &vertex[ 4], &vertex[ 5]);
+               Triangles[i].vertex[ 0] = vertex[ 0];
+               Triangles[i].vertex[ 1] = vertex[ 2];
+               Triangles[i].vertex[ 2] = vertex[ 4];
+               funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
+               funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
+       }
+
+       fclose(tfile);
+
+       UpdateVertexArray();
+
+       for(i=0;i<vertexNum;i++){
+               owner[i]=-1;
+       }
+
+       static int j;
+       boundingsphereradius=0;
+       for(i=0;i<vertexNum;i++){
+               for(j=0;j<vertexNum;j++){
+                       if(j!=i&&findDistancefast(&vertex[j],&vertex[i])/2>boundingsphereradius){
+                               boundingsphereradius=findDistancefast(&vertex[j],&vertex[i])/2;
+                               boundingspherecenter=(vertex[i]+vertex[j])/2;
+                       }
+               }
+       }       
+       boundingsphereradius=fast_sqrt(boundingsphereradius);
+
+       return 1;
+}
+
+
+bool Model::load(char *filename,bool texture )
+{
+       FILE                    *tfile;
+       long                            i;
+
+       LOGFUNC;
+
+       LOG(std::string("Loading model...") + filename);
+
+       if(visibleloading){
+               loadscreencolor=2;
+               pgame->LoadingScreen();
+       }
+
+       int oldvertexNum,oldTriangleNum;
+       oldvertexNum=vertexNum;
+       oldTriangleNum=TriangleNum;
+
+       type = normaltype;
+       color=0;
+
+       tfile=fopen( filename, "rb" );
+       // read model settings
+
+
+       fseek(tfile, 0, SEEK_SET);
+       funpackf(tfile, "Bs Bs", &vertexNum, &TriangleNum);
+
+       // read the model data
+       /*if(owner)dealloc(owner);
+       if(possible)dealloc(possible);
+       if(vertex)dealloc(vertex);
+       if(normals)dealloc(normals);
+       if(facenormals)dealloc(facenormals);
+       if(Triangles)dealloc(Triangles);
+       if(vArray)dealloc(vArray);*/
+       deallocate();
+
+       numpossible=0;
+
+       owner = (int*)malloc(sizeof(int)*vertexNum);
+       possible = (int*)malloc(sizeof(int)*TriangleNum);
+       vertex = (XYZ*)malloc(sizeof(XYZ)*vertexNum);
+       normals = (XYZ*)malloc(sizeof(XYZ)*vertexNum);
+       facenormals = (XYZ*)malloc(sizeof(XYZ)*TriangleNum);
+       Triangles = (TexturedTriangle*)malloc(sizeof(TexturedTriangle)*TriangleNum);
+       vArray = (GLfloat*)malloc(sizeof(GLfloat)*TriangleNum*24);
+
+       for(i=0;i<vertexNum;i++){
+               funpackf(tfile, "Bf Bf Bf", &vertex[i].x,&vertex[i].y,&vertex[i].z);
+       }
+
+       for(i=0;i<TriangleNum;i++){
+               //              funpackf(tfile, "Bi Bi Bi", &Triangles[i].vertex[0], &Triangles[i].vertex[1], &Triangles[i].vertex[2]);
+               short vertex[ 6];
+               funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[ 0], &vertex[ 1], &vertex[ 2], &vertex[ 3], &vertex[ 4], &vertex[ 5]);
+               Triangles[i].vertex[ 0] = vertex[ 0];
+               Triangles[i].vertex[ 1] = vertex[ 2];
+               Triangles[i].vertex[ 2] = vertex[ 4];
+               funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
+               funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
+       }
+
+       Texture.xsz=0;
+
+       fclose(tfile);
+
+       UpdateVertexArray();
+
+       for(i=0;i<vertexNum;i++){
+               owner[i]=-1;
+       }
+
+       static int j;
+       boundingsphereradius=0;
+       for(i=0;i<vertexNum;i++){
+               for(j=0;j<vertexNum;j++){
+                       if(j!=i&&findDistancefast(&vertex[j],&vertex[i])/2>boundingsphereradius){
+                               boundingsphereradius=findDistancefast(&vertex[j],&vertex[i])/2;
+                               boundingspherecenter=(vertex[i]+vertex[j])/2;
+                       }
+               }
+       }       
+       boundingsphereradius=fast_sqrt(boundingsphereradius);
+
+       return 1;
+}
+
+bool Model::loaddecal(char *filename,bool texture )
+{
+       FILE                    *tfile;
+       long                            i,j;
+
+       LOGFUNC;
+
+       LOG(std::string("Loading decal...") + filename);
+
+       int oldvertexNum,oldTriangleNum;
+       oldvertexNum=vertexNum;
+       oldTriangleNum=TriangleNum;
+
+       type = decalstype;
+       numdecals=0;
+       color=0;
+
+       tfile=fopen( filename, "rb" );
+       // read model settings
+
+
+       fseek(tfile, 0, SEEK_SET);
+       funpackf(tfile, "Bs Bs", &vertexNum, &TriangleNum);
+
+       // read the model data
+
+       /*if(owner)dealloc(owner);
+       if(possible)dealloc(possible);
+       if(vertex)dealloc(vertex);
+       if(normals)dealloc(normals);
+       if(facenormals)dealloc(facenormals);
+       if(Triangles)dealloc(Triangles);
+       if(vArray)dealloc(vArray);*/
+       deallocate();
+
+       numpossible=0;
+
+       owner = (int*)malloc(sizeof(int)*vertexNum);
+       possible = (int*)malloc(sizeof(int)*TriangleNum);
+       vertex = (XYZ*)malloc(sizeof(XYZ)*vertexNum);
+       normals = (XYZ*)malloc(sizeof(XYZ)*vertexNum);
+       facenormals = (XYZ*)malloc(sizeof(XYZ)*TriangleNum);
+       Triangles = (TexturedTriangle*)malloc(sizeof(TexturedTriangle)*TriangleNum);
+       vArray = (GLfloat*)malloc(sizeof(GLfloat)*TriangleNum*24);
+
+
+       for(i=0;i<vertexNum;i++){
+               funpackf(tfile, "Bf Bf Bf", &vertex[i].x,&vertex[i].y,&vertex[i].z);
+       }
+
+       for(i=0;i<TriangleNum;i++){
+               //              funpackf(tfile, "Bi Bi Bi", &Triangles[i].vertex[0], &Triangles[i].vertex[1], &Triangles[i].vertex[2]);
+               short vertex[ 6];
+               funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[ 0], &vertex[ 1], &vertex[ 2], &vertex[ 3], &vertex[ 4], &vertex[ 5]);
+               Triangles[i].vertex[ 0] = vertex[ 0];
+               Triangles[i].vertex[ 1] = vertex[ 2];
+               Triangles[i].vertex[ 2] = vertex[ 4];
+               funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
+               funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
+       }
+
+
+       Texture.xsz=0;
+
+       fclose(tfile);
+
+       UpdateVertexArray();
+
+       for(i=0;i<vertexNum;i++){
+               owner[i]=-1;
+       }
+
+       boundingsphereradius=0;
+       for(i=0;i<vertexNum;i++){
+               for(j=0;j<vertexNum;j++){
+                       if(j!=i&&findDistancefast(&vertex[j],&vertex[i])/2>boundingsphereradius){
+                               boundingsphereradius=findDistancefast(&vertex[j],&vertex[i])/2;
+                               boundingspherecenter=(vertex[i]+vertex[j])/2;
+                       }
+               }
+       }       
+       boundingsphereradius=fast_sqrt(boundingsphereradius);
+
+       //allow decals
+       if(!decaltexcoords){
+               decaltexcoords = (float***)malloc(sizeof(float**)*max_model_decals);
+               for(i=0;i<max_model_decals;i++){
+                       decaltexcoords[i] = (float**)malloc(sizeof(float*)*3);
+                       for(j=0;j<3;j++){
+                               decaltexcoords[i][j] = (float*)malloc(sizeof(float)*2);
+                       }
+               }
+               //if(decalvertex)free(decalvertex);
+               decalvertex = (XYZ**)malloc(sizeof(XYZ*)*max_model_decals);
+               for(i=0;i<max_model_decals;i++){
+                       decalvertex[i] = (XYZ*)malloc(sizeof(XYZ)*3);
+               }
+
+               decaltype = (int*)malloc(sizeof(int)*max_model_decals);
+               decalopacity = (float*)malloc(sizeof(float)*max_model_decals);
+               decalrotation = (float*)malloc(sizeof(float)*max_model_decals);
+               decalalivetime = (float*)malloc(sizeof(float)*max_model_decals);
+               decalposition = (XYZ*)malloc(sizeof(XYZ)*max_model_decals);
+       }
+
+       return 1;
+}
+
+bool Model::loadraw(char *filename )
+{
+       FILE                    *tfile;
+       long                            i;
+
+       LOGFUNC;
+
+       LOG(std::string("Loading raw...") + filename);
+
+       int oldvertexNum,oldTriangleNum;
+       oldvertexNum=vertexNum;
+       oldTriangleNum=TriangleNum;
+
+       type = rawtype;
+       color=0;
+
+       tfile=fopen( filename, "rb" );
+       // read model settings
+
+
+       fseek(tfile, 0, SEEK_SET);
+       funpackf(tfile, "Bs Bs", &vertexNum, &TriangleNum);
+
+       // read the model data
+       /*if(owner)dealloc(owner);
+       if(possible)dealloc(possible);
+       if(vertex)dealloc(vertex);
+       if(normals)dealloc(normals);
+       if(facenormals)dealloc(facenormals);
+       if(Triangles)dealloc(Triangles);
+       if(vArray)dealloc(vArray);*/
+       deallocate();
+
+       numpossible=0;
+
+       owner = (int*)malloc(sizeof(int)*vertexNum);
+       possible = (int*)malloc(sizeof(int)*TriangleNum);
+       vertex = (XYZ*)malloc(sizeof(XYZ)*vertexNum);
+       Triangles = (TexturedTriangle*)malloc(sizeof(TexturedTriangle)*TriangleNum);
+       vArray = (GLfloat*)malloc(sizeof(GLfloat)*TriangleNum*24);
+
+
+       for(i=0;i<vertexNum;i++){
+               funpackf(tfile, "Bf Bf Bf", &vertex[i].x,&vertex[i].y,&vertex[i].z);
+       }
+
+       for(i=0;i<TriangleNum;i++){
+               //              funpackf(tfile, "Bi Bi Bi", &Triangles[i].vertex[0], &Triangles[i].vertex[1], &Triangles[i].vertex[2]);
+               short vertex[ 6];
+               funpackf(tfile, "Bs Bs Bs Bs Bs Bs", &vertex[ 0], &vertex[ 1], &vertex[ 2], &vertex[ 3], &vertex[ 4], &vertex[ 5]);
+               Triangles[i].vertex[ 0] = vertex[ 0];
+               Triangles[i].vertex[ 1] = vertex[ 2];
+               Triangles[i].vertex[ 2] = vertex[ 4];
+               funpackf(tfile, "Bf Bf Bf", &Triangles[i].gx[0], &Triangles[i].gx[1], &Triangles[i].gx[2]);
+               funpackf(tfile, "Bf Bf Bf", &Triangles[i].gy[0], &Triangles[i].gy[1], &Triangles[i].gy[2]);
+       }
+
+
+       fclose(tfile);
+
+       for(i=0;i<vertexNum;i++){
+               owner[i]=-1;
+       }
+
+       return 1;
+}
+
+
+void Model::UniformTexCoords()
+{
+       static int i;
+       for(i=0; i<TriangleNum; i++){
+               Triangles[i].gy[0]=vertex[Triangles[i].vertex[0]].y;
+               Triangles[i].gy[1]=vertex[Triangles[i].vertex[1]].y;
+               Triangles[i].gy[2]=vertex[Triangles[i].vertex[2]].y;            
+               Triangles[i].gx[0]=vertex[Triangles[i].vertex[0]].x;
+               Triangles[i].gx[1]=vertex[Triangles[i].vertex[1]].x;
+               Triangles[i].gx[2]=vertex[Triangles[i].vertex[2]].x;            
+       }
+       UpdateVertexArray();
+}
+
+
+void Model::FlipTexCoords()
+{
+       static int i;
+       for(i=0; i<TriangleNum; i++){
+               Triangles[i].gy[0]=-Triangles[i].gy[0];
+               Triangles[i].gy[1]=-Triangles[i].gy[1];
+               Triangles[i].gy[2]=-Triangles[i].gy[2];         
+       }
+       UpdateVertexArray();
+}
+
+void Model::ScaleTexCoords(float howmuch)
+{
+       static int i;
+       for(i=0; i<TriangleNum; i++){
+               Triangles[i].gx[0]*=howmuch;
+               Triangles[i].gx[1]*=howmuch;
+               Triangles[i].gx[2]*=howmuch;    
+               Triangles[i].gy[0]*=howmuch;
+               Triangles[i].gy[1]*=howmuch;
+               Triangles[i].gy[2]*=howmuch;            
+       }
+       UpdateVertexArray();
+}
+
+void Model::Scale(float xscale,float yscale,float zscale)
+{
+       static int i;
+       for(i=0; i<vertexNum; i++){
+               vertex[i].x*=xscale;
+               vertex[i].y*=yscale;
+               vertex[i].z*=zscale;
+       }
+       UpdateVertexArray();
+
+       static int j;
+
+       boundingsphereradius=0;
+       for(i=0;i<vertexNum;i++){
+               for(j=0;j<vertexNum;j++){
+                       if(j!=i&&findDistancefast(&vertex[j],&vertex[i])/2>boundingsphereradius){
+                               boundingsphereradius=findDistancefast(&vertex[j],&vertex[i])/2;
+                               boundingspherecenter=(vertex[i]+vertex[j])/2;
+                       }
+               }
+       }       
+       boundingsphereradius=fast_sqrt(boundingsphereradius);
+}
+
+void Model::ScaleNormals(float xscale,float yscale,float zscale)
+{
+       if(type!=normaltype&&type!=decalstype)return;
+       static int i;
+       for(i=0; i<vertexNum; i++){
+               normals[i].x*=xscale;
+               normals[i].y*=yscale;
+               normals[i].z*=zscale;
+       }
+       for(i=0; i<TriangleNum; i++){
+               facenormals[i].x*=xscale;
+               facenormals[i].y*=yscale;
+               facenormals[i].z*=zscale;
+       }
+       UpdateVertexArray();
+}
+
+void Model::Translate(float xtrans,float ytrans,float ztrans)
+{
+       static int i;
+       for(i=0; i<vertexNum; i++){
+               vertex[i].x+=xtrans;
+               vertex[i].y+=ytrans;
+               vertex[i].z+=ztrans;
+       }
+       UpdateVertexArray();
+
+       static int j;
+       boundingsphereradius=0;
+       for(i=0;i<vertexNum;i++){
+               for(j=0;j<vertexNum;j++){
+                       if(j!=i&&findDistancefast(&vertex[j],&vertex[i])/2>boundingsphereradius){
+                               boundingsphereradius=findDistancefast(&vertex[j],&vertex[i])/2;
+                               boundingspherecenter=(vertex[i]+vertex[j])/2;
+                       }
+               }
+       }       
+       boundingsphereradius=fast_sqrt(boundingsphereradius);
+}
+
+void Model::Rotate(float xang,float yang,float zang)
+{
+       static int i;
+       for(i=0; i<vertexNum; i++){
+               vertex[i]=DoRotation(vertex[i],xang,yang,zang);
+       }
+       UpdateVertexArray();
+
+       static int j;
+       boundingsphereradius=0;
+       for(i=0;i<vertexNum;i++){
+               for(j=0;j<vertexNum;j++){
+                       if(j!=i&&findDistancefast(&vertex[j],&vertex[i])/2>boundingsphereradius){
+                               boundingsphereradius=findDistancefast(&vertex[j],&vertex[i])/2;
+                               boundingspherecenter=(vertex[i]+vertex[j])/2;
+                       }
+               }
+       }
+       boundingsphereradius=fast_sqrt(boundingsphereradius);   
+}
+
+
+void Model::CalculateNormals(bool facenormalise)
+{
+       if(visibleloading){
+               loadscreencolor=3;
+               pgame->LoadingScreen();
+       }
+       static int i;
+       if(type!=normaltype&&type!=decalstype)return;
+
+       for(i=0; i<vertexNum; i++){
+               normals[i].x=0;
+               normals[i].y=0;
+               normals[i].z=0;
+       }
+
+       for(i=0;i<TriangleNum;i++){
+               CrossProduct(vertex[Triangles[i].vertex[1]]-vertex[Triangles[i].vertex[0]],vertex[Triangles[i].vertex[2]]-vertex[Triangles[i].vertex[0]],&facenormals[i]);
+
+               normals[Triangles[i].vertex[0]].x+=facenormals[i].x;
+               normals[Triangles[i].vertex[0]].y+=facenormals[i].y;
+               normals[Triangles[i].vertex[0]].z+=facenormals[i].z;
+
+               normals[Triangles[i].vertex[1]].x+=facenormals[i].x;
+               normals[Triangles[i].vertex[1]].y+=facenormals[i].y;
+               normals[Triangles[i].vertex[1]].z+=facenormals[i].z;
+
+               normals[Triangles[i].vertex[2]].x+=facenormals[i].x;
+               normals[Triangles[i].vertex[2]].y+=facenormals[i].y;
+               normals[Triangles[i].vertex[2]].z+=facenormals[i].z;
+               if(facenormalise)Normalise(&facenormals[i]);
+       }
+       for(i=0; i<vertexNum; i++){
+               Normalise(&normals[i]);
+               normals[i]*=-1;
+       }
+       UpdateVertexArrayNoTex();
+}
+
+void Model::drawimmediate()
+{
+       glBindTexture(GL_TEXTURE_2D,(unsigned long)textureptr);
+       glBegin(GL_TRIANGLES);
+       for(int i=0;i<TriangleNum;i++){
+               /*if(Triangles[i].vertex[0]<vertexNum&&Triangles[i].vertex[1]<vertexNum&&Triangles[i].vertex[2]<vertexNum&&Triangles[i].vertex[0]>=0&&Triangles[i].vertex[1]>=0&&Triangles[i].vertex[2]>=0){
+               if(isnormal(vertex[Triangles[i].vertex[0]].x)&&isnormal(vertex[Triangles[i].vertex[0]].y)&&isnormal(vertex[Triangles[i].vertex[0]].z)
+               &&isnormal(vertex[Triangles[i].vertex[1]].x)&&isnormal(vertex[Triangles[i].vertex[1]].y)&&isnormal(vertex[Triangles[i].vertex[1]].z)
+               &&isnormal(vertex[Triangles[i].vertex[2]].x)&&isnormal(vertex[Triangles[i].vertex[2]].y)&&isnormal(vertex[Triangles[i].vertex[2]].z)){
+               */
+               glTexCoord2f(Triangles[i].gx[0],Triangles[i].gy[0]);
+               if(color)glColor3f(normals[Triangles[i].vertex[0]].x,normals[Triangles[i].vertex[0]].y,normals[Triangles[i].vertex[0]].z);
+               if(!color&&!flat)glNormal3f(normals[Triangles[i].vertex[0]].x,normals[Triangles[i].vertex[0]].y,normals[Triangles[i].vertex[0]].z);
+               if(!color&&flat)glNormal3f(facenormals[i].x,facenormals[i].y,facenormals[i].y);
+               glVertex3f(vertex[Triangles[i].vertex[0]].x,vertex[Triangles[i].vertex[0]].y,vertex[Triangles[i].vertex[0]].z);
+
+               glTexCoord2f(Triangles[i].gx[1],Triangles[i].gy[1]);
+               if(color)glColor3f(normals[Triangles[i].vertex[1]].x,normals[Triangles[i].vertex[1]].y,normals[Triangles[i].vertex[1]].z);
+               if(!color&&!flat)glNormal3f(normals[Triangles[i].vertex[1]].x,normals[Triangles[i].vertex[1]].y,normals[Triangles[i].vertex[1]].z);
+               if(!color&&flat)glNormal3f(facenormals[i].x,facenormals[i].y,facenormals[i].y);
+               glVertex3f(vertex[Triangles[i].vertex[1]].x,vertex[Triangles[i].vertex[1]].y,vertex[Triangles[i].vertex[1]].z);
+
+               glTexCoord2f(Triangles[i].gx[2],Triangles[i].gy[2]);
+               if(color)glColor3f(normals[Triangles[i].vertex[2]].x,normals[Triangles[i].vertex[2]].y,normals[Triangles[i].vertex[2]].z);
+               if(!color&&!flat)glNormal3f(normals[Triangles[i].vertex[2]].x,normals[Triangles[i].vertex[2]].y,normals[Triangles[i].vertex[2]].z);
+               if(!color&&flat)glNormal3f(facenormals[i].x,facenormals[i].y,facenormals[i].y);
+               glVertex3f(vertex[Triangles[i].vertex[2]].x,vertex[Triangles[i].vertex[2]].y,vertex[Triangles[i].vertex[2]].z);
+               //}
+               //}
+       }
+       glEnd();
+}
+
+void Model::draw()
+{
+       if(type!=normaltype&&type!=decalstype)return;
+
+       glEnableClientState(GL_NORMAL_ARRAY);
+       glEnableClientState(GL_VERTEX_ARRAY);
+       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+       if(!color)glInterleavedArrays( GL_T2F_N3F_V3F,8*sizeof(GLfloat),&vArray[0]);
+       if(color)glInterleavedArrays( GL_T2F_C3F_V3F,8*sizeof(GLfloat),&vArray[0]);
+       glBindTexture(GL_TEXTURE_2D,(unsigned long)textureptr);
+
+#ifndef WIN32
+       glLockArraysEXT( 0, TriangleNum*3);
+#endif
+       glDrawArrays(GL_TRIANGLES, 0, TriangleNum*3);
+#ifndef WIN32
+       glUnlockArraysEXT();
+#endif
+
+
+       if(!color)glDisableClientState(GL_NORMAL_ARRAY);
+       if(color)glDisableClientState(GL_COLOR_ARRAY);
+       glDisableClientState(GL_VERTEX_ARRAY);
+       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+       //drawimmediate();
+}
+
+void Model::drawdifftex(GLuint texture)
+{
+       glEnableClientState(GL_NORMAL_ARRAY);
+       glEnableClientState(GL_VERTEX_ARRAY);
+       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+       if(!color)glInterleavedArrays( GL_T2F_N3F_V3F,8*sizeof(GLfloat),&vArray[0]);
+       if(color)glInterleavedArrays( GL_T2F_C3F_V3F,8*sizeof(GLfloat),&vArray[0]);
+
+       glBindTexture(GL_TEXTURE_2D,(unsigned long)texture);
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+
+
+#ifndef WIN32
+       glLockArraysEXT( 0, TriangleNum*3);
+#endif
+       glDrawArrays(GL_TRIANGLES, 0, TriangleNum*3);
+#ifndef WIN32
+       glUnlockArraysEXT();
+#endif
+
+
+       if(!color)glDisableClientState(GL_NORMAL_ARRAY);
+       if(color)glDisableClientState(GL_COLOR_ARRAY);
+       glDisableClientState(GL_VERTEX_ARRAY);
+       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+       //drawdiffteximmediate(texture);
+}
+
+void Model::drawdiffteximmediate(GLuint texture)
+{
+       glBindTexture(GL_TEXTURE_2D,(unsigned long)texture);
+
+       glBegin(GL_TRIANGLES);
+       for(int i=0;i<TriangleNum;i++){
+               /*if(Triangles[i].vertex[0]<vertexNum&&Triangles[i].vertex[1]<vertexNum&&Triangles[i].vertex[2]<vertexNum&&Triangles[i].vertex[0]>=0&&Triangles[i].vertex[1]>=0&&Triangles[i].vertex[2]>=0){
+               if(isnormal(vertex[Triangles[i].vertex[0]].x)&&isnormal(vertex[Triangles[i].vertex[0]].y)&&isnormal(vertex[Triangles[i].vertex[0]].z)
+               &&isnormal(vertex[Triangles[i].vertex[1]].x)&&isnormal(vertex[Triangles[i].vertex[1]].y)&&isnormal(vertex[Triangles[i].vertex[1]].z)
+               &&isnormal(vertex[Triangles[i].vertex[2]].x)&&isnormal(vertex[Triangles[i].vertex[2]].y)&&isnormal(vertex[Triangles[i].vertex[2]].z)){
+               */glTexCoord2f(Triangles[i].gx[0],Triangles[i].gy[0]);
+               if(color)glColor3f(normals[Triangles[i].vertex[0]].x,normals[Triangles[i].vertex[0]].y,normals[Triangles[i].vertex[0]].z);
+               if(!color&&!flat)glNormal3f(normals[Triangles[i].vertex[0]].x,normals[Triangles[i].vertex[0]].y,normals[Triangles[i].vertex[0]].z);
+               if(!color&&flat)glNormal3f(facenormals[i].x,facenormals[i].y,facenormals[i].y);
+               glVertex3f(vertex[Triangles[i].vertex[0]].x,vertex[Triangles[i].vertex[0]].y,vertex[Triangles[i].vertex[0]].z);
+
+               glTexCoord2f(Triangles[i].gx[1],Triangles[i].gy[1]);
+               if(color)glColor3f(normals[Triangles[i].vertex[1]].x,normals[Triangles[i].vertex[1]].y,normals[Triangles[i].vertex[1]].z);
+               if(!color&&!flat)glNormal3f(normals[Triangles[i].vertex[1]].x,normals[Triangles[i].vertex[1]].y,normals[Triangles[i].vertex[1]].z);
+               if(!color&&flat)glNormal3f(facenormals[i].x,facenormals[i].y,facenormals[i].y);
+               glVertex3f(vertex[Triangles[i].vertex[1]].x,vertex[Triangles[i].vertex[1]].y,vertex[Triangles[i].vertex[1]].z);
+
+               glTexCoord2f(Triangles[i].gx[2],Triangles[i].gy[2]);
+               if(color)glColor3f(normals[Triangles[i].vertex[2]].x,normals[Triangles[i].vertex[2]].y,normals[Triangles[i].vertex[2]].z);
+               if(!color&&!flat)glNormal3f(normals[Triangles[i].vertex[2]].x,normals[Triangles[i].vertex[2]].y,normals[Triangles[i].vertex[2]].z);
+               if(!color&&flat)glNormal3f(facenormals[i].x,facenormals[i].y,facenormals[i].y);
+               glVertex3f(vertex[Triangles[i].vertex[2]].x,vertex[Triangles[i].vertex[2]].y,vertex[Triangles[i].vertex[2]].z);
+               //}
+               //}
+       }
+       glEnd();
+}
+
+void Model::drawdecals(GLuint shadowtexture,GLuint bloodtexture,GLuint bloodtexture2,GLuint breaktexture)
+{
+       if(decals){
+               if(type!=decalstype)return;
+               static int i,j;
+               static float distancemult;
+               static int lasttype;
+               static float viewdistsquared;
+               static bool blend;
+
+               viewdistsquared=viewdistance*viewdistance;
+               blend=1;
+
+               lasttype=-1;
+               glEnable(GL_BLEND);
+               glDisable(GL_LIGHTING);
+               glDisable(GL_CULL_FACE);
+               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+               glDepthMask(0);
+               if(numdecals>max_model_decals)numdecals=max_model_decals;
+               for(i=0;i<numdecals;i++){
+                       if(decaltype[i]==blooddecalfast&&decalalivetime[i]<2)decalalivetime[i]=2;
+
+                       if(decaltype[i]==shadowdecal&&decaltype[i]!=lasttype){
+                               glBindTexture( GL_TEXTURE_2D, shadowtexture);
+                               if(!blend){
+                                       blend=1;
+                                       glAlphaFunc(GL_GREATER, 0.0001);
+                                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                               }
+                       }
+                       if(decaltype[i]==breakdecal&&decaltype[i]!=lasttype){
+                               glBindTexture( GL_TEXTURE_2D, breaktexture);
+                               if(!blend){
+                                       blend=1;
+                                       glAlphaFunc(GL_GREATER, 0.0001);
+                                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                               }
+                       }
+                       if((decaltype[i]==blooddecal||decaltype[i]==blooddecalslow)&&decaltype[i]!=lasttype){
+                               glBindTexture( GL_TEXTURE_2D, bloodtexture);
+                               if(blend){
+                                       blend=0;
+                                       glAlphaFunc(GL_GREATER, 0.15);
+                                       glBlendFunc(GL_ONE,GL_ZERO);
+                               }
+                       }
+                       if((decaltype[i]==blooddecalfast)&&decaltype[i]!=lasttype){
+                               glBindTexture( GL_TEXTURE_2D, bloodtexture2);
+                               if(blend){
+                                       blend=0;
+                                       glAlphaFunc(GL_GREATER, 0.15);
+                                       glBlendFunc(GL_ONE,GL_ZERO);
+                               }
+                       }
+                       if(decaltype[i]==shadowdecal){
+                               glColor4f(1,1,1,decalopacity[i]);
+                       }
+                       if(decaltype[i]==breakdecal){
+                               glColor4f(1,1,1,decalopacity[i]);
+                               if(decalalivetime[i]>58)glColor4f(1,1,1,decalopacity[i]*(60-decalalivetime[i])/2);
+                       }
+                       if((decaltype[i]==blooddecal||decaltype[i]==blooddecalfast||decaltype[i]==blooddecalslow)){
+                               glColor4f(1,1,1,decalopacity[i]);
+                               if(decalalivetime[i]<4)glColor4f(1,1,1,decalopacity[i]*decalalivetime[i]*.25);
+                               if(decalalivetime[i]>58)glColor4f(1,1,1,decalopacity[i]*(60-decalalivetime[i])/2);
+                       }
+                       lasttype=decaltype[i];
+                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
+
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPushMatrix();
+                               glBegin(GL_TRIANGLES);
+                               for(int j=0;j<3;j++)
+                               {
+                                       glTexCoord2f(decaltexcoords[i][j][0], decaltexcoords[i][j][1]); glVertex3f(decalvertex[i][j].x,decalvertex[i][j].y,decalvertex[i][j].z);
+                               }
+                       glEnd();
+                       glPopMatrix();
+               }
+               for(i=numdecals-1;i>=0;i--){
+                       decalalivetime[i]+=multiplier;
+                       if(decaltype[i]==blooddecalslow)decalalivetime[i]-=multiplier*2/3;
+                       if(decaltype[i]==blooddecalfast)decalalivetime[i]+=multiplier*4;
+                       if(decaltype[i]==shadowdecal)DeleteDecal(i);
+                       if((decaltype[i]==blooddecal||decaltype[i]==blooddecalfast||decaltype[i]==blooddecalslow)&&decalalivetime[i]>=60)DeleteDecal(i);
+               }
+               glAlphaFunc(GL_GREATER, 0.0001);
+               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+       }
+}
+
+void Model::DeleteDecal(int which)
+{
+       if(decals){
+               if(type!=decalstype)return;
+               decaltype[which]=decaltype[numdecals-1];
+               decalposition[which]=decalposition[numdecals-1];
+               for(int i=0;i<3;i++){
+                       decalvertex[which][i]=decalvertex[numdecals-1][i];
+                       decaltexcoords[which][i][0]=decaltexcoords[numdecals-1][i][0];
+                       decaltexcoords[which][i][1]=decaltexcoords[numdecals-1][i][1];
+               }
+               decalrotation[which]=decalrotation[numdecals-1];
+               decalalivetime[which]=decalalivetime[numdecals-1];
+               decalopacity[which]=decalopacity[numdecals-1];
+               numdecals--;
+       }
+}
+
+void Model::MakeDecal(int atype, XYZ *where,float *size, float *opacity, float *rotation){
+       if(decals){
+               if(type!=decalstype)return;
+
+               static float placex,placez;
+               static XYZ rot;
+               //static XYZ point,point1,point2;
+               static float distance;
+               static int i,j;
+
+               if(*opacity>0)
+                       if(findDistancefast(where,&boundingspherecenter)<(boundingsphereradius+*size)*(boundingsphereradius+*size))
+                               for(i=0;i<TriangleNum;i++){
+                                       if(facenormals[i].y<-.1&&(vertex[Triangles[i].vertex[0]].y<where->y||vertex[Triangles[i].vertex[1]].y<where->y||vertex[Triangles[i].vertex[2]].y<where->y)){
+                                               decalposition[numdecals]=*where;
+                                               decaltype[numdecals]=atype;
+                                               decalrotation[numdecals]=*rotation;
+                                               decalalivetime[numdecals]=0;
+                                               distance=abs(((facenormals[i].x*where->x)+(facenormals[i].y*where->y)+(facenormals[i].z*where->z)-((facenormals[i].x*vertex[Triangles[i].vertex[0]].x)+(facenormals[i].y*vertex[Triangles[i].vertex[0]].y)+(facenormals[i].z*vertex[Triangles[i].vertex[0]].z)))/facenormals[i].y);
+                                               decalopacity[numdecals]=*opacity-distance/10;
+
+                                               if(decalopacity[numdecals>0]){
+                                                       placex=vertex[Triangles[i].vertex[0]].x;
+                                                       placez=vertex[Triangles[i].vertex[0]].z;
+
+                                                       decaltexcoords[numdecals][0][0]=(placex-where->x)/(*size)/2+.5;
+                                                       decaltexcoords[numdecals][0][1]=(placez-where->z)/(*size)/2+.5;
+
+                                                       decalvertex[numdecals][0].x=placex;
+                                                       decalvertex[numdecals][0].z=placez;
+                                                       decalvertex[numdecals][0].y=vertex[Triangles[i].vertex[0]].y;
+
+
+                                                       placex=vertex[Triangles[i].vertex[1]].x;
+                                                       placez=vertex[Triangles[i].vertex[1]].z;
+
+                                                       decaltexcoords[numdecals][1][0]=(placex-where->x)/(*size)/2+.5;
+                                                       decaltexcoords[numdecals][1][1]=(placez-where->z)/(*size)/2+.5;
+
+                                                       decalvertex[numdecals][1].x=placex;
+                                                       decalvertex[numdecals][1].z=placez;
+                                                       decalvertex[numdecals][1].y=vertex[Triangles[i].vertex[1]].y;
+
+
+                                                       placex=vertex[Triangles[i].vertex[2]].x;
+                                                       placez=vertex[Triangles[i].vertex[2]].z;
+
+                                                       decaltexcoords[numdecals][2][0]=(placex-where->x)/(*size)/2+.5;
+                                                       decaltexcoords[numdecals][2][1]=(placez-where->z)/(*size)/2+.5;
+
+                                                       decalvertex[numdecals][2].x=placex;
+                                                       decalvertex[numdecals][2].z=placez;
+                                                       decalvertex[numdecals][2].y=vertex[Triangles[i].vertex[2]].y;
+
+                                                       if(!(decaltexcoords[numdecals][0][0]<0&&decaltexcoords[numdecals][1][0]<0&&decaltexcoords[numdecals][2][0]<0))
+                                                               if(!(decaltexcoords[numdecals][0][1]<0&&decaltexcoords[numdecals][1][1]<0&&decaltexcoords[numdecals][2][1]<0))
+                                                                       if(!(decaltexcoords[numdecals][0][0]>1&&decaltexcoords[numdecals][1][0]>1&&decaltexcoords[numdecals][2][0]>1))
+                                                                               if(!(decaltexcoords[numdecals][0][1]>1&&decaltexcoords[numdecals][1][1]>1&&decaltexcoords[numdecals][2][1]>1))
+                                                                               {
+                                                                                       if(decalrotation[numdecals]){
+                                                                                               for(j=0;j<3;j++){                       
+                                                                                                       rot.y=0;
+                                                                                                       rot.x=decaltexcoords[numdecals][j][0]-.5;
+                                                                                                       rot.z=decaltexcoords[numdecals][j][1]-.5;
+                                                                                                       rot=DoRotation(rot,0,-decalrotation[numdecals],0);
+                                                                                                       decaltexcoords[numdecals][j][0]=rot.x+.5;
+                                                                                                       decaltexcoords[numdecals][j][1]=rot.z+.5;
+                                                                                               }
+                                                                                       }
+                                                                                       if(numdecals<max_model_decals-1)numdecals++;
+                                                                               }
+                                               }
+                                       }
+                               }
+       }
+}
+
+void Model::MakeDecal(int atype, XYZ where,float size, float opacity, float rotation){
+       if(decals){
+               if(type!=decalstype)return;
+
+               static float placex,placez;
+               static XYZ rot;
+               //static XYZ point,point1,point2;
+               static float distance;
+               static int i,j;
+
+               if(opacity>0)
+                       if(findDistancefast(&where,&boundingspherecenter)<(boundingsphereradius+size)*(boundingsphereradius+size))
+                               for(i=0;i<TriangleNum;i++){
+                                       distance=abs(((facenormals[i].x*where.x)+(facenormals[i].y*where.y)+(facenormals[i].z*where.z)-((facenormals[i].x*vertex[Triangles[i].vertex[0]].x)+(facenormals[i].y*vertex[Triangles[i].vertex[0]].y)+(facenormals[i].z*vertex[Triangles[i].vertex[0]].z))));
+                                       if(distance<.02&&abs(facenormals[i].y)>abs(facenormals[i].x)&&abs(facenormals[i].y)>abs(facenormals[i].z)){
+                                               decalposition[numdecals]=where;
+                                               decaltype[numdecals]=atype;
+                                               decalrotation[numdecals]=rotation;
+                                               decalalivetime[numdecals]=0;
+                                               decalopacity[numdecals]=opacity-distance/10;
+
+                                               if(decalopacity[numdecals>0]){
+                                                       placex=vertex[Triangles[i].vertex[0]].x;
+                                                       placez=vertex[Triangles[i].vertex[0]].z;
+
+                                                       decaltexcoords[numdecals][0][0]=(placex-where.x)/(size)/2+.5;
+                                                       decaltexcoords[numdecals][0][1]=(placez-where.z)/(size)/2+.5;
+
+                                                       decalvertex[numdecals][0].x=placex;
+                                                       decalvertex[numdecals][0].z=placez;
+                                                       decalvertex[numdecals][0].y=vertex[Triangles[i].vertex[0]].y;
+
+
+                                                       placex=vertex[Triangles[i].vertex[1]].x;
+                                                       placez=vertex[Triangles[i].vertex[1]].z;
+
+                                                       decaltexcoords[numdecals][1][0]=(placex-where.x)/(size)/2+.5;
+                                                       decaltexcoords[numdecals][1][1]=(placez-where.z)/(size)/2+.5;
+
+                                                       decalvertex[numdecals][1].x=placex;
+                                                       decalvertex[numdecals][1].z=placez;
+                                                       decalvertex[numdecals][1].y=vertex[Triangles[i].vertex[1]].y;
+
+
+                                                       placex=vertex[Triangles[i].vertex[2]].x;
+                                                       placez=vertex[Triangles[i].vertex[2]].z;
+
+                                                       decaltexcoords[numdecals][2][0]=(placex-where.x)/(size)/2+.5;
+                                                       decaltexcoords[numdecals][2][1]=(placez-where.z)/(size)/2+.5;
+
+                                                       decalvertex[numdecals][2].x=placex;
+                                                       decalvertex[numdecals][2].z=placez;
+                                                       decalvertex[numdecals][2].y=vertex[Triangles[i].vertex[2]].y;
+
+                                                       if(!(decaltexcoords[numdecals][0][0]<0&&decaltexcoords[numdecals][1][0]<0&&decaltexcoords[numdecals][2][0]<0))
+                                                               if(!(decaltexcoords[numdecals][0][1]<0&&decaltexcoords[numdecals][1][1]<0&&decaltexcoords[numdecals][2][1]<0))
+                                                                       if(!(decaltexcoords[numdecals][0][0]>1&&decaltexcoords[numdecals][1][0]>1&&decaltexcoords[numdecals][2][0]>1))
+                                                                               if(!(decaltexcoords[numdecals][0][1]>1&&decaltexcoords[numdecals][1][1]>1&&decaltexcoords[numdecals][2][1]>1))
+                                                                               {
+                                                                                       if(decalrotation[numdecals]){
+                                                                                               for(j=0;j<3;j++){                       
+                                                                                                       rot.y=0;
+                                                                                                       rot.x=decaltexcoords[numdecals][j][0]-.5;
+                                                                                                       rot.z=decaltexcoords[numdecals][j][1]-.5;
+                                                                                                       rot=DoRotation(rot,0,-decalrotation[numdecals],0);
+                                                                                                       decaltexcoords[numdecals][j][0]=rot.x+.5;
+                                                                                                       decaltexcoords[numdecals][j][1]=rot.z+.5;
+                                                                                               }
+                                                                                       }
+                                                                                       if(numdecals<max_model_decals-1)numdecals++;
+                                                                               }
+                                               }
+                                       }
+                                       else if(distance<.02&&abs(facenormals[i].x)>abs(facenormals[i].y)&&abs(facenormals[i].x)>abs(facenormals[i].z)){
+                                               decalposition[numdecals]=where;
+                                               decaltype[numdecals]=atype;
+                                               decalrotation[numdecals]=rotation;
+                                               decalalivetime[numdecals]=0;
+                                               decalopacity[numdecals]=opacity-distance/10;
+
+                                               if(decalopacity[numdecals>0]){
+                                                       placex=vertex[Triangles[i].vertex[0]].y;
+                                                       placez=vertex[Triangles[i].vertex[0]].z;
+
+                                                       decaltexcoords[numdecals][0][0]=(placex-where.y)/(size)/2+.5;
+                                                       decaltexcoords[numdecals][0][1]=(placez-where.z)/(size)/2+.5;
+
+                                                       decalvertex[numdecals][0].x=vertex[Triangles[i].vertex[0]].x;
+                                                       decalvertex[numdecals][0].z=placez;
+                                                       decalvertex[numdecals][0].y=placex;
+
+
+                                                       placex=vertex[Triangles[i].vertex[1]].y;
+                                                       placez=vertex[Triangles[i].vertex[1]].z;
+
+                                                       decaltexcoords[numdecals][1][0]=(placex-where.y)/(size)/2+.5;
+                                                       decaltexcoords[numdecals][1][1]=(placez-where.z)/(size)/2+.5;
+
+                                                       decalvertex[numdecals][1].x=vertex[Triangles[i].vertex[1]].x;
+                                                       decalvertex[numdecals][1].z=placez;
+                                                       decalvertex[numdecals][1].y=placex;
+
+
+                                                       placex=vertex[Triangles[i].vertex[2]].y;
+                                                       placez=vertex[Triangles[i].vertex[2]].z;
+
+                                                       decaltexcoords[numdecals][2][0]=(placex-where.y)/(size)/2+.5;
+                                                       decaltexcoords[numdecals][2][1]=(placez-where.z)/(size)/2+.5;
+
+                                                       decalvertex[numdecals][2].x=vertex[Triangles[i].vertex[2]].x;
+                                                       decalvertex[numdecals][2].z=placez;
+                                                       decalvertex[numdecals][2].y=placex;
+
+                                                       if(!(decaltexcoords[numdecals][0][0]<0&&decaltexcoords[numdecals][1][0]<0&&decaltexcoords[numdecals][2][0]<0))
+                                                               if(!(decaltexcoords[numdecals][0][1]<0&&decaltexcoords[numdecals][1][1]<0&&decaltexcoords[numdecals][2][1]<0))
+                                                                       if(!(decaltexcoords[numdecals][0][0]>1&&decaltexcoords[numdecals][1][0]>1&&decaltexcoords[numdecals][2][0]>1))
+                                                                               if(!(decaltexcoords[numdecals][0][1]>1&&decaltexcoords[numdecals][1][1]>1&&decaltexcoords[numdecals][2][1]>1))
+                                                                               {
+                                                                                       if(decalrotation[numdecals]){
+                                                                                               for(j=0;j<3;j++){                       
+                                                                                                       rot.y=0;
+                                                                                                       rot.x=decaltexcoords[numdecals][j][0]-.5;
+                                                                                                       rot.z=decaltexcoords[numdecals][j][1]-.5;
+                                                                                                       rot=DoRotation(rot,0,-decalrotation[numdecals],0);
+                                                                                                       decaltexcoords[numdecals][j][0]=rot.x+.5;
+                                                                                                       decaltexcoords[numdecals][j][1]=rot.z+.5;
+                                                                                               }
+                                                                                       }
+                                                                                       if(numdecals<max_model_decals-1)numdecals++;
+                                                                               }
+                                               }
+                                       }
+                                       else if(distance<.02&&abs(facenormals[i].z)>abs(facenormals[i].y)&&abs(facenormals[i].z)>abs(facenormals[i].x)){
+                                               decalposition[numdecals]=where;
+                                               decaltype[numdecals]=atype;
+                                               decalrotation[numdecals]=rotation;
+                                               decalalivetime[numdecals]=0;
+                                               decalopacity[numdecals]=opacity-distance/10;
+
+                                               if(decalopacity[numdecals>0]){
+                                                       placex=vertex[Triangles[i].vertex[0]].x;
+                                                       placez=vertex[Triangles[i].vertex[0]].y;
+
+                                                       decaltexcoords[numdecals][0][0]=(placex-where.x)/(size)/2+.5;
+                                                       decaltexcoords[numdecals][0][1]=(placez-where.y)/(size)/2+.5;
+
+                                                       decalvertex[numdecals][0].x=placex;
+                                                       decalvertex[numdecals][0].z=vertex[Triangles[i].vertex[0]].z;
+                                                       decalvertex[numdecals][0].y=placez;
+
+
+                                                       placex=vertex[Triangles[i].vertex[1]].x;
+                                                       placez=vertex[Triangles[i].vertex[1]].y;
+
+                                                       decaltexcoords[numdecals][1][0]=(placex-where.x)/(size)/2+.5;
+                                                       decaltexcoords[numdecals][1][1]=(placez-where.y)/(size)/2+.5;
+
+                                                       decalvertex[numdecals][1].x=placex;
+                                                       decalvertex[numdecals][1].z=vertex[Triangles[i].vertex[1]].z;
+                                                       decalvertex[numdecals][1].y=placez;
+
+
+                                                       placex=vertex[Triangles[i].vertex[2]].x;
+                                                       placez=vertex[Triangles[i].vertex[2]].y;
+
+                                                       decaltexcoords[numdecals][2][0]=(placex-where.x)/(size)/2+.5;
+                                                       decaltexcoords[numdecals][2][1]=(placez-where.y)/(size)/2+.5;
+
+                                                       decalvertex[numdecals][2].x=placex;
+                                                       decalvertex[numdecals][2].z=vertex[Triangles[i].vertex[2]].z;
+                                                       decalvertex[numdecals][2].y=placez;
+
+                                                       if(!(decaltexcoords[numdecals][0][0]<0&&decaltexcoords[numdecals][1][0]<0&&decaltexcoords[numdecals][2][0]<0))
+                                                               if(!(decaltexcoords[numdecals][0][1]<0&&decaltexcoords[numdecals][1][1]<0&&decaltexcoords[numdecals][2][1]<0))
+                                                                       if(!(decaltexcoords[numdecals][0][0]>1&&decaltexcoords[numdecals][1][0]>1&&decaltexcoords[numdecals][2][0]>1))
+                                                                               if(!(decaltexcoords[numdecals][0][1]>1&&decaltexcoords[numdecals][1][1]>1&&decaltexcoords[numdecals][2][1]>1))
+                                                                               {
+                                                                                       if(decalrotation[numdecals]){
+                                                                                               for(j=0;j<3;j++){                       
+                                                                                                       rot.y=0;
+                                                                                                       rot.x=decaltexcoords[numdecals][j][0]-.5;
+                                                                                                       rot.z=decaltexcoords[numdecals][j][1]-.5;
+                                                                                                       rot=DoRotation(rot,0,-decalrotation[numdecals],0);
+                                                                                                       decaltexcoords[numdecals][j][0]=rot.x+.5;
+                                                                                                       decaltexcoords[numdecals][j][1]=rot.z+.5;
+                                                                                               }
+                                                                                       }
+                                                                                       if(numdecals<max_model_decals-1)numdecals++;
+                                                                               }
+                                               }
+                                       }
+                               }
+       }
+}
+
+Model::~Model()
+{
+       deallocate();
+
+       if(textureptr) glDeleteTextures( 1, &textureptr );
+}
+
+void Model::deallocate()
+{
+       int i = 0, j = 0;
+
+       if(owner)dealloc(owner);
+       owner = 0;
+
+       if(possible)dealloc(possible);
+       possible = 0;
+
+       if(vertex)dealloc(vertex);
+       vertex = 0;
+
+       if(normals)dealloc(normals);
+       normals = 0;
+
+       if(facenormals)dealloc(facenormals);
+       facenormals = 0;
+
+       if(Triangles)dealloc(Triangles);
+       Triangles = 0;
+
+       if(vArray)dealloc(vArray);
+       vArray = 0;
+
+
+       //allow decals
+       if(decaltexcoords)
+       {
+               for(i=0;i<max_model_decals;i++)
+               {
+                       for(j=0;j<3;j++)
+                       {
+                               dealloc(decaltexcoords[i][j]);
+                       }
+                       dealloc(decaltexcoords[i]);
+               }
+               dealloc(decaltexcoords);
+       }
+       decaltexcoords = 0;
+
+
+       if (decalvertex)
+       {
+               for(i=0;i<max_model_decals;i++)
+               {
+                       dealloc(decalvertex[i]);
+               }
+               dealloc(decalvertex);
+       }
+       decalvertex = 0;
+
+
+       dealloc(decaltype);
+       decaltype = 0;
+
+       dealloc(decalopacity);
+       decalopacity = 0;
+
+       dealloc(decalrotation);
+       decalrotation = 0;
+
+       dealloc(decalalivetime);
+       decalalivetime = 0;
+
+       dealloc(decalposition);
+       decalposition = 0;
+
+};
+
+Model::Model()
+{
+       vertexNum = 0,TriangleNum = 0;
+       hastexture = 0;
+
+       type = 0,oldtype = 0;
+
+       possible=0;
+       owner=0;
+       vertex=0;
+       normals=0;
+       facenormals=0;
+       Triangles=0;
+       vArray=0;
+
+       textureptr = 0;
+       memset(&Texture, 0, sizeof(Texture));
+       numpossible = 0;
+       color = 0;
+
+       boundingspherecenter = 0;
+       boundingsphereradius = 0;
+
+       decaltexcoords=0;
+       decalvertex=0;
+       decaltype=0;
+       decalopacity=0;
+       decalrotation=0;
+       decalalivetime=0;
+       decalposition=0;
+
+       numdecals = 0;
+
+       flat = 0;
+
+       type=nothing;
+}
diff --git a/Source/Models.h b/Source/Models.h
new file mode 100644 (file)
index 0000000..2f1da97
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef _MODELS_H_
+#define _MODELS_H_
+
+/**> Model Loading <**/
+//
+// Model Maximums
+//
+#include "gl.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <vector>
+
+#include "Constants.h"
+#include "Terrain.h"
+#include "binio.h"
+#include "Quaternions.h"
+
+//
+// Textures List
+//
+typedef struct         {
+       long                    xsz,ysz;
+       GLubyte                         *txt;
+} ModelTexture;
+
+//
+// Model Structures
+//
+
+class TexturedTriangle{
+public:
+       short                   vertex[3];
+       float gx[3],gy[3];
+};
+
+#define max_model_decals 300
+
+#define nothing 0
+#define normaltype 4
+#define notextype 1
+#define rawtype 2
+#define decalstype 3
+
+class Model{
+public:
+       short   vertexNum,TriangleNum;
+       bool hastexture;
+
+       int type,oldtype;
+
+       int* possible;
+       int* owner;
+       XYZ* vertex;
+       XYZ* normals;
+       XYZ* facenormals;
+       TexturedTriangle* Triangles;
+       GLfloat* vArray;
+
+       /*int possible[max_model_vertex];
+       int owner[max_textured_triangle];
+       XYZ vertex[max_model_vertex];
+       XYZ normals[max_model_vertex];
+       XYZ facenormals[max_textured_triangle];
+       TexturedTriangle Triangles[max_textured_triangle];
+       GLfloat vArray[max_textured_triangle*24];*/
+
+       GLuint                          textureptr;
+       ModelTexture            Texture;
+       int numpossible;
+       bool color;
+
+       XYZ boundingspherecenter;
+       float boundingsphereradius;
+
+       float*** decaltexcoords;
+       XYZ** decalvertex;
+       int* decaltype;
+       float* decalopacity;
+       float* decalrotation;
+       float* decalalivetime;
+       XYZ* decalposition;
+
+       /*float decaltexcoords[max_model_decals][3][2];
+       XYZ decalvertex[max_model_decals][3];
+       int decaltype[max_model_decals];
+       float decalopacity[max_model_decals];
+       float decalrotation[max_model_decals];
+       float decalalivetime[max_model_decals];
+       XYZ decalposition[max_model_decals];*/
+
+       int numdecals;
+
+       bool flat;
+
+       void DeleteDecal(int which);
+       void MakeDecal(int atype, XYZ *where, float *size, float *opacity, float *rotation);
+       void MakeDecal(int atype, XYZ where, float size, float opacity, float rotation);
+       void drawdecals(GLuint shadowtexture,GLuint bloodtexture,GLuint bloodtexture2,GLuint breaktexture);
+       int SphereCheck(XYZ *p1,float radius, XYZ *p, XYZ *move, float *rotate);
+       int SphereCheckPossible(XYZ *p1,float radius, XYZ *move, float *rotate);
+       int LineCheck(XYZ *p1,XYZ *p2, XYZ *p, XYZ *move, float *rotate);
+       int LineCheckSlide(XYZ *p1,XYZ *p2, XYZ *p, XYZ *move, float *rotate);
+       int LineCheckPossible(XYZ *p1,XYZ *p2, XYZ *p, XYZ *move, float *rotate);
+       int LineCheckSlidePossible(XYZ *p1,XYZ *p2, XYZ *p, XYZ *move, float *rotate);
+       void UpdateVertexArray();
+       void UpdateVertexArrayNoTex();
+       void UpdateVertexArrayNoTexNoNorm();
+       bool loadnotex(char *filename);
+       bool loadraw(char *filename);
+       bool load(char *filename,bool texture);
+       bool loaddecal(char *filename,bool texture);
+       void Scale(float xscale,float yscale,float zscale);
+       void FlipTexCoords();
+       void UniformTexCoords();
+       void ScaleTexCoords(float howmuch);
+       void ScaleNormals(float xscale,float yscale,float zscale);
+       void Translate(float xtrans,float ytrans,float ztrans);
+       void CalculateNormals(bool facenormalise);
+       void draw();
+       void drawdifftex(GLuint texture);
+       void drawimmediate();
+       void drawdiffteximmediate(GLuint texture);
+       void Rotate(float xang,float yang,float zang);
+       ~Model();
+       void deallocate();
+       Model();
+};
+
+#endif
\ No newline at end of file
diff --git a/Source/MoreFilesX.c b/Source/MoreFilesX.c
new file mode 100644 (file)
index 0000000..617f492
--- /dev/null
@@ -0,0 +1,2770 @@
+/*
+       File:           MoreFilesX.c
+
+       Contains:       A collection of useful high-level File Manager routines
+                               which use the HFS Plus APIs wherever possible.
+
+       Version:        MoreFilesX 1.0.1
+
+       Copyright:      Â© 1992-2002 by Apple Computer, Inc., all rights reserved.
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                               ("Apple") in consideration of your agreement to the following terms, and your
+                               use, installation, modification or redistribution of this Apple software
+                               constitutes acceptance of these terms.  If you do not agree with these terms,
+                               please do not use, install, modify or redistribute this Apple software.
+
+                               In consideration of your agreement to abide by the following terms, and subject
+                               to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+                               copyrights in this original Apple software (the "Apple Software"), to use,
+                               reproduce, modify and redistribute the Apple Software, with or without
+                               modifications, in source and/or binary forms; provided that if you redistribute
+                               the Apple Software in its entirety and without modifications, you must retain
+                               this notice and the following text and disclaimers in all such redistributions of
+                               the Apple Software.  Neither the name, trademarks, service marks or logos of
+                               Apple Computer, Inc. may be used to endorse or promote products derived from the
+                               Apple Software without specific prior written permission from Apple.  Except as
+                               expressly stated in this notice, no other rights or licenses, express or implied,
+                               are granted by Apple herein, including but not limited to any patent rights that
+                               may be infringed by your derivative works or by other works in which the Apple
+                               Software may be incorporated.
+
+                               The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                               WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                               WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                               PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                               COMBINATION WITH YOUR PRODUCTS.
+
+                               IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                               CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                               GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                               ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                               OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                               (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                               ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+       File Ownership:
+
+               DRI:                            Apple Macintosh Developer Technical Support
+
+               Other Contact:          For bug reports, consult the following page on
+                                                       the World Wide Web:
+                                                               http://developer.apple.com/bugreporter/
+
+               Technology:                     DTS Sample Code
+
+       Writers:
+
+               (JL)    Jim Luther
+
+       Change History (most recent first):
+
+                <4>     8/22/02        JL              [3016251]  Changed FSMoveRenameObjectUnicode to not use
+                                                                       the Temporary folder because it isn't available on
+                                                                       NFS volumes.
+                <3>     4/19/02        JL              [2853905]  Fixed #if test around header includes.
+                <2>     4/19/02        JL              [2850624]  Fixed C++ compile errors and Project Builder
+                                                                       warnings.
+                <2>     4/19/02        JL              [2853901]  Updated standard disclaimer.
+                <1>     1/25/02        JL              MoreFilesX 1.0
+*/
+
+#if defined(__MACH__)
+       #include <Carbon/Carbon.h>
+       #include <string.h>
+#else
+       #include <Carbon.h>
+       #include <string.h>
+#endif
+
+#include "MoreFilesX.h"
+
+/* Set BuildingMoreFilesXForMacOS9 to 1 if building for Mac OS 9 */
+#ifndef BuildingMoreFilesXForMacOS9
+       #define BuildingMoreFilesXForMacOS9 0
+#endif
+
+/*****************************************************************************/
+
+#pragma mark ----- Local type definitions -----
+
+struct FSIterateContainerGlobals
+{
+       IterateContainerFilterProcPtr   iterateFilter;  /* pointer to IterateFilterProc */
+       FSCatalogInfoBitmap                             whichInfo;              /* fields of the CatalogInfo to get */
+       FSCatalogInfo                                   catalogInfo;    /* FSCatalogInfo */
+       FSRef                                                   ref;                    /* FSRef */
+       FSSpec                                                  spec;                   /* FSSpec */
+       FSSpec                                                  *specPtr;               /* pointer to spec field, or NULL */
+       HFSUniStr255                                    name;                   /* HFSUniStr255 */
+       HFSUniStr255                                    *namePtr;               /* pointer to name field, or NULL */
+       void                                                    *yourDataPtr;   /* a pointer to caller supplied data the filter may need to access */
+       ItemCount                                               maxLevels;              /* maximum levels to iterate through */
+       ItemCount                                               currentLevel;   /* the current level FSIterateContainerLevel is on */
+       Boolean                                                 quitFlag;               /* set to true if filter wants to kill interation */
+       Boolean                                                 containerChanged; /* temporary - set to true if the current container changed during iteration */
+       OSErr                                                   result;                 /* result */
+       ItemCount                                               actualObjects;  /* number of objects returned */
+};
+typedef struct FSIterateContainerGlobals FSIterateContainerGlobals;
+
+struct FSDeleteContainerGlobals
+{
+       OSErr                                                   result;                 /* result */
+       ItemCount                                               actualObjects;  /* number of objects returned */
+       FSCatalogInfo                                   catalogInfo;    /* FSCatalogInfo */
+};
+typedef struct FSDeleteContainerGlobals FSDeleteContainerGlobals;
+
+/*****************************************************************************/
+
+#pragma mark ----- Local prototypes -----
+
+static
+void
+FSDeleteContainerLevel(
+       const FSRef *container,
+       FSDeleteContainerGlobals *theGlobals);
+
+static
+void
+FSIterateContainerLevel(
+       FSIterateContainerGlobals *theGlobals);
+
+static
+OSErr
+GenerateUniqueHFSUniStr(
+       long *startSeed,
+       const FSRef *dir1,
+       const FSRef *dir2,
+       HFSUniStr255 *uniqueName);
+
+/*****************************************************************************/
+
+#pragma mark ----- File Access Routines -----
+
+/*****************************************************************************/
+
+OSErr
+FSCopyFork(
+       SInt16 srcRefNum,
+       SInt16 dstRefNum,
+       void *copyBufferPtr,
+       ByteCount copyBufferSize)
+{
+       OSErr           srcResult;
+       OSErr           dstResult;
+       OSErr           result;
+       SInt64          forkSize;
+       ByteCount       readActualCount;
+       
+       /* check input parameters */
+       require_action((NULL != copyBufferPtr) && (0 != copyBufferSize), BadParameter, result = paramErr);
+       
+       /* get source fork size */
+       result = FSGetForkSize(srcRefNum, &forkSize);
+       require_noerr(result, SourceFSGetForkSizeFailed);
+       
+       /* allocate disk space for destination fork */
+       result = FSSetForkSize(dstRefNum, fsFromStart, forkSize);
+       require_noerr(result, DestinationFSSetForkSizeFailed);
+       
+       /* reset source fork's position to 0 */
+       result = FSSetForkPosition(srcRefNum, fsFromStart, 0);
+       require_noerr(result, SourceFSSetForkPositionFailed);
+       
+       /* reset destination fork's position to 0 */
+       result = FSSetForkPosition(dstRefNum, fsFromStart, 0);
+       require_noerr(result, DestinationFSSetForkPositionFailed);
+
+       /* If copyBufferSize is greater than 4K bytes, make it a multiple of 4k bytes */
+       /* This will make writes on local volumes faster */
+       if ( (copyBufferSize >= 0x00001000) && ((copyBufferSize & 0x00000fff) != 0) )
+       {
+               copyBufferSize &= ~(0x00001000 - 1);
+       }
+       
+       /* copy source to destination */
+       srcResult = dstResult = noErr;
+       while ( (noErr == srcResult) && (noErr == dstResult) )
+       {
+               srcResult = FSReadFork(srcRefNum, fsAtMark + noCacheMask, 0, copyBufferSize, copyBufferPtr, &readActualCount);
+               dstResult = FSWriteFork(dstRefNum, fsAtMark + noCacheMask, 0, readActualCount, copyBufferPtr, NULL);
+       }
+       
+       /* make sure there were no errors at the destination */
+       require_noerr_action(dstResult, DestinationFSWriteForkFailed, result = dstResult);
+       
+       /* make sure the error at the source was eofErr */
+       require_action(eofErr == srcResult, SourceResultNotEofErr, result = srcResult);
+       
+       /* everything went as expected */
+       result = noErr;
+
+SourceResultNotEofErr:
+DestinationFSWriteForkFailed:
+DestinationFSSetForkPositionFailed:
+SourceFSSetForkPositionFailed:
+DestinationFSSetForkSizeFailed:
+SourceFSGetForkSizeFailed:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Volume Access Routines -----
+
+/*****************************************************************************/ 
+
+OSErr
+FSGetVolParms(
+       FSVolumeRefNum volRefNum,
+       UInt32 bufferSize,
+       GetVolParmsInfoBuffer *volParmsInfo,
+       UInt32 *actualInfoSize)
+{
+       OSErr                   result;
+       HParamBlockRec  pb;
+       
+       /* check parameters */
+       require_action((NULL != volParmsInfo) && (NULL != actualInfoSize),
+               BadParameter, result = paramErr);
+       
+       pb.ioParam.ioNamePtr = NULL;
+       pb.ioParam.ioVRefNum = volRefNum;
+       pb.ioParam.ioBuffer = (Ptr)volParmsInfo;
+       pb.ioParam.ioReqCount = (SInt32)bufferSize;
+       result = PBHGetVolParmsSync(&pb);
+       require_noerr(result, PBHGetVolParmsSync);
+       
+       /* return number of bytes the file system returned in volParmsInfo buffer */
+       *actualInfoSize = (UInt32)pb.ioParam.ioActCount;
+       
+PBHGetVolParmsSync:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVRefNum(
+       const FSRef *ref,
+       FSVolumeRefNum *vRefNum)
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       
+       /* check parameters */
+       require_action(NULL != vRefNum, BadParameter, result = paramErr);
+       
+       /* get the volume refNum from the FSRef */
+       result = FSGetCatalogInfo(ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* return volume refNum from catalogInfo */
+       *vRefNum = catalogInfo.volume;
+       
+FSGetCatalogInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVInfo(
+       FSVolumeRefNum volume,
+       HFSUniStr255 *volumeName,       /* can be NULL */
+       UInt64 *freeBytes,                      /* can be NULL */
+       UInt64 *totalBytes)                     /* can be NULL */
+{
+       OSErr                           result;
+       FSVolumeInfo            info;
+       
+       /* ask for the volume's sizes only if needed */
+       result = FSGetVolumeInfo(volume, 0, NULL,
+               (((NULL != freeBytes) || (NULL != totalBytes)) ? kFSVolInfoSizes : kFSVolInfoNone),
+               &info, volumeName, NULL);
+       require_noerr(result, FSGetVolumeInfo);
+       
+       if ( NULL != freeBytes )
+       {
+               *freeBytes = info.freeBytes;
+       }
+       if ( NULL != totalBytes )
+       {
+               *totalBytes = info.totalBytes;
+       }
+       
+FSGetVolumeInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVolFileSystemID(
+       FSVolumeRefNum volume,
+       UInt16 *fileSystemID,   /* can be NULL */
+       UInt16 *signature)              /* can be NULL */
+{
+       OSErr                   result;
+       FSVolumeInfo    info;
+       
+       result = FSGetVolumeInfo(volume, 0, NULL, kFSVolInfoFSInfo, &info, NULL, NULL);
+       require_noerr(result, FSGetVolumeInfo);
+       
+       if ( NULL != fileSystemID )
+       {
+               *fileSystemID = info.filesystemID;
+       }
+       if ( NULL != signature )
+       {
+               *signature = info.signature;
+       }
+       
+FSGetVolumeInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetMountedVolumes(
+       FSRef ***volumeRefsHandle,      /* pointer to handle of FSRefs */
+       ItemCount *numVolumes)
+{
+       OSErr           result;
+       OSErr           memResult;
+       ItemCount       volumeIndex;
+       FSRef           ref;
+       
+       /* check parameters */
+       require_action((NULL != volumeRefsHandle) && (NULL != numVolumes),
+               BadParameter, result = paramErr);
+       
+       /* No volumes yet */
+       *numVolumes = 0;
+       
+       /* Allocate a handle for the results */
+       *volumeRefsHandle = (FSRef **)NewHandle(0);
+       require_action(NULL != *volumeRefsHandle, NewHandle, result = memFullErr);
+       
+       /* Call FSGetVolumeInfo in loop to get all volumes starting with the first */
+       volumeIndex = 1;
+       do
+       {
+               result = FSGetVolumeInfo(0, volumeIndex, NULL, kFSVolInfoNone, NULL, NULL, &ref);
+               if ( noErr == result )
+               {
+                       /* concatenate the FSRef to the end of the handle */
+                       PtrAndHand(&ref, (Handle)*volumeRefsHandle, sizeof(FSRef));
+                       memResult = MemError();
+                       require_noerr_action(memResult, MemoryAllocationFailed, result = memResult);
+                       
+                       ++(*numVolumes);        /* increment the volume count */
+                       ++volumeIndex;          /* and the volumeIndex to get the next volume*/
+               }
+       } while ( noErr == result );
+       
+       /* nsvErr is OK -- it just means there are no more volumes */
+       require(nsvErr == result, FSGetVolumeInfo);
+               
+       return ( noErr );
+       
+       /**********************/
+       
+MemoryAllocationFailed:
+FSGetVolumeInfo:
+
+       /* dispose of handle if already allocated and clear the outputs */
+       if ( NULL != *volumeRefsHandle )
+       {
+               DisposeHandle((Handle)*volumeRefsHandle);
+               *volumeRefsHandle = NULL;
+       }
+       *numVolumes = 0;
+       
+NewHandle:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines -----
+
+/*****************************************************************************/
+
+OSErr
+FSRefMakeFSSpec(
+       const FSRef *ref,
+       FSSpec *spec)
+{
+       OSErr   result;
+       
+       /* check parameters */
+       require_action(NULL != spec, BadParameter, result = paramErr);
+       
+       result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+FSGetCatalogInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMakeFSRef(
+       FSVolumeRefNum volRefNum,
+       SInt32 dirID,
+       ConstStr255Param name,
+       FSRef *ref)
+{
+       OSErr           result;
+       FSRefParam      pb;
+       
+       /* check parameters */
+       require_action(NULL != ref, BadParameter, result = paramErr);
+       
+       pb.ioVRefNum = volRefNum;
+       pb.ioDirID = dirID;
+       pb.ioNamePtr = (StringPtr)name;
+       pb.newRef = ref;
+       result = PBMakeFSRefSync(&pb);
+       require_noerr(result, PBMakeFSRefSync);
+       
+PBMakeFSRefSync:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSStatus
+FSMakePath(
+       SInt16 volRefNum,
+       SInt32 dirID,
+       ConstStr255Param name,
+       UInt8 *path,
+       UInt32 maxPathSize)
+{
+       OSStatus        result;
+       FSRef           ref;
+       
+       /* check parameters */
+       require_action(NULL != path, BadParameter, result = paramErr);
+       
+       /* convert the inputs to an FSRef */
+       result = FSMakeFSRef(volRefNum, dirID, name, &ref);
+       require_noerr(result, FSMakeFSRef);
+       
+       /* and then convert the FSRef to a path */
+       result = FSRefMakePath(&ref, path, maxPathSize);
+       require_noerr(result, FSRefMakePath);
+       
+FSRefMakePath:
+FSMakeFSRef:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSStatus
+FSPathMakeFSSpec(
+       const UInt8 *path,
+       FSSpec *spec,
+       Boolean *isDirectory)   /* can be NULL */
+{
+       OSStatus        result;
+       FSRef           ref;
+       
+       /* check parameters */
+       require_action(NULL != spec, BadParameter, result = paramErr);
+       
+       /* convert the POSIX path to an FSRef */
+       result = FSPathMakeRef(path, &ref, isDirectory);
+       require_noerr(result, FSPathMakeRef);
+       
+       /* and then convert the FSRef to an FSSpec */
+       result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+FSGetCatalogInfo:
+FSPathMakeRef:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+UnicodeNameGetHFSName(
+       UniCharCount nameLength,
+       const UniChar *name,
+       TextEncoding textEncodingHint,
+       Boolean isVolumeName,
+       Str31 hfsName)
+{
+       OSStatus                        result;
+       ByteCount                       unicodeByteLength;
+       ByteCount                       unicodeBytesConverted;
+       ByteCount                       actualPascalBytes;
+       UnicodeMapping          uMapping;
+       UnicodeToTextInfo       utInfo;
+       
+       /* check parameters */
+       require_action(NULL != hfsName, BadParameter, result = paramErr);
+       
+       /* make sure output is valid in case we get errors or there's nothing to convert */
+       hfsName[0] = 0;
+       
+       unicodeByteLength = nameLength * sizeof(UniChar);
+       if ( 0 == unicodeByteLength )
+       {
+               /* do nothing */
+               result = noErr;
+       }
+       else
+       {
+               /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
+               if ( kTextEncodingUnknown == textEncodingHint )
+               {
+                       ScriptCode                      script;
+                       RegionCode                      region;
+                       
+                       script = (ScriptCode)GetScriptManagerVariable(smSysScript);
+                       region = (RegionCode)GetScriptManagerVariable(smRegionCode);
+                       result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region,
+                               NULL, &textEncodingHint );
+                       if ( paramErr == result )
+                       {
+                               /* ok, ignore the region and try again */
+                               result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
+                                       kTextRegionDontCare, NULL, &textEncodingHint );
+                       }
+                       if ( noErr != result )
+                       {
+                               /* ok... try something */
+                               textEncodingHint = kTextEncodingMacRoman;
+                       }
+               }
+               
+               uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0,
+                       kUnicodeCanonicalDecompVariant, kUnicode16BitFormat);
+               uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint);
+               uMapping.mappingVersion = kUnicodeUseHFSPlusMapping;
+       
+               result = CreateUnicodeToTextInfo(&uMapping, &utInfo);
+               require_noerr(result, CreateUnicodeToTextInfo);
+               
+               result = ConvertFromUnicodeToText(utInfo, unicodeByteLength, name, kUnicodeLooseMappingsMask,
+                       0, NULL, 0, NULL,       /* offsetCounts & offsetArrays */
+                       isVolumeName ? kHFSMaxVolumeNameChars : kHFSMaxFileNameChars,
+                       &unicodeBytesConverted, &actualPascalBytes, &hfsName[1]);
+               require_noerr(result, ConvertFromUnicodeToText);
+               
+               hfsName[0] = (unsigned char)actualPascalBytes;  /* fill in length byte */
+
+ConvertFromUnicodeToText:
+               
+               /* verify the result in debug builds -- there's really not anything you can do if it fails */
+               verify_noerr(DisposeUnicodeToTextInfo(&utInfo));
+       }
+       
+CreateUnicodeToTextInfo:       
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+HFSNameGetUnicodeName(
+       ConstStr31Param hfsName,
+       TextEncoding textEncodingHint,
+       HFSUniStr255 *unicodeName)
+{
+       ByteCount                       unicodeByteLength;
+       OSStatus                        result;
+       UnicodeMapping          uMapping;
+       TextToUnicodeInfo       tuInfo;
+       ByteCount                       pascalCharsRead;
+       
+       /* check parameters */
+       require_action(NULL != unicodeName, BadParameter, result = paramErr);
+       
+       /* make sure output is valid in case we get errors or there's nothing to convert */
+       unicodeName->length = 0;
+       
+       if ( 0 == StrLength(hfsName) )
+       {
+               result = noErr;
+       }
+       else
+       {
+               /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
+               if ( kTextEncodingUnknown == textEncodingHint )
+               {
+                       ScriptCode                      script;
+                       RegionCode                      region;
+                       
+                       script = GetScriptManagerVariable(smSysScript);
+                       region = GetScriptManagerVariable(smRegionCode);
+                       result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region,
+                               NULL, &textEncodingHint);
+                       if ( paramErr == result )
+                       {
+                               /* ok, ignore the region and try again */
+                               result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
+                                       kTextRegionDontCare, NULL, &textEncodingHint);
+                       }
+                       if ( noErr != result )
+                       {
+                               /* ok... try something */
+                               textEncodingHint = kTextEncodingMacRoman;
+                       }
+               }
+               
+               uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0,
+                       kUnicodeCanonicalDecompVariant, kUnicode16BitFormat);
+               uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint);
+               uMapping.mappingVersion = kUnicodeUseHFSPlusMapping;
+       
+               result = CreateTextToUnicodeInfo(&uMapping, &tuInfo);
+               require_noerr(result, CreateTextToUnicodeInfo);
+                       
+               result = ConvertFromTextToUnicode(tuInfo, hfsName[0], &hfsName[1],
+                       0,                                                              /* no control flag bits */
+                       0, NULL, 0, NULL,                               /* offsetCounts & offsetArrays */
+                       sizeof(unicodeName->unicode),   /* output buffer size in bytes */
+                       &pascalCharsRead, &unicodeByteLength, unicodeName->unicode);
+               require_noerr(result, ConvertFromTextToUnicode);
+               
+               /* convert from byte count to char count */
+               unicodeName->length = unicodeByteLength / sizeof(UniChar);
+
+ConvertFromTextToUnicode:
+
+               /* verify the result in debug builds -- there's really not anything you can do if it fails */
+               verify_noerr(DisposeTextToUnicodeInfo(&tuInfo));
+       }
+       
+CreateTextToUnicodeInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- File/Directory Manipulation Routines -----
+
+/*****************************************************************************/
+
+Boolean FSRefValid(const FSRef *ref)
+{
+       return ( noErr == FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, NULL, NULL) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetParentRef(
+       const FSRef *ref,
+       FSRef *parentRef)
+{
+       OSErr   result;
+       FSCatalogInfo   catalogInfo;
+       
+       /* check parameters */
+       require_action(NULL != parentRef, BadParameter, result = paramErr);
+       
+       result = FSGetCatalogInfo(ref, kFSCatInfoNodeID, &catalogInfo, NULL, NULL, parentRef);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /*
+        * Note: FSRefs always point to real file system objects. So, there cannot
+        * be a FSRef to the parent of volume root directories. Early versions of
+        * Mac OS X do not handle this case correctly and incorrectly return a
+        * FSRef for the parent of volume root directories instead of returning an
+        * invalid FSRef (a cleared FSRef is invalid). The next three lines of code
+        * ensure that you won't run into this bug. WW9D!
+        */
+       if ( fsRtDirID == catalogInfo.nodeID )
+       {
+               /* clear parentRef and return noErr which is the proper behavior */
+               memset(parentRef, 0, sizeof(FSRef));
+       }
+
+FSGetCatalogInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetFileDirName(
+       const FSRef *ref,
+       HFSUniStr255 *outName)
+{
+       OSErr   result;
+       
+       /* check parameters */
+       require_action(NULL != outName, BadParameter, result = paramErr);
+       
+       result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, outName, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+FSGetCatalogInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetNodeID(
+       const FSRef *ref,
+       long *nodeID,                   /* can be NULL */
+       Boolean *isDirectory)   /* can be NULL */
+{
+       OSErr                           result;
+       FSCatalogInfo           catalogInfo;
+       FSCatalogInfoBitmap whichInfo;
+       
+       /* determine what catalog information to get */
+       whichInfo = kFSCatInfoNone; /* start with none */
+       if ( NULL != nodeID )
+       {
+               whichInfo |= kFSCatInfoNodeID;
+       }
+       if ( NULL != isDirectory )
+       {
+               whichInfo |= kFSCatInfoNodeFlags;
+       }
+       
+       result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       if ( NULL != nodeID )
+       {
+               *nodeID = catalogInfo.nodeID;
+       }
+       if ( NULL != isDirectory )
+       {
+               *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags));
+       }
+       
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetUserPrivilegesPermissions(
+       const FSRef *ref,
+       UInt8 *userPrivileges,          /* can be NULL */
+       UInt32 permissions[4])          /* can be NULL */
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       FSCatalogInfoBitmap whichInfo;
+       
+       /* determine what catalog information to get */
+       whichInfo = kFSCatInfoNone; /* start with none */
+       if ( NULL != userPrivileges )
+       {
+               whichInfo |= kFSCatInfoUserPrivs;
+       }
+       if ( NULL != permissions )
+       {
+               whichInfo |= kFSCatInfoPermissions;
+       }
+       
+       result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       if ( NULL != userPrivileges )
+       {
+               *userPrivileges = catalogInfo.userPrivileges;
+       }
+       if ( NULL != permissions )
+       {
+               BlockMoveData(&catalogInfo.permissions, permissions, sizeof(UInt32) * 4);
+       }
+       
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSCheckLock(
+       const FSRef *ref)
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       FSVolumeInfo    volumeInfo;
+       
+       /* get nodeFlags and vRefNum for container */
+       result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoVolume, &catalogInfo, NULL, NULL,NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* is file locked? */
+       if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) )
+       {
+               result = fLckdErr;      /* file is locked */
+       }
+       else
+       {
+               /* file isn't locked, but is volume locked? */
+               
+               /* get volume flags */
+               result = FSGetVolumeInfo(catalogInfo.volume, 0, NULL, kFSVolInfoFlags, &volumeInfo, NULL, NULL);
+               require_noerr(result, FSGetVolumeInfo);
+               
+               if ( 0 != (volumeInfo.flags & kFSVolFlagHardwareLockedMask) )
+               {
+                       result = wPrErr;        /* volume locked by hardware */
+               }
+               else if ( 0 != (volumeInfo.flags & kFSVolFlagSoftwareLockedMask) )
+               {
+                       result = vLckdErr;      /* volume locked by software */
+               }
+       }
+       
+FSGetVolumeInfo:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetForkSizes(
+       const FSRef *ref,
+       UInt64 *dataLogicalSize,        /* can be NULL */
+       UInt64 *rsrcLogicalSize)        /* can be NULL */
+{
+       OSErr                           result;
+       FSCatalogInfoBitmap whichInfo;
+       FSCatalogInfo           catalogInfo;
+       
+       whichInfo = kFSCatInfoNodeFlags;
+       if ( NULL != dataLogicalSize )
+       {
+               /* get data fork size */
+               whichInfo |= kFSCatInfoDataSizes;
+       }
+       if ( NULL != rsrcLogicalSize )
+       {
+               /* get resource fork size */
+               whichInfo |= kFSCatInfoRsrcSizes;
+       }
+
+       /* get nodeFlags and catalog info */
+       result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL,NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* make sure FSRef was to a file */
+       require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr);
+       
+       if ( NULL != dataLogicalSize )
+       {
+               /* return data fork size */
+               *dataLogicalSize = catalogInfo.dataLogicalSize;
+       }
+       if ( NULL != rsrcLogicalSize )
+       {
+               /* return resource fork size */
+               *rsrcLogicalSize = catalogInfo.rsrcLogicalSize;
+       }
+       
+FSRefNotFile:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetTotalForkSizes(
+       const FSRef *ref,
+       UInt64 *totalLogicalSize,       /* can be NULL */
+       UInt64 *totalPhysicalSize,      /* can be NULL */
+       ItemCount *forkCount)           /* can be NULL */
+{
+       OSErr                   result;
+       CatPositionRec  forkIterator;
+       SInt64                  forkSize;
+       SInt64                  *forkSizePtr;
+       UInt64                  forkPhysicalSize;
+       UInt64                  *forkPhysicalSizePtr;
+       
+       /* Determine if forkSize needed */
+       if ( NULL != totalLogicalSize)
+       {
+               *totalLogicalSize = 0;
+               forkSizePtr = &forkSize;
+       }
+       else
+       {
+               forkSizePtr = NULL;
+       }
+       
+       /* Determine if forkPhysicalSize is needed */
+       if ( NULL != totalPhysicalSize )
+       {
+               *totalPhysicalSize = 0;
+               forkPhysicalSizePtr = &forkPhysicalSize;
+       }
+       else
+       {
+               forkPhysicalSizePtr = NULL;
+       }
+       
+       /* zero fork count if returning it */
+       if ( NULL != forkCount )
+       {
+               *forkCount = 0;
+       }
+       
+       /* Iterate through the forks to get the sizes */
+       forkIterator.initialize = 0;
+       do
+       {
+               result = FSIterateForks(ref, &forkIterator, NULL, forkSizePtr, forkPhysicalSizePtr);
+               if ( noErr == result )
+               {
+                       if ( NULL != totalLogicalSize )
+                       {
+                               *totalLogicalSize += forkSize;
+                       }
+                       
+                       if ( NULL != totalPhysicalSize )
+                       {
+                               *totalPhysicalSize += forkPhysicalSize;
+                       }
+                       
+                       if ( NULL != forkCount )
+                       {
+                               ++*forkCount;
+                       }
+               }
+       } while ( noErr == result );
+       
+       /* any error result other than errFSNoMoreItems is serious */
+       require(errFSNoMoreItems == result, FSIterateForks);
+       
+       /* Normal exit */
+       result = noErr;
+
+FSIterateForks:
+       
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSBumpDate(
+       const FSRef *ref)
+{
+       OSStatus                result;
+       FSCatalogInfo   catalogInfo;
+       UTCDateTime             oldDateTime;
+#if !BuildingMoreFilesXForMacOS9
+       FSRef                   parentRef;
+       Boolean                 notifyParent;
+#endif
+
+#if !BuildingMoreFilesXForMacOS9
+       /* Get the node flags, the content modification date and time, and the parent ref */
+       result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoContentMod, &catalogInfo, NULL, NULL, &parentRef);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* Notify the parent if this is a file */
+       notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask));
+#else
+       /* Get the content modification date and time */
+       result = FSGetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+#endif
+       
+       oldDateTime = catalogInfo.contentModDate;
+
+       /* Get the current date and time */
+       result = GetUTCDateTime(&catalogInfo.contentModDate, kUTCDefaultOptions);
+       require_noerr(result, GetUTCDateTime);
+       
+       /* if the old date and time is the the same as the current, bump the seconds by one */
+       if ( (catalogInfo.contentModDate.fraction == oldDateTime.fraction) &&
+                (catalogInfo.contentModDate.lowSeconds == oldDateTime.lowSeconds) &&
+                (catalogInfo.contentModDate.highSeconds == oldDateTime.highSeconds) )
+       {
+               ++catalogInfo.contentModDate.lowSeconds;
+               if ( 0 == catalogInfo.contentModDate.lowSeconds )
+               {
+                       ++catalogInfo.contentModDate.highSeconds;
+               }
+       }
+       
+       /* Bump the content modification date and time */
+       result = FSSetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo);
+       require_noerr(result, FSSetCatalogInfo);
+
+#if !BuildingMoreFilesXForMacOS9
+       /*
+        * The problem with FNNotify is that it is not available under Mac OS 9
+        * and there's no way to test for that except for looking for the symbol
+        * or something. So, I'll just conditionalize this for those who care
+        * to send a notification.
+        */
+       
+       /* Send a notification for the parent of the file, or for the directory */
+       result = FNNotify(notifyParent ? &parentRef : ref, kFNDirectoryModifiedMessage, kNilOptions);
+       require_noerr(result, FNNotify);
+#endif
+
+       /* ignore errors from FSSetCatalogInfo (volume might be write protected) and FNNotify */
+FNNotify:
+FSSetCatalogInfo:
+       
+       return ( noErr );
+       
+       /**********************/
+       
+GetUTCDateTime:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetFinderInfo(
+       const FSRef *ref,
+       FinderInfo *info,                                       /* can be NULL */
+       ExtendedFinderInfo *extendedInfo,       /* can be NULL */
+       Boolean *isDirectory)                           /* can be NULL */
+{
+       OSErr                           result;
+       FSCatalogInfo           catalogInfo;
+       FSCatalogInfoBitmap whichInfo;
+       
+       /* determine what catalog information is really needed */
+       whichInfo = kFSCatInfoNone;
+       
+       if ( NULL != info )
+       {
+               /* get FinderInfo */
+               whichInfo |= kFSCatInfoFinderInfo;
+       }
+       
+       if ( NULL != extendedInfo )
+       {
+               /* get ExtendedFinderInfo */
+               whichInfo |= kFSCatInfoFinderXInfo;
+       }
+       
+       if ( NULL != isDirectory )
+       {
+               whichInfo |= kFSCatInfoNodeFlags;
+       }
+       
+       result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* return FinderInfo if requested */
+       if ( NULL != info )
+       {
+               BlockMoveData(catalogInfo.finderInfo, info, sizeof(FinderInfo));
+       }
+       
+       /* return ExtendedFinderInfo if requested */
+       if ( NULL != extendedInfo)
+       {
+               BlockMoveData(catalogInfo.extFinderInfo, extendedInfo, sizeof(ExtendedFinderInfo));
+       }
+       
+       /* set isDirectory Boolean if requested */
+       if ( NULL != isDirectory)
+       {
+               *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags));
+       }
+       
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetFinderInfo(
+       const FSRef *ref,
+       const FinderInfo *info,
+       const ExtendedFinderInfo *extendedInfo)
+{
+       OSErr                           result;
+       FSCatalogInfo           catalogInfo;
+       FSCatalogInfoBitmap whichInfo;
+       
+       /* determine what catalog information will be set */
+       whichInfo = kFSCatInfoNone; /* start with none */
+       if ( NULL != info )
+       {
+               /* set FinderInfo */
+               whichInfo |= kFSCatInfoFinderInfo;
+               BlockMoveData(info, catalogInfo.finderInfo, sizeof(FinderInfo));
+       }
+       if ( NULL != extendedInfo )
+       {
+               /* set ExtendedFinderInfo */
+               whichInfo |= kFSCatInfoFinderXInfo;
+               BlockMoveData(extendedInfo, catalogInfo.extFinderInfo, sizeof(ExtendedFinderInfo));
+       }
+       
+       result = FSSetCatalogInfo(ref, whichInfo, &catalogInfo);
+       require_noerr(result, FSGetCatalogInfo);
+       
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSChangeCreatorType(
+       const FSRef *ref,
+       OSType fileCreator,
+       OSType fileType)
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       FSRef                   parentRef;
+       
+       /* get nodeFlags, finder info, and parent FSRef */
+       result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo, &catalogInfo , NULL, NULL, &parentRef);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* make sure FSRef was to a file */
+       require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr);
+       
+       /* If fileType not 0x00000000, change fileType */
+       if ( fileType != (OSType)0x00000000 )
+       {
+               ((FileInfo *)&catalogInfo.finderInfo)->fileType = fileType;
+       }
+       
+       /* If creator not 0x00000000, change creator */
+       if ( fileCreator != (OSType)0x00000000 )
+       {
+               ((FileInfo *)&catalogInfo.finderInfo)->fileCreator = fileCreator;
+       }
+       
+       /* now, save the new information back to disk */
+       result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
+       require_noerr(result, FSSetCatalogInfo);
+       
+       /* and attempt to bump the parent directory's mod date to wake up */
+       /* the Finder to the change we just made (ignore errors from this) */
+       verify_noerr(FSBumpDate(&parentRef));
+       
+FSSetCatalogInfo:
+FSRefNotFile:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSChangeFinderFlags(
+       const FSRef *ref,
+       Boolean setBits,
+       UInt16 flagBits)
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       FSRef                   parentRef;
+       
+       /* get the current finderInfo */
+       result = FSGetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, &parentRef);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* set or clear the appropriate bits in the finderInfo.finderFlags */
+       if ( setBits )
+       {
+               /* OR in the bits */
+               ((FileInfo *)&catalogInfo.finderInfo)->finderFlags |= flagBits;
+       }
+       else
+       {
+               /* AND out the bits */
+               ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~flagBits;
+       }
+       
+       /* save the modified finderInfo */
+       result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
+       require_noerr(result, FSSetCatalogInfo);
+       
+       /* and attempt to bump the parent directory's mod date to wake up the Finder */
+       /* to the change we just made (ignore errors from this) */
+       verify_noerr(FSBumpDate(&parentRef));
+       
+FSSetCatalogInfo:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetInvisible(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, true, kIsInvisible) );
+}
+
+OSErr
+FSClearInvisible(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, false, kIsInvisible) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetNameLocked(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, true, kNameLocked) );
+}
+
+OSErr
+FSClearNameLocked(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, false, kNameLocked) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetIsStationery(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, true, kIsStationery) );
+}
+
+OSErr
+FSClearIsStationery(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, false, kIsStationery) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetHasCustomIcon(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, true, kHasCustomIcon) );
+}
+
+OSErr
+FSClearHasCustomIcon(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, false, kHasCustomIcon) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSClearHasBeenInited(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, false, kHasBeenInited) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSCopyFileMgrAttributes(
+       const FSRef *sourceRef,
+       const FSRef *destinationRef,
+       Boolean copyLockBit)
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       
+       /* get the source information */
+       result = FSGetCatalogInfo(sourceRef, kFSCatInfoSettableInfo, &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* don't copy the hasBeenInited bit; clear it */
+       ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~kHasBeenInited;
+       
+       /* should the locked bit be copied? */
+       if ( !copyLockBit )
+       {
+               /* no, make sure the locked bit is clear */
+               catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
+       }
+               
+       /* set the destination information */
+       result = FSSetCatalogInfo(destinationRef, kFSCatInfoSettableInfo, &catalogInfo);
+       require_noerr(result, FSSetCatalogInfo);
+       
+FSSetCatalogInfo:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMoveRenameObjectUnicode(
+       const FSRef *ref,
+       const FSRef *destDirectory,
+       UniCharCount nameLength,
+       const UniChar *name,                    /* can be NULL (no rename during move) */
+       TextEncoding textEncodingHint,
+       FSRef *newRef)                                  /* if function fails along the way, newRef is final location of file */
+{
+       OSErr                   result;
+       FSVolumeRefNum  vRefNum;
+       FSCatalogInfo   catalogInfo;
+       FSRef                   originalDirectory;
+       TextEncoding    originalTextEncodingHint;
+       HFSUniStr255    originalName;
+       HFSUniStr255    uniqueName;             /* unique name given to object while moving it to destination */
+       long                    theSeed;                /* the seed for generating unique names */
+       
+       /* check parameters */
+       require_action(NULL != newRef, BadParameter, result = paramErr);
+       
+       /* newRef = input to start with */
+       BlockMoveData(ref, newRef, sizeof(FSRef));
+       
+       /* get destDirectory's vRefNum */
+       result = FSGetCatalogInfo(destDirectory, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, DestinationBad);
+       
+       /* save vRefNum */
+       vRefNum = catalogInfo.volume;
+       
+       /* get ref's vRefNum, TextEncoding, name and parent directory*/
+       result = FSGetCatalogInfo(ref, kFSCatInfoTextEncoding + kFSCatInfoVolume, &catalogInfo, &originalName, NULL, &originalDirectory);
+       require_noerr(result, SourceBad);
+       
+       /* save TextEncoding */
+       originalTextEncodingHint = catalogInfo.textEncodingHint;
+       
+       /* make sure ref and destDirectory are on same volume */
+       require_action(vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr);
+       
+       /* Skip a few steps if we're not renaming */
+       if ( NULL != name )
+       {
+               /* generate a name that is unique in both directories */
+               theSeed = 0x4a696d4c;   /* a fine unlikely filename */
+               
+               result = GenerateUniqueHFSUniStr(&theSeed, &originalDirectory, destDirectory, &uniqueName);
+               require_noerr(result, GenerateUniqueHFSUniStrFailed);
+               
+               /* Rename the object to uniqueName */
+               result = FSRenameUnicode(ref, uniqueName.length, uniqueName.unicode, kTextEncodingUnknown, newRef);
+               require_noerr(result, FSRenameUnicodeBeforeMoveFailed);
+               
+               /* Move object to its new home */
+               result = FSMoveObject(newRef, destDirectory, newRef);
+               require_noerr(result, FSMoveObjectAfterRenameFailed);
+               
+               /* Rename the object to new name */
+               result = FSRenameUnicode(ref, nameLength, name, textEncodingHint, newRef);
+               require_noerr(result, FSRenameUnicodeAfterMoveFailed);
+       }
+       else
+       {
+               /* Move object to its new home */
+               result = FSMoveObject(newRef, destDirectory, newRef);
+               require_noerr(result, FSMoveObjectNoRenameFailed);
+       }
+       
+       return ( result );
+       
+       /*************/
+
+/*
+ * failure handling code when renaming
+ */
+
+FSRenameUnicodeAfterMoveFailed:
+
+       /* Error handling: move object back to original location - ignore errors */
+       verify_noerr(FSMoveObject(newRef, &originalDirectory, newRef));
+       
+FSMoveObjectAfterRenameFailed:
+
+       /* Error handling: rename object back to original name - ignore errors */
+       verify_noerr(FSRenameUnicode(newRef, originalName.length, originalName.unicode, originalTextEncodingHint, newRef));
+       
+FSRenameUnicodeBeforeMoveFailed:
+GenerateUniqueHFSUniStrFailed:
+
+/*
+ * failure handling code for renaming or not
+ */
+FSMoveObjectNoRenameFailed:
+NotSameVolume:
+SourceBad:
+DestinationBad:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+/*
+       The FSDeleteContainerLevel function deletes the contents of a container
+       directory. All files and subdirectories in the specified container are
+       deleted. If a locked file or directory is encountered, it is unlocked
+       and then deleted. If any unexpected errors are encountered,
+       FSDeleteContainerLevel quits and returns to the caller.
+       
+       container                       --> FSRef to a directory.
+       theGlobals                      --> A pointer to a FSDeleteContainerGlobals struct
+                                                       which contains the variables that do not need to
+                                                       be allocated each time FSDeleteContainerLevel
+                                                       recurses. That lets FSDeleteContainerLevel use
+                                                       less stack space per recursion level.
+*/
+
+static
+void
+FSDeleteContainerLevel(
+       const FSRef *container,
+       FSDeleteContainerGlobals *theGlobals)
+{
+       /* level locals */
+       FSIterator                                      iterator;
+       FSRef                                           itemToDelete;
+       UInt16                                          nodeFlags;
+       
+       /* Open FSIterator for flat access and give delete optimization hint */
+       theGlobals->result = FSOpenIterator(container, kFSIterateFlat + kFSIterateDelete, &iterator);
+       require_noerr(theGlobals->result, FSOpenIterator);
+       
+       /* delete the contents of the directory */
+       do
+       {
+               /* get 1 item to delete */
+               theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
+                                                               NULL, kFSCatInfoNodeFlags, &theGlobals->catalogInfo,
+                                                               &itemToDelete, NULL, NULL);
+               if ( (noErr == theGlobals->result) && (1 == theGlobals->actualObjects) )
+               {
+                       /* save node flags in local in case we have to recurse */
+                       nodeFlags = theGlobals->catalogInfo.nodeFlags;
+                       
+                       /* is it a file or directory? */
+                       if ( 0 != (nodeFlags & kFSNodeIsDirectoryMask) )
+                       {
+                               /* it's a directory -- delete its contents before attempting to delete it */
+                               FSDeleteContainerLevel(&itemToDelete, theGlobals);
+                       }
+                       /* are we still OK to delete? */
+                       if ( noErr == theGlobals->result )
+                       {
+                               /* is item locked? */
+                               if ( 0 != (nodeFlags & kFSNodeLockedMask) )
+                               {
+                                       /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */
+                                       theGlobals->catalogInfo.nodeFlags = nodeFlags & ~kFSNodeLockedMask;
+                                       (void) FSSetCatalogInfo(&itemToDelete, kFSCatInfoNodeFlags, &theGlobals->catalogInfo);
+                               }
+                               /* delete the item */
+                               theGlobals->result = FSDeleteObject(&itemToDelete);
+                       }
+               }
+       } while ( noErr == theGlobals->result );
+       
+       /* we found the end of the items normally, so return noErr */
+       if ( errFSNoMoreItems == theGlobals->result )
+       {
+               theGlobals->result = noErr;
+       }
+       
+       /* close the FSIterator (closing an open iterator should never fail) */
+       verify_noerr(FSCloseIterator(iterator));
+
+FSOpenIterator:
+
+       return;
+}
+
+/*****************************************************************************/
+
+OSErr
+FSDeleteContainerContents(
+       const FSRef *container)
+{
+       FSDeleteContainerGlobals        theGlobals;
+       
+       /* delete container's contents */
+       FSDeleteContainerLevel(container, &theGlobals);
+       
+       return ( theGlobals.result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSDeleteContainer(
+       const FSRef *container)
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       
+       /* get nodeFlags for container */
+       result = FSGetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL,NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* make sure container is a directory */
+       require_action(0 != (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), ContainerNotDirectory, result = dirNFErr);
+       
+       /* delete container's contents */
+       result = FSDeleteContainerContents(container);
+       require_noerr(result, FSDeleteContainerContents);
+       
+       /* is container locked? */
+       if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) )
+       {
+               /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */
+               catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
+               (void) FSSetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo);
+       }
+       
+       /* delete the container */
+       result = FSDeleteObject(container);
+       
+FSDeleteContainerContents:
+ContainerNotDirectory:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+/*
+       The FSIterateContainerLevel function iterates the contents of a container
+       directory and calls a IterateContainerFilterProc function once for each
+       file and directory found.
+       
+       theGlobals                      --> A pointer to a FSIterateContainerGlobals struct
+                                                       which contains the variables needed globally by
+                                                       all recusion levels of FSIterateContainerLevel.
+                                                       That makes FSIterateContainer thread safe since
+                                                       each call to it uses its own global world.
+                                                       It also contains the variables that do not need
+                                                       to be allocated each time FSIterateContainerLevel
+                                                       recurses. That lets FSIterateContainerLevel use
+                                                       less stack space per recursion level.
+*/
+
+static
+void
+FSIterateContainerLevel(
+       FSIterateContainerGlobals *theGlobals)
+{      
+       FSIterator      iterator;
+       
+       /* If maxLevels is zero, we aren't checking levels */
+       /* If currentLevel < maxLevels, look at this level */
+       if ( (theGlobals->maxLevels == 0) ||
+                (theGlobals->currentLevel < theGlobals->maxLevels) )
+       {
+               /* Open FSIterator for flat access to theGlobals->ref */
+               theGlobals->result = FSOpenIterator(&theGlobals->ref, kFSIterateFlat, &iterator);
+               require_noerr(theGlobals->result, FSOpenIterator);
+               
+               ++theGlobals->currentLevel; /* Go to next level */
+               
+               /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
+               do
+               {
+                       theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
+                               &theGlobals->containerChanged, theGlobals->whichInfo, &theGlobals->catalogInfo,
+                               &theGlobals->ref, theGlobals->specPtr, theGlobals->namePtr);
+                       if ( (noErr == theGlobals->result || errFSNoMoreItems == theGlobals->result) &&
+                               (0 != theGlobals->actualObjects) )
+                       {
+                               /* Call the IterateFilterProc */
+                               theGlobals->quitFlag = CallIterateContainerFilterProc(theGlobals->iterateFilter,
+                                       theGlobals->containerChanged, theGlobals->currentLevel,
+                                       &theGlobals->catalogInfo, &theGlobals->ref,
+                                       theGlobals->specPtr, theGlobals->namePtr, theGlobals->yourDataPtr);
+                               /* Is it a directory? */
+                               if ( 0 != (theGlobals->catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) )
+                               {
+                                       /* Keep going? */
+                                       if ( !theGlobals->quitFlag )
+                                       {
+                                               /* Dive again if the IterateFilterProc didn't say "quit" */
+                                               FSIterateContainerLevel(theGlobals);
+                                       }
+                               }
+                       }
+                       /* time to fall back a level? */
+               } while ( (noErr == theGlobals->result) && (!theGlobals->quitFlag) );
+               
+               /* errFSNoMoreItems is OK - it only means we hit the end of this level */
+               /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
+               if ( (errFSNoMoreItems == theGlobals->result) ||
+                        (afpAccessDenied == theGlobals->result) )
+               {
+                       theGlobals->result = noErr;
+               }
+               
+               --theGlobals->currentLevel; /* Return to previous level as we leave */
+               
+               /* Close the FSIterator (closing an open iterator should never fail) */
+               verify_noerr(FSCloseIterator(iterator));
+       }
+       
+FSOpenIterator:
+
+       return;
+}
+
+/*****************************************************************************/
+
+OSErr
+FSIterateContainer(
+       const FSRef *container,
+       ItemCount maxLevels,
+       FSCatalogInfoBitmap whichInfo,
+       Boolean wantFSSpec,
+       Boolean wantName,
+       IterateContainerFilterProcPtr iterateFilter,
+       void *yourDataPtr)
+{
+       OSErr                                           result;
+       FSIterateContainerGlobals       theGlobals;
+       
+       /* make sure there is an iterateFilter */
+       require_action(iterateFilter != NULL, NoIterateFilter, result = paramErr);
+       
+       /*
+        * set up the globals we need to access from the recursive routine
+        */
+       theGlobals.iterateFilter = iterateFilter;
+       /* we need the node flags no matter what was requested so we can detect files vs. directories */
+       theGlobals.whichInfo = whichInfo | kFSCatInfoNodeFlags;
+       /* start with input container -- the first OpenIterator will ensure it is a directory */
+       theGlobals.ref = *container;
+       if ( wantFSSpec )
+       {
+               theGlobals.specPtr = &theGlobals.spec;
+       }
+       else
+       {
+               theGlobals.specPtr = NULL;
+       }
+       if ( wantName )
+       {
+               theGlobals.namePtr = &theGlobals.name;
+       }
+       else
+       {
+               theGlobals.namePtr = NULL;
+       }
+       theGlobals.yourDataPtr = yourDataPtr;
+       theGlobals.maxLevels = maxLevels;
+       theGlobals.currentLevel = 0;
+       theGlobals.quitFlag = false;
+       theGlobals.containerChanged = false;
+       theGlobals.result = noErr;
+       theGlobals.actualObjects = 0;
+       
+       /* here we go into recursion land... */
+       FSIterateContainerLevel(&theGlobals);
+       result = theGlobals.result;
+       require_noerr(result, FSIterateContainerLevel);
+       
+FSIterateContainerLevel:
+NoIterateFilter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetDirectoryItems(
+       const FSRef *container,
+       FSRef ***refsHandle,    /* pointer to handle of FSRefs */
+       ItemCount *numRefs,
+       Boolean *containerChanged)
+{
+       /* Grab items 10 at a time. */
+       enum { kMaxItemsPerBulkCall = 10 };
+       
+       OSErr           result;
+       OSErr           memResult;
+       FSIterator      iterator;
+       FSRef           refs[kMaxItemsPerBulkCall];
+       ItemCount       actualObjects;
+       Boolean         changed;
+       
+       /* check parameters */
+       require_action((NULL != refsHandle) && (NULL != numRefs) && (NULL != containerChanged),
+               BadParameter, result = paramErr);
+       
+       *numRefs = 0;
+       *containerChanged = false;
+       *refsHandle = (FSRef **)NewHandle(0);
+       require_action(NULL != *refsHandle, NewHandle, result = memFullErr);
+       
+       /* open an FSIterator */
+       result = FSOpenIterator(container, kFSIterateFlat, &iterator);
+       require_noerr(result, FSOpenIterator);
+       
+       /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
+       do
+       {
+               result = FSGetCatalogInfoBulk(iterator, kMaxItemsPerBulkCall, &actualObjects,
+                                       &changed, kFSCatInfoNone,  NULL,  refs, NULL, NULL);
+               
+               /* if the container changed, set containerChanged for output, but keep going */
+               if ( changed )
+               {
+                       *containerChanged = changed;
+               }
+               
+               /* any result other than noErr and errFSNoMoreItems is serious */
+               require((noErr == result) || (errFSNoMoreItems == result), FSGetCatalogInfoBulk);
+               
+               /* add objects to output array and count */
+               if ( 0 != actualObjects )
+               {
+                       /* concatenate the FSRefs to the end of the      handle */
+                       PtrAndHand(refs, (Handle)*refsHandle, actualObjects * sizeof(FSRef));
+                       memResult = MemError();
+                       require_noerr_action(memResult, MemoryAllocationFailed, result = memResult);
+                       
+                       *numRefs += actualObjects;
+               }
+       } while ( noErr == result );
+       
+       verify_noerr(FSCloseIterator(iterator)); /* closing an open iterator should never fail, but... */
+       
+       return ( noErr );
+       
+       /**********************/
+       
+MemoryAllocationFailed:
+FSGetCatalogInfoBulk:
+
+       /* close the iterator */
+       verify_noerr(FSCloseIterator(iterator));
+
+FSOpenIterator:
+       /* dispose of handle if already allocated and clear the outputs */
+       if ( NULL != *refsHandle )
+       {
+               DisposeHandle((Handle)*refsHandle);
+               *refsHandle = NULL;
+       }
+       *numRefs = 0;
+       
+NewHandle:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+/*
+       The GenerateUniqueName function generates a HFSUniStr255 name that is
+       unique in both dir1 and dir2.
+       
+       startSeed                       -->     A pointer to a long which is used to generate the
+                                                       unique name.
+                                               <--     It is modified on output to a value which should
+                                                       be used to generate the next unique name.
+       dir1                            -->     The first directory.
+       dir2                            -->     The second directory.
+       uniqueName                      <--     A pointer to a HFSUniStr255 where the unique name
+                                                       is to be returned.
+*/
+
+static
+OSErr
+GenerateUniqueHFSUniStr(
+       long *startSeed,
+       const FSRef *dir1,
+       const FSRef *dir2,
+       HFSUniStr255 *uniqueName)
+{
+       OSErr                   result;
+       long                    i;
+       FSRefParam              pb;
+       FSRef                   newRef;
+       unsigned char   hexStr[17] = "0123456789ABCDEF";
+       
+       /* set up the parameter block */
+       pb.name = uniqueName->unicode;
+       pb.nameLength = 8;      /* always 8 characters */
+       pb.textEncodingHint = kTextEncodingUnknown;
+       pb.newRef = &newRef;
+
+       /* loop until we get fnfErr with a filename in both directories */
+       result = noErr;
+       while ( fnfErr != result )
+       {
+               /* convert startSeed to 8 character Unicode string */
+               uniqueName->length = 8;
+               for ( i = 0; i < 8; ++i )
+               {
+                       uniqueName->unicode[i] = hexStr[((*startSeed >> ((7-i)*4)) & 0xf)];
+               }
+               
+               /* try in dir1 */
+               pb.ref = dir1;
+               result = PBMakeFSRefUnicodeSync(&pb);
+               if ( fnfErr == result )
+               {
+                       /* try in dir2 */
+                       pb.ref = dir2;
+                       result = PBMakeFSRefUnicodeSync(&pb);
+                       if ( fnfErr != result )
+                       {
+                               /* exit if anything other than noErr or fnfErr */
+                               require_noerr(result, Dir2PBMakeFSRefUnicodeSyncFailed);
+                       }
+               }
+               else
+               {
+                       /* exit if anything other than noErr or fnfErr */
+                       require_noerr(result, Dir1PBMakeFSRefUnicodeSyncFailed);
+               }
+               
+               /* increment seed for next pass through loop, */
+               /* or for next call to GenerateUniqueHFSUniStr */
+               ++(*startSeed);
+       }
+       
+       /* we have a unique file name which doesn't exist in dir1 or dir2 */
+       result = noErr;
+       
+Dir2PBMakeFSRefUnicodeSyncFailed:
+Dir1PBMakeFSRefUnicodeSyncFailed:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSExchangeObjectsCompat(
+       const FSRef *sourceRef,
+       const FSRef *destRef,
+       FSRef *newSourceRef,
+       FSRef *newDestRef)
+{
+       enum
+       {
+               /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */
+               kGetCatInformationMask = (kFSCatInfoSettableInfo |
+                                                                 kFSCatInfoVolume |
+                                                                 kFSCatInfoParentDirID) &
+                                                                ~(kFSCatInfoContentMod | kFSCatInfoAttrMod),
+               /* set everything possible except for mod dates */
+               kSetCatinformationMask = kFSCatInfoSettableInfo &
+                                                                ~(kFSCatInfoContentMod | kFSCatInfoAttrMod)
+       };
+       
+       OSErr                                   result;
+       GetVolParmsInfoBuffer   volParmsInfo;
+       UInt32                                  infoSize;
+       FSCatalogInfo                   sourceCatalogInfo;      /* source file's catalog information */
+       FSCatalogInfo                   destCatalogInfo;        /* destination file's catalog information */
+       HFSUniStr255                    sourceName;                     /* source file's Unicode name */
+       HFSUniStr255                    destName;                       /* destination file's Unicode name */
+       FSRef                                   sourceCurrentRef;       /* FSRef to current location of source file throughout this function */
+       FSRef                                   destCurrentRef;         /* FSRef to current location of destination file throughout this function */
+       FSRef                                   sourceParentRef;        /* FSRef to parent directory of source file */
+       FSRef                                   destParentRef;          /* FSRef to parent directory of destination file */
+       HFSUniStr255                    sourceUniqueName;       /* unique name given to source file while exchanging it with destination */
+       HFSUniStr255                    destUniqueName;         /* unique name given to destination file while exchanging it with source */
+       long                                    theSeed;                        /* the seed for generating unique names */
+       Boolean                                 sameParentDirs;         /* true if source and destinatin parent directory is the same */
+       
+       /* check parameters */
+       require_action((NULL != newSourceRef) && (NULL != newDestRef), BadParameter, result = paramErr);
+       
+       /* output refs and current refs = input refs to start with */
+       BlockMoveData(sourceRef, newSourceRef, sizeof(FSRef));
+       BlockMoveData(sourceRef, &sourceCurrentRef, sizeof(FSRef));
+       
+       BlockMoveData(destRef, newDestRef, sizeof(FSRef));
+       BlockMoveData(destRef, &destCurrentRef, sizeof(FSRef));
+
+       /* get source volume's vRefNum */
+       result = FSGetCatalogInfo(&sourceCurrentRef, kFSCatInfoVolume, &sourceCatalogInfo, NULL, NULL, NULL);
+       require_noerr(result, DetermineSourceVRefNumFailed);
+       
+       /* see if that volume supports FSExchangeObjects */
+       result = FSGetVolParms(sourceCatalogInfo.volume, sizeof(GetVolParmsInfoBuffer),
+               &volParmsInfo, &infoSize);
+       if ( (noErr == result) && VolSupportsFSExchangeObjects(&volParmsInfo) )
+       {
+               /* yes - use FSExchangeObjects */
+               result = FSExchangeObjects(sourceRef, destRef);
+       }
+       else
+       {
+               /* no - emulate FSExchangeObjects */
+               
+               /* Note: The compatibility case won't work for files with *Btree control blocks. */
+               /* Right now the only *Btree files are created by the system. */
+               
+               /* get all catalog information and Unicode names for each file */
+               result = FSGetCatalogInfo(&sourceCurrentRef, kGetCatInformationMask, &sourceCatalogInfo, &sourceName, NULL, &sourceParentRef);
+               require_noerr(result, SourceFSGetCatalogInfoFailed);
+               
+               result = FSGetCatalogInfo(&destCurrentRef, kGetCatInformationMask, &destCatalogInfo, &destName, NULL, &destParentRef);
+               require_noerr(result, DestFSGetCatalogInfoFailed);
+               
+               /* make sure source and destination are on same volume */
+               require_action(sourceCatalogInfo.volume == destCatalogInfo.volume, NotSameVolume, result = diffVolErr);
+               
+               /* make sure both files are *really* files */
+               require_action((0 == (sourceCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) &&
+                                          (0 == (destCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)), NotAFile, result = notAFileErr);
+               
+               /* generate 2 names that are unique in both directories */
+               theSeed = 0x4a696d4c;   /* a fine unlikely filename */
+               
+               result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &sourceUniqueName);
+               require_noerr(result, GenerateUniqueHFSUniStr1Failed);
+               
+               result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &destUniqueName);
+               require_noerr(result, GenerateUniqueHFSUniStr2Failed);
+
+               /* rename sourceCurrentRef to sourceUniqueName */
+               result = FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef);
+               require_noerr(result, FSRenameUnicode1Failed);
+               BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+               
+               /* rename destCurrentRef to destUniqueName */
+               result = FSRenameUnicode(&destCurrentRef, destUniqueName.length, destUniqueName.unicode, kTextEncodingUnknown, newDestRef);
+               require_noerr(result, FSRenameUnicode2Failed);
+               BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
+               
+               /* are the source and destination parent directories the same? */
+               sameParentDirs = ( sourceCatalogInfo.parentDirID == destCatalogInfo.parentDirID );
+               if ( !sameParentDirs )
+               {
+                       /* move source file to dest parent directory */
+                       result = FSMoveObject(&sourceCurrentRef, &destParentRef, newSourceRef);
+                       require_noerr(result, FSMoveObject1Failed);
+                       BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+                       
+                       /* move dest file to source parent directory */
+                       result = FSMoveObject(&destCurrentRef, &sourceParentRef, newDestRef);
+                       require_noerr(result, FSMoveObject2Failed);
+                       BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
+               }
+               
+               /* At this point, the files are in their new locations (if they were moved). */
+               /* The source file is named sourceUniqueName and is in the directory referred to */
+               /* by destParentRef. The destination file is named destUniqueName and is in the */
+               /* directory referred to by sourceParentRef. */
+                               
+               /* give source file the dest file's catalog information except for mod dates */
+               result = FSSetCatalogInfo(&sourceCurrentRef, kSetCatinformationMask, &destCatalogInfo);
+               require_noerr(result, FSSetCatalogInfo1Failed);
+               
+               /* give dest file the source file's catalog information except for mod dates */
+               result = FSSetCatalogInfo(&destCurrentRef, kSetCatinformationMask, &sourceCatalogInfo);
+               require_noerr(result, FSSetCatalogInfo2Failed);
+               
+               /* rename source file with dest file's name */
+               result = FSRenameUnicode(&sourceCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newSourceRef);
+               require_noerr(result, FSRenameUnicode3Failed);
+               BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+               
+               /* rename dest file with source file's name */
+               result = FSRenameUnicode(&destCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newDestRef);
+               require_noerr(result, FSRenameUnicode4Failed);
+               
+               /* we're done with no errors, so swap newSourceRef and newDestRef */
+               BlockMoveData(newDestRef, newSourceRef, sizeof(FSRef));
+               BlockMoveData(&sourceCurrentRef, newDestRef, sizeof(FSRef));
+       }
+       
+       return ( result );
+       
+       /**********************/
+
+/* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */
+/* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */
+/* state and location they ended up in so that both files can be found by the calling code. */
+       
+FSRenameUnicode4Failed:
+
+       /* attempt to rename source file to sourceUniqueName */
+       if ( noErr == FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef) )
+       {
+               BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+       }
+
+FSRenameUnicode3Failed:
+
+       /* attempt to restore dest file's catalog information */
+       verify_noerr(FSSetCatalogInfo(&destCurrentRef, kFSCatInfoSettableInfo, &destCatalogInfo));
+
+FSSetCatalogInfo2Failed:
+
+       /* attempt to restore source file's catalog information */
+       verify_noerr(FSSetCatalogInfo(&sourceCurrentRef, kFSCatInfoSettableInfo, &sourceCatalogInfo));
+
+FSSetCatalogInfo1Failed:
+
+       if ( !sameParentDirs )
+       {
+               /* attempt to move dest file back to dest directory */
+               if ( noErr == FSMoveObject(&destCurrentRef, &destParentRef, newDestRef) )
+               {
+                       BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
+               }
+       }
+
+FSMoveObject2Failed:
+
+       if ( !sameParentDirs )
+       {
+               /* attempt to move source file back to source directory */
+               if ( noErr == FSMoveObject(&sourceCurrentRef, &sourceParentRef, newSourceRef) )
+               {
+                       BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+               }
+       }
+
+FSMoveObject1Failed:
+
+       /* attempt to rename dest file to original name */
+       verify_noerr(FSRenameUnicode(&destCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newDestRef));
+
+FSRenameUnicode2Failed:
+
+       /* attempt to rename source file to original name */
+       verify_noerr(FSRenameUnicode(&sourceCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newSourceRef));
+
+FSRenameUnicode1Failed:
+GenerateUniqueHFSUniStr2Failed:
+GenerateUniqueHFSUniStr1Failed:
+NotAFile:
+NotSameVolume:
+DestFSGetCatalogInfoFailed:
+SourceFSGetCatalogInfoFailed:
+DetermineSourceVRefNumFailed:  
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Shared Environment Routines -----
+
+/*****************************************************************************/
+
+OSErr
+FSLockRange(
+       SInt16 refNum,
+       SInt32 rangeLength,
+       SInt32 rangeStart)
+{
+       OSErr                   result;
+       ParamBlockRec   pb;
+
+       pb.ioParam.ioRefNum = refNum;
+       pb.ioParam.ioReqCount = rangeLength;
+       pb.ioParam.ioPosMode = fsFromStart;
+       pb.ioParam.ioPosOffset = rangeStart;
+       result = PBLockRangeSync(&pb);
+       require_noerr(result, PBLockRangeSync);
+       
+PBLockRangeSync:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSUnlockRange(
+       SInt16 refNum,
+       SInt32 rangeLength,
+       SInt32 rangeStart)
+{
+       OSErr                   result;
+       ParamBlockRec   pb;
+
+       pb.ioParam.ioRefNum = refNum;
+       pb.ioParam.ioReqCount = rangeLength;
+       pb.ioParam.ioPosMode = fsFromStart;
+       pb.ioParam.ioPosOffset = rangeStart;
+       result = PBUnlockRangeSync(&pb);
+       require_noerr(result, PBUnlockRangeSync);
+       
+PBUnlockRangeSync:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetDirAccess(
+       const FSRef *ref,
+       SInt32 *ownerID,                /* can be NULL */
+       SInt32 *groupID,                /* can be NULL */
+       SInt32 *accessRights)   /* can be NULL */
+{
+       OSErr                   result;
+       FSSpec                  spec;
+       HParamBlockRec  pb;
+       
+       /* get FSSpec from FSRef */
+       result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* get directory access info for FSSpec */
+       pb.accessParam.ioNamePtr = (StringPtr)spec.name;
+       pb.accessParam.ioVRefNum = spec.vRefNum;
+       pb.fileParam.ioDirID = spec.parID;
+       result = PBHGetDirAccessSync(&pb);
+       require_noerr(result, PBHGetDirAccessSync);
+       
+       /* return the IDs and access rights */
+       if ( NULL != ownerID )
+       {
+               *ownerID = pb.accessParam.ioACOwnerID;
+       }
+       if ( NULL != groupID )
+       {
+               *groupID = pb.accessParam.ioACGroupID;
+       }
+       if ( NULL != accessRights )
+       {
+               *accessRights = pb.accessParam.ioACAccess;
+       }
+       
+PBHGetDirAccessSync:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetDirAccess(
+       const FSRef *ref,
+       SInt32 ownerID,
+       SInt32 groupID,
+       SInt32 accessRights)
+{
+       OSErr                   result;
+       FSSpec                  spec;
+       HParamBlockRec  pb;
+
+       enum
+       {
+               /* Just the bits that can be set */
+               kSetDirAccessSettableMask = (kioACAccessBlankAccessMask +
+                       kioACAccessEveryoneWriteMask + kioACAccessEveryoneReadMask + kioACAccessEveryoneSearchMask +
+                       kioACAccessGroupWriteMask + kioACAccessGroupReadMask + kioACAccessGroupSearchMask +
+                       kioACAccessOwnerWriteMask + kioACAccessOwnerReadMask + kioACAccessOwnerSearchMask)
+       };
+       
+       /* get FSSpec from FSRef */
+       result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* set directory access info for FSSpec */
+       pb.accessParam.ioNamePtr = (StringPtr)spec.name;
+       pb.accessParam.ioVRefNum = spec.vRefNum;
+       pb.fileParam.ioDirID = spec.parID;
+       pb.accessParam.ioACOwnerID = ownerID;
+       pb.accessParam.ioACGroupID = groupID;
+       pb.accessParam.ioACAccess = accessRights & kSetDirAccessSettableMask;
+       result = PBHSetDirAccessSync(&pb);
+       require_noerr(result, PBHSetDirAccessSync);
+       
+PBHSetDirAccessSync:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVolMountInfoSize(
+       FSVolumeRefNum volRefNum,
+       SInt16 *size)
+{
+       OSErr                   result;
+       ParamBlockRec   pb;
+
+       /* check parameters */
+       require_action(NULL != size, BadParameter, result = paramErr);
+       
+       pb.ioParam.ioNamePtr = NULL;
+       pb.ioParam.ioVRefNum = volRefNum;
+       pb.ioParam.ioBuffer = (Ptr)size;
+       result = PBGetVolMountInfoSize(&pb);
+       require_noerr(result, PBGetVolMountInfoSize);
+       
+PBGetVolMountInfoSize:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVolMountInfo(
+       FSVolumeRefNum volRefNum,
+       void *volMountInfo)
+{
+       OSErr                   result;
+       ParamBlockRec   pb;
+
+       /* check parameters */
+       require_action(NULL != volMountInfo, BadParameter, result = paramErr);
+       
+       pb.ioParam.ioNamePtr = NULL;
+       pb.ioParam.ioVRefNum = volRefNum;
+       pb.ioParam.ioBuffer = (Ptr)volMountInfo;
+       result = PBGetVolMountInfo(&pb);
+       require_noerr(result, PBGetVolMountInfo);
+       
+PBGetVolMountInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSVolumeMount(
+       const void *volMountInfo,
+       FSVolumeRefNum *volRefNum)
+{
+       OSErr                   result;
+       ParamBlockRec   pb;
+
+       /* check parameters */
+       require_action(NULL != volRefNum, BadParameter, result = paramErr);
+       
+       pb.ioParam.ioBuffer = (Ptr)volMountInfo;
+       result = PBVolumeMount(&pb);
+       require_noerr(result, PBVolumeMount);
+       
+       /* return the volume reference number */
+       *volRefNum = pb.ioParam.ioVRefNum;
+
+PBVolumeMount:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMapID(
+       FSVolumeRefNum volRefNum,
+       SInt32 ugID,
+       SInt16 objType,
+       Str31 name)
+{
+       OSErr                   result;
+       HParamBlockRec  pb;
+
+       /* check parameters */
+       require_action(NULL != name, BadParameter, result = paramErr);
+       
+       pb.objParam.ioNamePtr = NULL;
+       pb.objParam.ioVRefNum = volRefNum;
+       pb.objParam.ioObjType = objType;
+       pb.objParam.ioObjNamePtr = name;
+       pb.objParam.ioObjID = ugID;
+       result = PBHMapIDSync(&pb);
+       require_noerr(result, PBHMapIDSync);
+       
+PBHMapIDSync:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMapName(
+       FSVolumeRefNum volRefNum,
+       ConstStr255Param name,
+       SInt16 objType,
+       SInt32 *ugID)
+{
+       OSErr                   result;
+       HParamBlockRec  pb;
+
+       /* check parameters */
+       require_action(NULL != ugID, BadParameter, result = paramErr);
+       
+       pb.objParam.ioNamePtr = NULL;
+       pb.objParam.ioVRefNum = volRefNum;
+       pb.objParam.ioObjType = objType;
+       pb.objParam.ioObjNamePtr = (StringPtr)name;
+       result = PBHMapNameSync(&pb);
+       require_noerr(result, PBHMapNameSync);
+       
+       /* return the user or group ID */
+       *ugID = pb.objParam.ioObjID;
+       
+PBHMapNameSync:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSCopyFile(
+       const FSRef *srcFileRef,
+       const FSRef *dstDirectoryRef,
+       UniCharCount nameLength,
+       const UniChar *copyName,        /* can be NULL (no rename during copy) */
+       TextEncoding textEncodingHint,
+       FSRef *newRef)                          /* can be NULL */
+{
+       OSErr                                   result;
+       FSSpec                                  srcFileSpec;
+       FSCatalogInfo                   catalogInfo;
+       HParamBlockRec                  pb;
+       Str31                                   hfsName;
+       GetVolParmsInfoBuffer   volParmsInfo;
+       UInt32                                  infoSize;
+       
+       /* get source FSSpec from source FSRef */
+       result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
+       require_noerr(result, FSGetCatalogInfo_srcFileRef);
+       
+       /* Make sure the volume supports CopyFile */
+       result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
+               &volParmsInfo, &infoSize);
+       require_action((noErr == result) && VolHasCopyFile(&volParmsInfo),
+               NoCopyFileSupport, result = paramErr);
+
+       /* get destination volume reference number and destination directory ID from destination FSRef */
+       result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
+               &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
+       
+       /* tell the server to copy the object */
+       pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
+       pb.copyParam.ioDirID = srcFileSpec.parID;
+       pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
+       pb.copyParam.ioDstVRefNum = catalogInfo.volume;
+       pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
+       pb.copyParam.ioNewName = NULL;
+       if ( NULL != copyName )
+       {
+               result = UnicodeNameGetHFSName(nameLength, copyName, textEncodingHint, false, hfsName);
+               require_noerr(result, UnicodeNameGetHFSName);
+               
+               pb.copyParam.ioCopyName = hfsName;
+       }
+       else
+       {
+               pb.copyParam.ioCopyName = NULL;
+       }
+       result = PBHCopyFileSync(&pb);
+       require_noerr(result, PBHCopyFileSync);
+       
+       if ( NULL != newRef )
+       {
+               verify_noerr(FSMakeFSRef(pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID,
+                       pb.copyParam.ioCopyName, newRef));
+       }
+               
+PBHCopyFileSync:
+UnicodeNameGetHFSName:
+FSGetCatalogInfo_dstDirectoryRef:
+NoCopyFileSupport:
+FSGetCatalogInfo_srcFileRef:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMoveRename(
+       const FSRef *srcFileRef,
+       const FSRef *dstDirectoryRef,
+       UniCharCount nameLength,
+       const UniChar *moveName,        /* can be NULL (no rename during move) */
+       TextEncoding textEncodingHint,
+       FSRef *newRef)                          /* can be NULL */
+{
+       OSErr                                   result;
+       FSSpec                                  srcFileSpec;
+       FSCatalogInfo                   catalogInfo;
+       HParamBlockRec                  pb;
+       Str31                                   hfsName;
+       GetVolParmsInfoBuffer   volParmsInfo;
+       UInt32                                  infoSize;
+       
+       /* get source FSSpec from source FSRef */
+       result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
+       require_noerr(result, FSGetCatalogInfo_srcFileRef);
+       
+       /* Make sure the volume supports MoveRename */
+       result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
+               &volParmsInfo, &infoSize);
+       require_action((noErr == result) && VolHasMoveRename(&volParmsInfo),
+               NoMoveRenameSupport, result = paramErr);
+
+       /* get destination volume reference number and destination directory ID from destination FSRef */
+       result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
+               &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
+       
+       /* make sure the source and destination are on the same volume */
+       require_action(srcFileSpec.vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr);
+       
+       /* tell the server to move and rename the object */
+       pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
+       pb.copyParam.ioDirID = srcFileSpec.parID;
+       pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
+       pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
+       pb.copyParam.ioNewName = NULL;
+       if ( NULL != moveName )
+       {
+               result = UnicodeNameGetHFSName(nameLength, moveName, textEncodingHint, false, hfsName);
+               require_noerr(result, UnicodeNameGetHFSName);
+               
+               pb.copyParam.ioCopyName = hfsName;
+       }
+       else
+       {
+               pb.copyParam.ioCopyName = NULL;
+       }
+       result = PBHMoveRenameSync(&pb);
+       require_noerr(result, PBHMoveRenameSync);
+       
+       if ( NULL != newRef )
+       {
+               verify_noerr(FSMakeFSRef(pb.copyParam.ioVRefNum, pb.copyParam.ioNewDirID,
+                       pb.copyParam.ioCopyName, newRef));
+       }
+       
+PBHMoveRenameSync:
+UnicodeNameGetHFSName:
+NotSameVolume:
+FSGetCatalogInfo_dstDirectoryRef:
+NoMoveRenameSupport:
+FSGetCatalogInfo_srcFileRef:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- File ID Routines -----
+
+/*****************************************************************************/
+
+OSErr
+FSResolveFileIDRef(
+       FSVolumeRefNum volRefNum,
+       SInt32 fileID,
+       FSRef *ref)
+{
+       OSErr           result;
+       FIDParam        pb;
+       Str255          tempStr;
+       
+       /* check parameters */
+       require_action(NULL != ref, BadParameter, result = paramErr);
+       
+       /* resolve the file ID reference */
+       tempStr[0] = 0;
+       pb.ioNamePtr = tempStr;
+       pb.ioVRefNum = volRefNum;
+       pb.ioFileID = fileID;
+       result = PBResolveFileIDRefSync((HParmBlkPtr)&pb);
+       require_noerr(result, PBResolveFileIDRefSync);
+       
+       /* and then make an FSRef to the file */
+       result = FSMakeFSRef(volRefNum, pb.ioSrcDirID, tempStr, ref);
+       require_noerr(result, FSMakeFSRef);
+       
+FSMakeFSRef:
+PBResolveFileIDRefSync:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSCreateFileIDRef(
+       const FSRef *ref,
+       SInt32 *fileID)
+{
+       OSErr           result;
+       FSSpec          spec;
+       FIDParam        pb;
+       
+       /* check parameters */
+       require_action(NULL != fileID, BadParameter, result = paramErr);
+       
+       /* Get an FSSpec from the FSRef */
+       result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* Create (or get) the file ID reference using the FSSpec */
+       pb.ioNamePtr = (StringPtr)spec.name;
+       pb.ioVRefNum = spec.vRefNum;
+       pb.ioSrcDirID = spec.parID;
+       result = PBCreateFileIDRefSync((HParmBlkPtr)&pb);
+       require((noErr == result) || (fidExists == result) || (afpIDExists == result),
+               PBCreateFileIDRefSync);
+       
+       /* return the file ID reference */
+       *fileID = pb.ioFileID;
+       
+PBCreateFileIDRefSync:
+FSGetCatalogInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Utility Routines -----
+
+/*****************************************************************************/
+
+Ptr
+GetTempBuffer(
+       ByteCount buffReqSize,
+       ByteCount *buffActSize)
+{
+       enum
+       {
+               kSlopMemory = 0x00008000        /* 32K - Amount of free memory to leave when allocating buffers */
+       };
+       
+       Ptr tempPtr;
+       
+       /* check parameters */
+       require_action(NULL != buffActSize, BadParameter, tempPtr = NULL);
+       
+       /* Make request a multiple of 4K bytes */
+       buffReqSize = buffReqSize & 0xfffff000;
+       
+       if ( buffReqSize < 0x00001000 )
+       {
+               /* Request was smaller than 4K bytes - make it 4K */
+               buffReqSize = 0x00001000;
+       }
+       
+       /* Attempt to allocate the memory */
+       tempPtr = NewPtr(buffReqSize);
+       
+       /* If request failed, go to backup plan */
+       if ( (tempPtr == NULL) && (buffReqSize > 0x00001000) )
+       {
+               /*
+               **      Try to get largest 4K byte block available
+               **      leaving some slop for the toolbox if possible
+               */
+               long freeMemory = (FreeMem() - kSlopMemory) & 0xfffff000;
+               
+               buffReqSize = MaxBlock() & 0xfffff000;
+               
+               if ( buffReqSize > freeMemory )
+               {
+                       buffReqSize = freeMemory;
+               }
+               
+               if ( buffReqSize == 0 )
+               {
+                       buffReqSize = 0x00001000;
+               }
+               
+               tempPtr = NewPtr(buffReqSize);
+       }
+       
+       /* Return bytes allocated */
+       if ( tempPtr != NULL )
+       {
+               *buffActSize = buffReqSize;
+       }
+       else
+       {
+               *buffActSize = 0;
+       }
+       
+BadParameter:
+
+       return ( tempPtr );
+}
+
+/*****************************************************************************/
+
+OSErr
+FileRefNumGetFSRef(
+       short refNum,
+       FSRef *ref)
+{
+       return ( FSGetForkCBInfo(refNum, 0, NULL, NULL, NULL, ref, NULL) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetDefault(
+       const FSRef *newDefault,
+       FSRef *oldDefault)
+{
+       OSErr                   result;
+       FSVolumeRefNum  vRefNum;
+       long                    dirID;
+       FSCatalogInfo   catalogInfo;
+       
+       /* check parameters */
+       require_action((NULL != newDefault) && (NULL != oldDefault), BadParameter, result = paramErr);
+       
+       /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */
+       result = FSGetCatalogInfo(newDefault,
+               kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
+               &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* Make sure newDefault is a directory */
+       require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), NewDefaultNotDirectory,
+               result = dirNFErr);
+       
+       /* Get the current working directory. */
+       result = HGetVol(NULL, &vRefNum, &dirID);
+       require_noerr(result, HGetVol);
+       
+       /* Return the oldDefault FSRef */
+       result = FSMakeFSRef(vRefNum, dirID, NULL, oldDefault);
+       require_noerr(result, FSMakeFSRef);
+       
+       /* Set the new current working directory */
+       result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
+       require_noerr(result, HSetVol);
+
+HSetVol:
+FSMakeFSRef:
+HGetVol:
+NewDefaultNotDirectory:
+FSGetCatalogInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSRestoreDefault(
+       const FSRef *oldDefault)
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       
+       /* check parameters */
+       require_action(NULL != oldDefault, BadParameter, result = paramErr);
+       
+       /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */
+       result = FSGetCatalogInfo(oldDefault,
+               kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
+               &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* Make sure oldDefault is a directory */
+       require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), OldDefaultNotDirectory,
+               result = dirNFErr);
+       
+       /* Set the current working directory to oldDefault */
+       result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
+       require_noerr(result, HSetVol);
+
+HSetVol:
+OldDefaultNotDirectory:
+FSGetCatalogInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
diff --git a/Source/MoreFilesX.h b/Source/MoreFilesX.h
new file mode 100644 (file)
index 0000000..856e22c
--- /dev/null
@@ -0,0 +1,1827 @@
+/*
+       File:           MoreFilesX.h
+
+       Contains:       A collection of useful high-level File Manager routines
+                               which use the HFS Plus APIs wherever possible.
+
+       Version:        MoreFilesX 1.0.1
+
+       Copyright:      Â© 1992-2002 by Apple Computer, Inc., all rights reserved.
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                               ("Apple") in consideration of your agreement to the following terms, and your
+                               use, installation, modification or redistribution of this Apple software
+                               constitutes acceptance of these terms.  If you do not agree with these terms,
+                               please do not use, install, modify or redistribute this Apple software.
+
+                               In consideration of your agreement to abide by the following terms, and subject
+                               to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+                               copyrights in this original Apple software (the "Apple Software"), to use,
+                               reproduce, modify and redistribute the Apple Software, with or without
+                               modifications, in source and/or binary forms; provided that if you redistribute
+                               the Apple Software in its entirety and without modifications, you must retain
+                               this notice and the following text and disclaimers in all such redistributions of
+                               the Apple Software.  Neither the name, trademarks, service marks or logos of
+                               Apple Computer, Inc. may be used to endorse or promote products derived from the
+                               Apple Software without specific prior written permission from Apple.  Except as
+                               expressly stated in this notice, no other rights or licenses, express or implied,
+                               are granted by Apple herein, including but not limited to any patent rights that
+                               may be infringed by your derivative works or by other works in which the Apple
+                               Software may be incorporated.
+
+                               The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                               WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                               WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                               PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                               COMBINATION WITH YOUR PRODUCTS.
+
+                               IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                               CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                               GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                               ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                               OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                               (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                               ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+       File Ownership:
+
+               DRI:                            Apple Macintosh Developer Technical Support
+
+               Other Contact:          For bug reports, consult the following page on
+                                                       the World Wide Web:
+                                                               http://developer.apple.com/bugreporter/
+
+               Technology:                     DTS Sample Code
+
+       Writers:
+
+               (JL)    Jim Luther
+
+       Change History (most recent first):
+
+                <3>     4/19/02        JL              [2853905]  Fixed #if test around header includes.
+                <2>     4/19/02        JL              [2853901]  Updated standard disclaimer.
+                <1>     1/25/02        JL              MoreFilesX 1.0
+       
+       Notes:
+               What do those arrows in the documentation for each routine mean?
+                       
+                       --> The parameter is an input
+                       
+                       <-- The parameter is an output. The pointer to the variable
+                               where the output will be returned (must not be NULL).
+                       
+                       <** The parameter is an optional output. If it is not a
+                               NULL pointer, it points to the variable where the output
+                               will be returned. If it is a NULL pointer, the output will
+                               not be returned and will possibly let the routine and the
+                               File Manager do less work. If you don't need an optional output,
+                               don't ask for it.
+                       **> The parameter is an optional input. If it is not a
+                               NULL pointer, it points to the variable containing the
+                               input data. If it is a NULL pointer, the input is not used
+                               and will possibly let the routine and the File Manager
+                               do less work.
+*/
+
+#ifndef __MOREFILESX__
+#define __MOREFILESX__
+
+#ifndef __CARBON__
+       #if defined(__MACH__)
+               #include <Carbon/Carbon.h>
+       #else
+               #include <Carbon.h>
+       #endif
+#endif
+
+#if PRAGMA_ONCE
+#pragma once
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if PRAGMA_IMPORT
+#pragma import on
+#endif
+
+#if PRAGMA_STRUCT_ALIGN
+       #pragma options align=mac68k
+#elif PRAGMA_STRUCT_PACKPUSH
+       #pragma pack(push, 2)
+#elif PRAGMA_STRUCT_PACK
+       #pragma pack(2)
+#endif
+
+/*****************************************************************************/
+
+#ifndef WIN32
+#pragma mark ----- FinderInfo and ExtendedFinderInfo -----
+#endif
+
+/*
+ *     FSGetFinderInfo and FSSetFinderInfo use these unions for Finder information.
+ */
+
+union FinderInfo
+{
+  FileInfo                             file;
+  FolderInfo                   folder;
+};
+typedef union FinderInfo FinderInfo;
+
+union ExtendedFinderInfo
+{
+  ExtendedFileInfo             file;
+  ExtendedFolderInfo   folder;
+};
+typedef union ExtendedFinderInfo ExtendedFinderInfo;
+
+/*****************************************************************************/
+
+#pragma mark ----- GetVolParmsInfoBuffer Macros -----
+
+/*
+ *     Macros to get information out of GetVolParmsInfoBuffer.
+ */
+
+/* version 1 field getters */
+#define GetVolParmsInfoVersion(volParms) \
+               ((volParms)->vMVersion)
+#define GetVolParmsInfoAttrib(volParms) \
+               ((volParms)->vMAttrib)
+#define GetVolParmsInfoLocalHand(volParms) \
+               ((volParms)->vMLocalHand)
+#define GetVolParmsInfoServerAdr(volParms) \
+               ((volParms)->vMServerAdr)
+
+/* version 2 field getters (assume zero result if version < 2) */
+#define GetVolParmsInfoVolumeGrade(volParms) \
+               (((volParms)->vMVersion >= 2) ? (volParms)->vMVolumeGrade : 0)
+#define GetVolParmsInfoForeignPrivID(volParms) \
+               (((volParms)->vMVersion >= 2) ? (volParms)->vMForeignPrivID : 0)
+
+/* version 3 field getters (assume zero result if version < 3) */
+#define GetVolParmsInfoExtendedAttributes(volParms) \
+               (((volParms)->vMVersion >= 3) ? (volParms)->vMExtendedAttributes : 0)
+
+/* attribute bits supported by all versions of GetVolParmsInfoBuffer */
+#define VolIsNetworkVolume(volParms) \
+               ((volParms)->vMServerAdr != 0)
+#define VolHasLimitFCBs(volParms) \
+               (((volParms)->vMAttrib & (1L << bLimitFCBs)) != 0)
+#define VolHasLocalWList(volParms) \
+               (((volParms)->vMAttrib & (1L << bLocalWList)) != 0)
+#define VolHasNoMiniFndr(volParms) \
+               (((volParms)->vMAttrib & (1L << bNoMiniFndr)) != 0)
+#define VolHasNoVNEdit(volParms) \
+               (((volParms)->vMAttrib & (1L << bNoVNEdit)) != 0)
+#define VolHasNoLclSync(volParms) \
+               (((volParms)->vMAttrib & (1L << bNoLclSync)) != 0)
+#define VolHasTrshOffLine(volParms) \
+               (((volParms)->vMAttrib & (1L << bTrshOffLine)) != 0)
+#define VolHasNoSwitchTo(volParms) \
+               (((volParms)->vMAttrib & (1L << bNoSwitchTo)) != 0)
+#define VolHasNoDeskItems(volParms) \
+               (((volParms)->vMAttrib & (1L << bNoDeskItems)) != 0)
+#define VolHasNoBootBlks(volParms) \
+               (((volParms)->vMAttrib & (1L << bNoBootBlks)) != 0)
+#define VolHasAccessCntl(volParms) \
+               (((volParms)->vMAttrib & (1L << bAccessCntl)) != 0)
+#define VolHasNoSysDir(volParms) \
+               (((volParms)->vMAttrib & (1L << bNoSysDir)) != 0)
+#define VolHasExtFSVol(volParms) \
+               (((volParms)->vMAttrib & (1L << bHasExtFSVol)) != 0)
+#define VolHasOpenDeny(volParms) \
+               (((volParms)->vMAttrib & (1L << bHasOpenDeny)) != 0)
+#define VolHasCopyFile(volParms) \
+               (((volParms)->vMAttrib & (1L << bHasCopyFile)) != 0)
+#define VolHasMoveRename(volParms) \
+               (((volParms)->vMAttrib & (1L << bHasMoveRename)) != 0)
+#define VolHasDesktopMgr(volParms) \
+               (((volParms)->vMAttrib & (1L << bHasDesktopMgr)) != 0)
+#define VolHasShortName(volParms) \
+               (((volParms)->vMAttrib & (1L << bHasShortName)) != 0)
+#define VolHasFolderLock(volParms) \
+               (((volParms)->vMAttrib & (1L << bHasFolderLock)) != 0)
+#define VolHasPersonalAccessPrivileges(volParms) \
+               (((volParms)->vMAttrib & (1L << bHasPersonalAccessPrivileges)) != 0)
+#define VolHasUserGroupList(volParms) \
+               (((volParms)->vMAttrib & (1L << bHasUserGroupList)) != 0)
+#define VolHasCatSearch(volParms) \
+               (((volParms)->vMAttrib & (1L << bHasCatSearch)) != 0)
+#define VolHasFileIDs(volParms) \
+               (((volParms)->vMAttrib & (1L << bHasFileIDs)) != 0)
+#define VolHasBTreeMgr(volParms) \
+               (((volParms)->vMAttrib & (1L << bHasBTreeMgr)) != 0)
+#define VolHasBlankAccessPrivileges(volParms) \
+               (((volParms)->vMAttrib & (1L << bHasBlankAccessPrivileges)) != 0)
+#define VolSupportsAsyncRequests(volParms) \
+               (((volParms)->vMAttrib & (1L << bSupportsAsyncRequests)) != 0)
+#define VolSupportsTrashVolumeCache(volParms) \
+               (((volParms)->vMAttrib & (1L << bSupportsTrashVolumeCache)) != 0)
+
+/* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */
+#define VolIsEjectable(volParms) \
+               ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsEjectable)) != 0)
+#define VolSupportsHFSPlusAPIs(volParms) \
+               ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsHFSPlusAPIs)) != 0)
+#define VolSupportsFSCatalogSearch(volParms) \
+               ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSCatalogSearch)) != 0)
+#define VolSupportsFSExchangeObjects(volParms) \
+               ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSExchangeObjects)) != 0)
+#define VolSupports2TBFiles(volParms) \
+               ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupports2TBFiles)) != 0)
+#define VolSupportsLongNames(volParms) \
+               ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsLongNames)) != 0)
+#define VolSupportsMultiScriptNames(volParms) \
+               ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsMultiScriptNames)) != 0)
+#define VolSupportsNamedForks(volParms) \
+               ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsNamedForks)) != 0)
+#define VolSupportsSubtreeIterators(volParms) \
+               ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSubtreeIterators)) != 0)
+#define VolL2PCanMapFileBlocks(volParms) \
+               ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bL2PCanMapFileBlocks)) != 0)
+#define VolParentModDateChanges(volParms) \
+               ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bParentModDateChanges)) != 0)
+#define VolAncestorModDateChanges(volParms) \
+               ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bAncestorModDateChanges)) != 0)
+#define VolSupportsSymbolicLinks(volParms) \
+               ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSymbolicLinks)) != 0)
+#define VolIsAutoMounted(volParms) \
+               ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsAutoMounted)) != 0)
+
+/*****************************************************************************/
+
+#pragma mark ----- userPrivileges Bit Masks and Macros -----
+
+/*
+ *     Bit masks and macros to get common information out of userPrivileges byte
+ *     returned by FSGetCatalogInfo.
+ *
+ *     Note:   The userPrivileges byte is the same as the ioACUser byte returned
+ *                     by PBGetCatInfo, and is the 1's complement of the user's privileges
+ *                     byte returned in ioACAccess by PBHGetDirAccess. That's where the
+ *                     ioACUser names came from.
+ *
+ *                     The userPrivileges are user's effective privileges based on the
+ *                     user ID and the groups that user belongs to, and the owner, group,
+ *                     and everyone privileges for the given directory.
+ */
+
+enum
+{
+       /* mask for just the access restriction bits */
+       kioACUserAccessMask             = (kioACUserNoSeeFolderMask +
+                                                          kioACUserNoSeeFilesMask +
+                                                          kioACUserNoMakeChangesMask),
+       /* common access privilege settings */
+       kioACUserFull                   = 0x00, /* no access restiction bits on */
+       kioACUserNone                   = kioACUserAccessMask, /* all access restiction bits on */
+       kioACUserDropBox                = (kioACUserNoSeeFolderMask +
+                                                          kioACUserNoSeeFilesMask), /* make changes, but not see files or folders */
+       kioACUserBulletinBoard  = kioACUserNoMakeChangesMask /* see files and folders, but not make changes */
+};
+
+
+/* Macros for testing ioACUser bits. */
+
+#define UserIsOwner(userPrivileges) \
+               (((userPrivileges) & kioACUserNotOwnerMask) == 0)
+#define UserHasFullAccess(userPrivileges)      \
+               (((userPrivileges) & (kioACUserAccessMask)) == kioACUserFull)
+#define UserHasDropBoxAccess(userPrivileges)   \
+               (((userPrivileges) & kioACUserAccessMask) == kioACUserDropBox)
+#define UserHasBulletinBoard(userPrivileges)   \
+               (((userPrivileges) & kioACUserAccessMask) == kioACUserBulletinBoard)
+#define UserHasNoAccess(userPrivileges)                \
+               (((userPrivileges) & kioACUserAccessMask) == kioACUserNone)
+
+/*****************************************************************************/
+
+#pragma mark ----- File Access Routines -----
+
+/*****************************************************************************/
+
+#pragma mark FSCopyFork
+
+OSErr
+FSCopyFork(
+       SInt16 srcRefNum,
+       SInt16 dstRefNum,
+       void *copyBufferPtr,
+       ByteCount copyBufferSize);
+
+/*
+       The FSCopyFork function copies all data from the source fork to the
+       destination fork of open file forks and makes sure the destination EOF
+       is equal to the source EOF.
+
+       srcRefNum                       --> The source file reference number.
+       dstRefNum                       --> The destination file reference number.
+       copyBufferPtr           --> Pointer to buffer to use during copy. The
+                                                       buffer should be at least 4K-bytes minimum.
+                                                       The larger the buffer, the faster the copy
+                                                       (up to a point).
+       copyBufferSize          --> The size of the copy buffer.
+*/
+
+/*****************************************************************************/
+
+#pragma mark ----- Volume Access Routines -----
+
+/*****************************************************************************/
+
+#pragma mark FSGetVolParms
+
+OSErr
+FSGetVolParms(
+       FSVolumeRefNum volRefNum,
+       UInt32 bufferSize,
+       GetVolParmsInfoBuffer *volParmsInfo,
+       UInt32 *actualInfoSize);
+
+/*
+       The FSGetVolParms function returns information about the characteristics
+       of a volume. A result of paramErr usually just means the volume doesn't
+       support GetVolParms and the feature you were going to check
+       for isn't available.
+       
+       volRefNum                       --> Volume specification.
+       bufferSize                      --> Size of buffer pointed to by volParmsInfo.
+       volParmsInfo            <-- A GetVolParmsInfoBuffer record where the volume
+                                                       attributes information is returned.
+       actualInfoSize          <-- The number of bytes actually returned
+                                                       in volParmsInfo.
+       
+       __________
+       
+       Also see:       The GetVolParmsInfoBuffer Macros for checking attribute bits
+                               in this file
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetVRefNum
+
+OSErr
+FSGetVRefNum(
+       const FSRef *ref,
+       FSVolumeRefNum *vRefNum);
+
+/*
+       The FSGetVRefNum function determines the volume reference
+       number of a volume from a FSRef.
+
+       ref                                     --> The FSRef.
+       vRefNum                         <-- The volume reference number.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetVInfo
+
+OSErr
+FSGetVInfo(
+       FSVolumeRefNum volume,
+       HFSUniStr255 *volumeName,       /* can be NULL */
+       UInt64 *freeBytes,                      /* can be NULL */
+       UInt64 *totalBytes);            /* can be NULL */
+
+/*
+       The FSGetVInfo function returns the name, available space (in bytes),
+       and total space (in bytes) for the specified volume.
+
+       volume                          --> The volume reference number.
+       volumeName                      <** An optional pointer to a HFSUniStr255.
+                                                       If not NULL, the volume name will be returned in
+                                                       the HFSUniStr255.
+       freeBytes                       <** An optional pointer to a UInt64.
+                                                       If not NULL, the number of free bytes on the
+                                                       volume will be returned in the UInt64.
+       totalBytes                      <** An optional pointer to a UInt64.
+                                                       If not NULL, the total number of bytes on the
+                                                       volume will be returned in the UInt64.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetVolFileSystemID
+
+OSErr
+FSGetVolFileSystemID(
+       FSVolumeRefNum volume,
+       UInt16 *fileSystemID,   /* can be NULL */
+       UInt16 *signature);             /* can be NULL */
+
+/*
+       The FSGetVolFileSystemID function returns the file system ID and signature
+       of a mounted volume. The file system ID identifies the file system
+       that handles requests to a particular volume. The signature identifies the
+       volume type of the volume (for example, FSID 0 is Macintosh HFS Plus, HFS
+       or MFS, where a signature of 0x4244 identifies the volume as HFS).
+       Here's a partial list of file system ID numbers (only Apple's file systems
+       are listed):
+               FSID    File System
+               -----   -----------------------------------------------------
+               $0000   Macintosh HFS Plus, HFS or MFS
+               $0100   ProDOS File System
+               $0101   PowerTalk Mail Enclosures
+               $4147   ISO 9660 File Access (through Foreign File Access)
+               $4242   High Sierra File Access (through Foreign File Access)
+               $464D   QuickTake File System (through Foreign File Access)
+               $4953   Macintosh PC Exchange (MS-DOS)
+               $4A48   Audio CD Access (through Foreign File Access)
+               $4D4B   Apple Photo Access (through Foreign File Access)
+               $6173   AppleShare (later versions of AppleShare only)
+       
+       See the Technical Note "FL 35 - Determining Which File System
+       Is Active" and the "Guide to the File System Manager" for more
+       information.
+       
+       volume                          --> The volume reference number.
+       fileSystemID            <** An optional pointer to a UInt16.
+                                                       If not NULL, the volume's file system ID will
+                                                       be returned in the UInt16.
+       signature                       <** An optional pointer to a UInt16.
+                                                       If not NULL, the volume's signature will
+                                                       be returned in the UInt16.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetMountedVolumes
+
+OSErr
+FSGetMountedVolumes(
+       FSRef ***volumeRefsHandle,      /* pointer to handle of FSRefs */
+       ItemCount *numVolumes);
+
+/*
+       The FSGetMountedVolumes function returns the list of volumes currently
+       mounted in an array of FSRef records. The array of FSRef records is
+       returned in a Handle, volumeRefsHandle, which is allocated by
+       FSGetMountedVolumes. The caller is responsible for disposing of
+       volumeRefsHandle if the FSGetMountedVolumes returns noErr.
+               
+       volumeRefsHandle        <-- Pointer to an FSRef Handle where the array of
+                                                       FSRefs is to be returned.
+       numVolumes                      <-- The number of volumes returned in the array.
+*/
+
+/*****************************************************************************/
+
+#pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines -----
+
+/*****************************************************************************/
+
+#pragma mark FSRefMakeFSSpec
+
+OSErr
+FSRefMakeFSSpec(
+       const FSRef *ref,
+       FSSpec *spec);
+
+/*
+       The FSRefMakeFSSpec function returns an FSSpec for the file or
+       directory specified by the ref parameter.
+
+       ref                                     --> An FSRef specifying the file or directory.
+       spec                            <-- The FSSpec.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSMakeFSRef
+
+OSErr
+FSMakeFSRef(
+       FSVolumeRefNum volRefNum,
+       SInt32 dirID,
+       ConstStr255Param name,
+       FSRef *ref);
+
+/*
+       The FSMakeFSRef function creates an FSRef from the traditional
+       volume reference number, directory ID and pathname inputs. It is
+       functionally equivalent to FSMakeFSSpec followed by FSpMakeFSRef.
+       
+       volRefNum                       --> Volume specification.
+       dirID                           --> Directory specification.
+       name                            --> The file or directory name, or NULL.
+       ref                                     <-- The FSRef.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSMakePath
+
+OSStatus
+FSMakePath(
+       SInt16 vRefNum,
+       SInt32 dirID,
+       ConstStr255Param name,
+       UInt8 *path,
+       UInt32 maxPathSize);
+
+/*
+       The FSMakePath function creates a pathname from the traditional volume reference
+       number, directory ID, and pathname inputs. It is functionally equivalent to
+       FSMakeFSSpec, FSpMakeFSRef, FSRefMakePath.
+       
+       volRefNum                       --> Volume specification.
+       dirID                           --> Directory specification.
+       name                            --> The file or directory name, or NULL.
+       path                            <-- A pointer to a buffer which FSMakePath will
+                                                       fill with a C string representing the pathname
+                                                       to the file or directory specified. The format of
+                                                       the pathname returned can be determined with the
+                                                       Gestalt selector gestaltFSAttr's
+                                                       gestaltFSUsesPOSIXPathsForConversion bit.
+                                                       If the gestaltFSUsesPOSIXPathsForConversion bit is
+                                                       clear, the pathname is a Mac OS File Manager full
+                                                       pathname in a C string, and file or directory names
+                                                       in the pathname may be mangled as returned by
+                                                       the File Manager. If the
+                                                       gestaltFSUsesPOSIXPathsForConversion bit is set,
+                                                       the pathname is a UTF8 encoded POSIX absolute
+                                                       pathname in a C string. In either case, the
+                                                       pathname returned can be passed back to
+                                                       FSPathMakeRef to create an FSRef to the file or
+                                                       directory, or FSPathMakeFSSpec to craete an FSSpec
+                                                       to the file or directory.
+       maxPathSize                     --> The size of the path buffer in bytes. If the path
+                                                       buffer is too small for the pathname string,
+                                                       FSMakePath returns pathTooLongErr or
+                                                       buffersTooSmall.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSPathMakeFSSpec
+
+OSStatus
+FSPathMakeFSSpec(
+       const UInt8 *path,
+       FSSpec *spec,
+       Boolean *isDirectory);  /* can be NULL */
+
+/*
+       The FSPathMakeFSSpec function converts a pathname to an FSSpec.
+       
+       path                            --> A pointer to a C String that is the pathname. The
+                                                       format of the pathname you must supply can be
+                                                       determined with the Gestalt selector gestaltFSAttr's
+                                                       gestaltFSUsesPOSIXPathsForConversion bit.
+                                                       If the gestaltFSUsesPOSIXPathsForConversion bit is
+                                                       clear, the pathname must be a Mac OS File Manager
+                                                       full pathname in a C string. If the
+                                                       gestaltFSUsesPOSIXPathsForConversion bit is set,
+                                                       the pathname must be a UTF8 encoded POSIX absolute
+                                                       pathname in a C string.
+       spec                            <-- The FSSpec.
+       isDirectory                     <** An optional pointer to a Boolean.
+                                                       If not NULL, true will be returned in the Boolean
+                                                       if the specified path is a directory, or false will
+                                                       be returned in the Boolean if the specified path is
+                                                       a file.
+*/
+
+/*****************************************************************************/
+
+#pragma mark UnicodeNameGetHFSName
+
+OSErr
+UnicodeNameGetHFSName(
+       UniCharCount nameLength,
+       const UniChar *name,
+       TextEncoding textEncodingHint,
+       Boolean isVolumeName,
+       Str31 hfsName);
+
+/*
+       The UnicodeNameGetHFSName function converts a Unicode string
+       to a Pascal Str31 (or Str27) string using an algorithm similar to that used
+       by the File Manager. Note that if the name is too long or cannot be converted
+       using the given text encoding hint, you will get an error instead of the
+       mangled name that the File Manager would return.
+       
+       nameLength                      --> Number of UniChar in name parameter.
+       name                            --> The Unicode string to convert.
+       textEncodingHint        --> The text encoding hint used for the conversion.
+                                                       You can pass kTextEncodingUnknown to use the
+                                                       "default" textEncodingHint.
+       isVolumeName            --> If true, the output name will be limited to
+                                                       27 characters (kHFSMaxVolumeNameChars). If false,
+                                                       the output name will be limited to 31 characters
+                                                       (kHFSMaxFileNameChars).
+       hfsName                         <-- The hfsName as a Pascal string.
+       
+       __________
+       
+       Also see:       HFSNameGetUnicodeName
+*/
+
+/*****************************************************************************/
+
+#pragma mark HFSNameGetUnicodeName
+
+OSErr
+HFSNameGetUnicodeName(
+       ConstStr31Param hfsName,
+       TextEncoding textEncodingHint,
+       HFSUniStr255 *unicodeName);
+
+/*
+       The HFSNameGetUnicodeName function converts a Pascal Str31 string to an
+       Unicode HFSUniStr255 string using the same routines as the File Manager.
+       
+       hfsName                         --> The Pascal string to convert.
+       textEncodingHint        --> The text encoding hint used for the conversion.
+                                                       You can pass kTextEncodingUnknown to use the
+                                                       "default" textEncodingHint.
+       unicodeName                     <-- The Unicode string.
+       
+       __________
+       
+       Also see:       UnicodeNameGetHFSName
+*/
+
+/*****************************************************************************/
+
+#pragma mark ----- File/Directory Manipulation Routines -----
+
+/*****************************************************************************/
+
+#pragma mark FSRefValid
+
+Boolean FSRefValid(const FSRef *ref);
+
+/*
+       The FSRefValid function determines if an FSRef is valid. If the result is
+       true, then the FSRef refers to an existing file or directory.
+       
+       ref                                     --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetParentRef
+
+OSErr
+FSGetParentRef(
+       const FSRef *ref,
+       FSRef *parentRef);
+
+/*
+       The FSGetParentRef function gets the parent directory FSRef of the
+       specified object.
+       
+       Note: FSRefs always point to real file system objects. So, there cannot
+       be a FSRef to the parent of volume root directories. If you call
+       FSGetParentRef with a ref to the root directory of a volume, the
+       function result will be noErr and the parentRef will be invalid (using it
+       for other file system requests will fail).
+
+       ref                                     --> FSRef to a file or directory.
+       parentRef                       <-- The parent directory's FSRef.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetFileDirName
+
+OSErr
+FSGetFileDirName(
+       const FSRef *ref,
+       HFSUniStr255 *outName);
+
+/*
+       The FSGetFileDirName function gets the name of the file or directory
+       specified.
+
+       ref                                     --> FSRef to a file or directory.
+       outName                         <-- The file or directory name.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetNodeID
+
+OSErr
+FSGetNodeID(
+       const FSRef *ref,
+       long *nodeID,                   /* can be NULL */
+       Boolean *isDirectory);  /* can be NULL */
+
+/*
+       The GetNodeIDFromFSRef function gets the node ID number of the
+       file or directory specified (note: the node ID is the directory ID
+       for directories).
+
+       ref                                     --> FSRef to a file or directory.
+       nodeID                          <** An optional pointer to a long.
+                                                       If not NULL, the node ID will be returned in
+                                                       the long.
+       isDirectory                     <** An optional pointer to a Boolean.
+                                                       If not NULL, true will be returned in the Boolean
+                                                       if the object is a directory, or false will be
+                                                       returned in the Boolean if object is a file.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetUserPrivilegesPermissions
+
+OSErr
+FSGetUserPrivilegesPermissions(
+       const FSRef *ref,
+       UInt8 *userPrivileges,          /* can be NULL */
+       UInt32 permissions[4]);         /* can be NULL */
+
+/*
+       The FSGetUserPrivilegesPermissions function gets the userPrivileges and/or
+       permissions of the file or directory specified.
+
+       ref                                     --> FSRef to a file or directory.
+       userPrivileges          <** An optional pointer to a UInt8.
+                                                       If not NULL, the userPrivileges will be returned
+                                                       in the UInt8.
+       permissions                     <** An optional pointer to an UInt32[4] array.
+                                                       If not NULL, the permissions will be returned
+                                                       in the UInt32[4] array.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSCheckLock
+
+OSErr
+FSCheckLock(
+       const FSRef *ref);
+
+/*
+       The FSCheckLock function determines if a file or directory is locked.
+       If FSCheckLock returns noErr, then the file or directory is not locked
+       and the volume it is on is not locked either. If FSCheckLock returns
+       fLckdErr, then the file or directory is locked. If FSCheckLock returns
+       wPrErr, then the volume is locked by hardware (i.e., locked tab on
+       removable media). If FSCheckLock returns vLckdErr, then the volume is
+       locked by software.
+       
+       ref                                     --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetForkSizes
+
+OSErr
+FSGetForkSizes(
+       const FSRef *ref,
+       UInt64 *dataLogicalSize,        /* can be NULL */
+       UInt64 *rsrcLogicalSize);       /* can be NULL */
+
+/*
+       The FSGetForkSizes returns the size of the data and/or resource fork for
+       the specified file.
+       
+       ref                                     --> FSRef to a file or directory.
+       dataLogicalSize         <** An optional pointer to a UInt64.
+                                                       If not NULL, the data fork's size will be
+                                                       returned in the UInt64.
+       rsrcLogicalSize         <** An optional pointer to a UInt64.
+                                                       If not NULL, the resource fork's size will be
+                                                       returned in the UInt64.
+       
+       __________
+       
+       Also see:       FSGetTotalForkSizes
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetTotalForkSizes
+
+OSErr
+FSGetTotalForkSizes(
+       const FSRef *ref,
+       UInt64 *totalLogicalSize,       /* can be NULL */
+       UInt64 *totalPhysicalSize,      /* can be NULL */
+       ItemCount *forkCount);          /* can be NULL */
+
+/*
+       The FSGetTotalForkSizes returns the total logical size and/or the total
+       physical size of the specified file (i.e., it adds the sizes of all file
+       forks). It optionally returns the number of file forks.
+       
+       ref                                     --> FSRef to a file or directory.
+       totalLogicalSize        <** An optional pointer to a UInt64.
+                                                       If not NULL, the sum of all fork logical sizes
+                                                       will be returned in the UInt64.
+       totalPhysicalSize       <** An optional pointer to a UInt64.
+                                                       If not NULL, the sum of all fork physical sizes
+                                                       will be returned in the UInt64.
+       forkCount                       <** An optional pointer to a ItemCount.
+                                                       If not NULL, the number of file forks
+                                                       will be returned in the ItemCount.
+       
+       __________
+       
+       Also see:       FSGetForkSizes
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSBumpDate
+
+OSErr
+FSBumpDate(
+       const FSRef *ref);
+
+/*
+       The FSBumpDate function changes the content modification date of a file
+       or directory to the current date/time. If the content modification date
+       is already equal to the current date/time, then add one second to the
+       content modification date.
+
+       ref                                     --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetFinderInfo
+
+OSErr
+FSGetFinderInfo(
+       const FSRef *ref,
+       FinderInfo *info,                                       /* can be NULL */
+       ExtendedFinderInfo *extendedInfo,       /* can be NULL */
+       Boolean *isDirectory);                          /* can be NULL */
+
+/*
+       The FSGetFinderInfo function gets the finder information for a file or
+       directory.
+
+       ref                                     --> FSRef to a file or directory.
+       info                            <** An optional pointer to a FinderInfo.
+                                                       If not NULL, the FileInfo (if ref is a file) or
+                                                       the FolderInfo (if ref is a folder) will be
+                                                       returned in the FinderInfo.
+       extendedInfo            <** An optional pointer to a ExtendedFinderInfo.
+                                                       If not NULL, the ExtendedFileInfo (if ref is a file)
+                                                       or the ExtendedFolderInfo (if ref is a folder) will
+                                                       be returned in the ExtendedFinderInfo.
+       isDirectory                     <** An optional pointer to a Boolean.
+                                                       If not NULL, true will be returned in the Boolean
+                                                       if the object is a directory, or false will be
+                                                       returned in the Boolean if object is a file.
+
+       __________
+
+       Also see:       FSSetFinderInfo
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSSetFinderInfo
+
+OSErr
+FSSetFinderInfo(
+       const FSRef *ref,
+       const FinderInfo *info,                                         /* can be NULL */
+       const ExtendedFinderInfo *extendedInfo);        /* can be NULL */
+
+/*
+       The FSSetFinderInfo function sets the finder information for a file or
+       directory.
+
+       ref                                     --> FSRef to a file or directory.
+       info                            **> A pointer to a FinderInfo record with the new
+                                                       FileInfo (if ref is a file) or new FolderInfo
+                                                       (if ref is a folder), or NULL if the FinderInfo
+                                                       is not to be changed.
+       extendedInfo            **> A pointer to a FinderInfo record with the new
+                                                       ExtendedFileInfo (if ref is a file) or new
+                                                       ExtendedFolderInfo (if ref is a folder), or NULL
+                                                       if the ExtendedFinderInfo is not to be changed.
+               
+       __________
+
+       Also see:       FSGetFinderInfo
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSChangeCreatorType
+
+OSErr
+FSChangeCreatorType(
+       const FSRef *ref,
+       OSType fileCreator,
+       OSType fileType);
+
+/*
+       The FSChangeCreatorType function changes the creator and/or file type of a file.
+
+       ref                                     --> FSRef to a file.
+       creator                         --> The new creator type or 0x00000000 to leave
+                                                       the creator type alone.
+       fileType                        --> The new file type or 0x00000000 to leave the
+                                                       file type alone.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSChangeFinderFlags
+
+OSErr
+FSChangeFinderFlags(
+       const FSRef *ref,
+       Boolean setBits,
+       UInt16 flagBits);
+
+/*
+       The FSChangeFinderFlags function sets or clears flag bits in
+       the finderFlags field of a file's FileInfo record or a
+       directory's FolderInfo record.
+
+       ref                                     --> FSRef to a file or directory.
+       setBits                         --> If true, then set the bits specified in flagBits.
+                                                       If false, then clear the bits specified in flagBits.
+       flagBits                        --> The flagBits parameter specifies which Finder Flag
+                                                       bits to set or clear. If a bit in flagBits is set,
+                                                       then the same bit in fdFlags is either set or
+                                                       cleared depending on the state of the setBits
+                                                       parameter.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSSetInvisible
+
+OSErr
+FSSetInvisible(
+       const FSRef *ref);
+
+#pragma mark FSClearInvisible
+
+OSErr
+FSClearInvisible(
+       const FSRef *ref);
+
+/*
+       The FSSetInvisible and FSClearInvisible functions set or clear the
+       kIsInvisible bit in the finderFlags field of the specified file or
+       directory's finder information.
+
+       ref                                     --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSSetNameLocked
+
+OSErr
+FSSetNameLocked(
+       const FSRef *ref);
+
+#pragma mark FSClearNameLocked
+
+OSErr
+FSClearNameLocked(
+       const FSRef *ref);
+
+/*
+       The FSSetNameLocked and FSClearNameLocked functions set or clear the
+       kNameLocked bit bit in the finderFlags field of the specified file or
+       directory's finder information.
+
+       ref                                     --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSSetIsStationery
+
+OSErr
+FSSetIsStationery(
+       const FSRef *ref);
+
+#pragma mark FSClearIsStationery
+
+OSErr
+FSClearIsStationery(
+       const FSRef *ref);
+
+/*
+       The FSSetIsStationery and FSClearIsStationery functions set or clear the
+       kIsStationery bit bit in the finderFlags field of the specified file or
+       directory's finder information.
+
+       ref                                     --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSSetHasCustomIcon
+
+OSErr
+FSSetHasCustomIcon(
+       const FSRef *ref);
+
+#pragma mark FSClearHasCustomIcon
+
+OSErr
+FSClearHasCustomIcon(
+       const FSRef *ref);
+
+/*
+       The FSSetHasCustomIcon and FSClearHasCustomIcon functions set or clear the
+       kHasCustomIcon bit bit in the finderFlags field of the specified file or
+       directory's finder information.
+
+       ref                                     --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSClearHasBeenInited
+
+OSErr
+FSClearHasBeenInited(
+       const FSRef *ref);
+
+/*
+       The FSClearHasBeenInited function clears the kHasBeenInited bit in the
+       finderFlags field of the specified file or directory's finder information.
+       
+       Note:   There is no FSSetHasBeenInited function because ONLY the Finder
+                       should set the kHasBeenInited bit.
+
+       ref                                     --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSCopyFileMgrAttributes
+
+OSErr
+FSCopyFileMgrAttributes(
+       const FSRef *sourceRef,
+       const FSRef *destinationRef,
+       Boolean copyLockBit);
+
+/*
+       The CopyFileMgrAttributes function copies all File Manager attributes
+       from the source file or directory to the destination file or directory.
+       If copyLockBit is true, then set the locked state of the destination
+       to match the source.
+
+       sourceRef                       --> FSRef to a file or directory.
+       destinationRef          --> FSRef to a file or directory.
+       copyLockBit                     --> If true, set the locked state of the destination
+                                                       to match the source.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSMoveRenameObjectUnicode
+
+OSErr
+FSMoveRenameObjectUnicode(
+       const FSRef *ref,
+       const FSRef *destDirectory,
+       UniCharCount nameLength,
+       const UniChar *name,                    /* can be NULL (no rename during move) */
+       TextEncoding textEncodingHint,
+       FSRef *newRef);                                 /* if function fails along the way, newRef is final location of file */
+
+/*
+       The FSMoveRenameObjectUnicode function moves a file or directory and
+       optionally renames it.  The source and destination locations must be on
+       the same volume.
+       
+       Note:   If the input ref parameter is invalid, this call will fail and
+                       newRef, like ref, will be invalid.
+
+       ref                                     --> FSRef to a file or directory.
+       destDirectory           --> FSRef to the destination directory.
+       nameLength                      --> Number of UniChar in name parameter.
+       name                            --> An Unicode string with the new name for the
+                                                       moved object, or NULL if no rename is wanted.
+       textEncodingHint        --> The text encoding hint used for the rename.
+                                                       You can pass kTextEncodingUnknown to use the
+                                                       "default" textEncodingHint.
+       newRef                          <-- The new FSRef of the object moved. Note that if
+                                                       this function fails at any step along the way,
+                                                       newRef is still then final location of the object.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSDeleteContainerContents
+
+OSErr
+FSDeleteContainerContents(
+       const FSRef *container);
+
+/*
+       The FSDeleteContainerContents function deletes the contents of a container
+       directory. All files and subdirectories in the specified container are
+       deleted. If a locked file or directory is encountered, it is unlocked and
+       then deleted. If any unexpected errors are encountered,
+       FSDeleteContainerContents quits and returns to the caller.
+       
+       container                       --> FSRef to a directory.
+       
+       __________
+       
+       Also see:       FSDeleteContainer
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSDeleteContainer
+
+OSErr
+FSDeleteContainer(
+       const FSRef *container);
+
+/*
+       The FSDeleteContainer function deletes a container directory and its contents.
+       All files and subdirectories in the specified container are deleted.
+       If a locked file or directory is encountered, it is unlocked and then
+       deleted.  After deleting the container's contents, the container is
+       deleted. If any unexpected errors are encountered, FSDeleteContainer
+       quits and returns to the caller.
+       
+       container                       --> FSRef to a directory.
+       
+       __________
+       
+       Also see:       FSDeleteContainerContents
+*/
+
+/*****************************************************************************/
+
+#pragma mark IterateContainerFilterProcPtr
+
+typedef CALLBACK_API( Boolean , IterateContainerFilterProcPtr ) (
+       Boolean containerChanged,
+       ItemCount currentLevel,
+       const FSCatalogInfo *catalogInfo,
+       const FSRef *ref,
+       const FSSpec *spec,
+       const HFSUniStr255 *name,
+       void *yourDataPtr);
+
+/*
+       This is the prototype for the IterateContainerFilterProc function which
+       is called once for each file and directory found by FSIterateContainer.
+       The IterateContainerFilterProc can use the read-only data it receives for
+       whatever it wants.
+
+       The result of the IterateContainerFilterProc function indicates if
+       iteration should be stopped. To stop iteration, return true; to continue
+       iteration, return false.
+
+       The yourDataPtr parameter can point to whatever data structure you might
+       want to access from within the IterateContainerFilterProc.
+
+       containerChanged        --> Set to true if the container's contents changed
+                                                       during iteration.
+       currentLevel            --> The current recursion level into the container.
+                                                       1 = the container, 2 = the container's immediate
+                                                       subdirectories, etc.
+       catalogInfo                     --> The catalog information for the current object.
+                                                       Only the fields requested by the whichInfo
+                                                       parameter passed to FSIterateContainer are valid.
+       ref                                     --> The FSRef to the current object.
+       spec                            --> The FSSpec to the current object if the wantFSSpec
+                                                       parameter passed to FSIterateContainer is true.
+       name                            --> The name of the current object if the wantName
+                                                       parameter passed to FSIterateContainer is true.
+       yourDataPtr                     --> An optional pointer to whatever data structure you
+                                                       might want to access from within the
+                                                       IterateFilterProc.
+       result                          <-- To stop iteration, return true; to continue
+                                                       iteration, return false.
+
+       __________
+
+       Also see:       FSIterateContainer
+*/
+
+/*****************************************************************************/
+
+#pragma mark CallIterateContainerFilterProc
+
+#define CallIterateContainerFilterProc(userRoutine, containerChanged, currentLevel, catalogInfo, ref, spec, name, yourDataPtr) \
+       (*(userRoutine))((containerChanged), (currentLevel), (catalogInfo), (ref), (spec), (name), (yourDataPtr))
+
+/*****************************************************************************/
+
+#pragma mark FSIterateContainer
+
+OSErr
+FSIterateContainer(
+       const FSRef *container,
+       ItemCount maxLevels,
+       FSCatalogInfoBitmap whichInfo,
+       Boolean wantFSSpec,
+       Boolean wantName,
+       IterateContainerFilterProcPtr iterateFilter,
+       void *yourDataPtr);
+
+/*
+       The FSIterateContainer function performs a recursive iteration (scan) of the
+       specified container directory and calls your IterateContainerFilterProc
+       function once for each file and directory found.
+
+       The maxLevels parameter lets you control how deep the recursion goes.
+       If maxLevels is 1, FSIterateContainer only scans the specified directory;
+       if maxLevels is 2, FSIterateContainer scans the specified directory and
+       one subdirectory below the specified directory; etc. Set maxLevels to
+       zero to scan all levels.
+
+       The yourDataPtr parameter can point to whatever data structure you might
+       want to access from within your IterateContainerFilterProc.
+
+       container                       --> The FSRef to the container directory to iterate.
+       maxLevels                       --> Maximum number of directory levels to scan or
+                                                       zero to scan all directory levels.
+       whichInfo                       --> The fields of the FSCatalogInfo you wish to get.
+       wantFSSpec                      --> Set to true if you want the FSSpec to each
+                                                       object passed to your IterateContainerFilterProc.
+       wantName                        --> Set to true if you want the name of each
+                                                       object passed to your IterateContainerFilterProc.
+       iterateFilter           --> A pointer to the IterateContainerFilterProc you
+                                                       want called once for each file and directory found
+                                                       by FSIterateContainer.
+       yourDataPtr                     --> An optional pointer to whatever data structure you
+                                                       might want to access from within the
+                                                       IterateFilterProc.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetDirectoryItems
+
+OSErr
+FSGetDirectoryItems(
+       const FSRef *container,
+       FSRef ***refsHandle,    /* pointer to handle of FSRefs */
+       ItemCount *numRefs,
+       Boolean *containerChanged);
+
+/*
+       The FSGetDirectoryItems function returns the list of items in the specified
+       container. The array of FSRef records is returned in a Handle, refsHandle,
+       which is allocated by FSGetDirectoryItems. The caller is responsible for
+       disposing of refsHandle if the FSGetDirectoryItems returns noErr.
+               
+       container                       --> FSRef to a directory.
+       refsHandle                      <-- Pointer to an FSRef Handle where the array of
+                                                       FSRefs is to be returned.
+       numRefs                         <-- The number of FSRefs returned in the array.
+       containerChanged        <-- Set to true if the container changes while the
+                                                       list of items is being obtained.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSExchangeObjectsCompat
+
+OSErr
+FSExchangeObjectsCompat(
+       const FSRef *sourceRef,
+       const FSRef *destRef,
+       FSRef *newSourceRef,
+       FSRef *newDestRef);
+
+/*
+       The FSExchangeObjectsCompat function exchanges the data between two files.
+       
+       The FSExchangeObjectsCompat function is an enhanced version of
+       FSExchangeObjects function. The two enhancements FSExchangeObjectsCompat
+       provides are:
+       
+       1,      FSExchangeObjectsCompat will work on volumes which do not support
+               FSExchangeObjects. FSExchangeObjectsCompat does this by emulating
+               FSExchangeObjects through a series of File Manager operations. If
+               there is a failure at any step along the way, FSExchangeObjectsCompat
+               attempts to undo any steps already taken to leave the files in their
+               original state in their original locations.
+               
+       2.      FSExchangeObjectsCompat returns new FSRefs to the source and
+               destination files. Note that if this function fails at any step along
+               the way, newSourceRef and newDestRef still give you access to the final
+               locations of the files being exchanged -- even if they are renamed or
+               not in their original locations.
+
+       sourceRef                       --> FSRef to the source file.
+       destRef                         --> FSRef to the destination file.
+       newSourceRef            <-- The new FSRef to the source file.
+       newDestRef                      <-- The new FSRef to the destination file.
+*/
+
+/*****************************************************************************/
+
+#pragma mark ----- Shared Environment Routines -----
+
+/*****************************************************************************/
+
+#pragma mark FSLockRange
+
+OSErr
+FSLockRange(
+       SInt16 refNum,
+       SInt32 rangeLength,
+       SInt32 rangeStart);
+
+/*
+       The LockRange function locks (denies access to) a portion of a file
+       that was opened with shared read/write permission.
+
+       refNum                          --> The file reference number of an open file.
+       rangeLength                     --> The number of bytes in the range.
+       rangeStart                      --> The starting byte in the range to lock.
+
+       __________
+
+       Also see:       UnlockRange
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSUnlockRange
+
+OSErr
+FSUnlockRange(
+       SInt16 refNum,
+       SInt32 rangeLength,
+       SInt32 rangeStart);
+
+/*
+       The UnlockRange function unlocks (allows access to) a previously locked
+       portion of a file that was opened with shared read/write permission.
+
+       refNum                          --> The file reference number of an open file.
+       rangeLength                     --> The number of bytes in the range.
+       rangeStart                      --> The starting byte in the range to unlock.
+
+       __________
+
+       Also see:       LockRange
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetDirAccess
+
+OSErr
+FSGetDirAccess(
+       const FSRef *ref,
+       SInt32 *ownerID,                /* can be NULL */
+       SInt32 *groupID,                /* can be NULL */
+       SInt32 *accessRights);  /* can be NULL */
+
+/*
+       The FSGetDirAccess function retrieves the directory access control
+       information for a directory on a shared volume.
+
+       ref                                     --> An FSRef specifying the directory.
+       ownerID                         <** An optional pointer to a SInt32.
+                                                       If not NULL, the directory's owner ID
+                                                       will be returned in the SInt32.
+       groupID                         <** An optional pointer to a SInt32.
+                                                       If not NULL, the directory's group ID, or 0
+                                                       if no group affiliation, will be returned in
+                                                       the SInt32.
+       accessRights            <** An optional pointer to a SInt32.
+                                                       If not NULL, the directory's access rights
+                                                       will be returned in the SInt32.
+
+       __________
+
+       Also see:       FSSetDirAccess, FSMapID, FSMapName
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSSetDirAccess
+
+OSErr
+FSSetDirAccess(
+       const FSRef *ref,
+       SInt32 ownerID,
+       SInt32 groupID,
+       SInt32 accessRights);
+
+/*
+       The FSpSetDirAccess function changes the directory access control
+       information for a directory on a shared volume. You must be the owner of
+       a directory to change its access control information.
+       
+       ref                                     --> An FSRef specifying the directory.
+       ownerID                         --> The directory's owner ID.
+       groupID                         --> The directory's group ID or 0 if no group affiliation.
+       accessRights            --> The directory's access rights.
+       
+       __________
+       
+       Also see:       FSGetDirAccess, FSMapID, FSMapName
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetVolMountInfoSize
+
+OSErr
+FSGetVolMountInfoSize(
+       FSVolumeRefNum volRefNum,
+       SInt16 *size);
+
+/*
+       The FSGetVolMountInfoSize function determines the how much space the
+       program needs to allocate for a volume mounting information record.
+
+       volRefNum                       --> Volume specification.
+       size                            <-- The space needed (in bytes) of the volume
+                                                       mounting information record.
+
+       __________
+
+       Also see:       FSGetVolMountInfo, VolumeMount
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetVolMountInfo
+
+OSErr
+FSGetVolMountInfo(
+       FSVolumeRefNum volRefNum,
+       void *volMountInfo);
+
+/*
+       The FSGetVolMountInfo function retrieves a volume mounting information
+       record containing all the information needed to mount the volume,
+       except for passwords.
+
+       volRefNum                       --> Volume specification.
+       volMountInfo            <-- The volume mounting information.
+
+       __________
+
+       Also see:       FSGetVolMountInfoSize, VolumeMount
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSVolumeMount
+
+OSErr
+FSVolumeMount(
+       const void *volMountInfo,
+       FSVolumeRefNum *volRefNum);
+
+/*
+       The VolumeMount function mounts a volume using a volume mounting
+       information record.
+
+       volMountInfo            --> A volume mounting information record.
+       volRefNum                       <-- The volume reference number.
+
+       __________
+
+       Also see:       FSGetVolMountInfoSize, FSGetVolMountInfo
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSMapID
+
+OSErr
+FSMapID(
+       FSVolumeRefNum volRefNum,
+       SInt32 ugID,
+       SInt16 objType,
+       Str31 name);
+
+/*
+       The FSMapID function determines the name of a user or group if you know
+       the user or group ID.
+
+       volRefNum                       --> Volume specification.
+       objType                         --> The mapping function code:
+                                                       kOwnerID2Name to map a user ID to a user name
+                                                       kGroupID2Name to map a group ID to a group name
+       name                            <** An optional pointer to a buffer (minimum Str31).
+                                                       If not NULL, the user or group name
+                                                       will be returned in the buffer.
+
+       __________
+
+       Also see:       FSGetDirAccess, FSSetDirAccess, FSMapName
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSMapName
+
+OSErr
+FSMapName(
+       FSVolumeRefNum volRefNum,
+       ConstStr255Param name,
+       SInt16 objType,
+       SInt32 *ugID);
+
+/*
+       The FSMapName function determines the user or group ID if you know the
+       user or group name.
+       
+       volRefNum                       --> Volume specification.
+       name                            --> The user or group name.
+       objType                         --> The mapping function code:
+                                                       kOwnerName2ID to map a user name to a user ID
+                                                       kGroupName2ID to map a user name to a group ID
+       ugID                            <-- The user or group ID.
+
+       __________
+       
+       Also see:       FSGetDirAccess, FSSetDirAccess, FSMapID
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSCopyFile
+
+OSErr
+FSCopyFile(
+       const FSRef *srcFileRef,
+       const FSRef *dstDirectoryRef,
+       UniCharCount nameLength,
+       const UniChar *copyName,        /* can be NULL (no rename during copy) */
+       TextEncoding textEncodingHint,
+       FSRef *newRef);                         /* can be NULL */
+
+/*
+       The FSCopyFile function duplicates a file and optionally renames it.
+       The source and destination volumes must be on the same file server.
+       This function instructs the server to copy the file.
+       
+       srcFileRef                      --> An FSRef specifying the source file.
+       dstDirectoryRef         --> An FSRef specifying the destination directory.
+       nameLength                      --> Number of UniChar in copyName parameter (ignored
+                                                       if copyName is NULL).
+       copyName                        --> Points to the new file name if the file is to be
+                                                       renamed, or NULL if the file isn't to be renamed.
+       textEncodingHint        --> The text encoding hint used for the rename.
+                                                       You can pass kTextEncodingUnknown to use the
+                                                       "default" textEncodingHint.
+       newRef                          <** An optional pointer to a FSRef.
+                                                       If not NULL, the FSRef of the duplicated file
+                                                       will be returned in the FSRef.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSMoveRename
+
+OSErr
+FSMoveRename(
+       const FSRef *srcFileRef,
+       const FSRef *dstDirectoryRef,
+       UniCharCount nameLength,
+       const UniChar *moveName,        /* can be NULL (no rename during move) */
+       TextEncoding textEncodingHint,
+       FSRef *newRef);                         /* can be NULL */
+
+/*
+       The FSMoveRename function moves a file or directory (object), and
+       optionally renames it. The source and destination locations must be on
+       the same shared volume.
+       
+       srcFileRef                      --> An FSRef specifying the source file.
+       dstDirectoryRef         --> An FSRef specifying the destination directory.
+       nameLength                      --> Number of UniChar in moveName parameter (ignored
+                                                       if copyName is NULL)
+       moveName                        --> Points to the new object name if the object is to be
+                                                       renamed, or NULL if the object isn't to be renamed.
+       textEncodingHint        --> The text encoding hint used for the rename.
+                                                       You can pass kTextEncodingUnknown to use the
+                                                       "default" textEncodingHint.
+       newRef                          <** An optional pointer to a FSRef.
+                                                       If not NULL, the FSRef of the moved object
+                                                       will be returned in the FSRef.
+*/
+
+/*****************************************************************************/
+
+#pragma mark ----- File ID Routines -----
+
+/*****************************************************************************/
+
+#pragma mark FSResolveFileIDRef
+
+OSErr
+FSResolveFileIDRef(
+       FSVolumeRefNum volRefNum,
+       SInt32 fileID,
+       FSRef *ref);
+
+/*
+       The FSResolveFileIDRef function returns an FSRef for the file with the
+       specified file ID reference.
+
+       volRefNum                       --> Volume specification.
+       fileID                          --> The file ID reference.
+       ref                                     <-- The FSRef for the file ID reference.
+
+       __________
+
+       Also see:       FSCreateFileIDRef, FSDeleteFileIDRef
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSCreateFileIDRef
+
+OSErr
+FSCreateFileIDRef(
+       const FSRef *ref,
+       SInt32 *fileID);
+
+/*
+       The FSCreateFileIDRef function creates a file ID reference for the
+       specified file, or if a file ID reference already exists, supplies
+       the file ID reference and returns the result code fidExists or afpIDExists.
+
+       ref                                     --> The FSRef for the file.
+       fileID                          <-- The file ID reference (if result is noErr,
+                                                       fidExists, or afpIDExists).
+
+       __________
+
+       Also see:       GetFSRefFromFileIDRef, FSDeleteFileIDRef
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSDeleteFileIDRef
+
+/*
+       Why is there no FSDeleteFileIDRef routine? There are two reasons:
+       
+       1.      Since Mac OS 8.1, PBDeleteFileIDRef hasn't deleted file ID references.
+               On HFS volumes, deleting a file ID reference breaks aliases (which
+               use file ID references to track files as they are moved around on a
+               volume) and file ID references are automatically deleted when the file
+               they refer to is deleted. On HFS Plus volumes, file ID references are
+               always created when a file is created, deleted when the file is deleted,
+               and cannot be deleted at any other time.
+               
+       2.      PBDeleteFileIDRef causes a memory access fault under Mac OS X 10.0
+               through 10.1.x. While this will be fixed in a future release, the
+               implementation, like the Mac OS 8/9 implementation, does not delete
+               file ID references.
+               
+       __________
+
+       Also see:       GetFSRefFromFileIDRef, FSCreateFileIDRef
+*/
+
+/*****************************************************************************/
+
+#pragma mark ----- Utility Routines -----
+
+/*****************************************************************************/
+
+#pragma mark GetTempBuffer
+
+Ptr
+GetTempBuffer(
+       ByteCount buffReqSize,
+       ByteCount *buffActSize);
+
+/*
+       The GetTempBuffer function allocates a temporary buffer for file system
+       operations which is at least 4K bytes and a multiple of 4K bytes.
+       
+       buffReqSize                     --> Size you'd like the buffer to be.
+       buffActSize                     <-- The size of the buffer allocated.
+       function result         <-- Pointer to memory allocated, or NULL if no memory
+                                                       was available. The caller is responsible for
+                                                       disposing of this buffer with DisposePtr.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FileRefNumGetFSRef
+
+OSErr
+FileRefNumGetFSRef(
+       short refNum,
+       FSRef *ref);
+
+/*
+       The FileRefNumGetFSRef function gets the FSRef of an open file.
+
+       refNum                          --> The file reference number of an open file.
+       ref                                     <-- The FSRef to the open file.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSSetDefault
+
+OSErr
+FSSetDefault(
+       const FSRef *newDefault,
+       FSRef *oldDefault);
+
+/*
+       The FSSetDefault function sets the current working directory to the
+       directory specified by newDefault. The previous current working directory
+       is returned in oldDefault and must be used to restore the current working
+       directory to its previous state with the FSRestoreDefault function.
+       These two functions are designed to be used as a wrapper around
+       Standard I/O routines where the location of the file is implied to be the
+       current working directory. This is how you should use these functions:
+       
+               result = FSSetDefault(&newDefault, &oldDefault);
+               if ( noErr == result )
+               {
+                       // call the Stdio functions like remove, rename,
+                       // fopen, freopen, etc here!
+
+                       result = FSRestoreDefault(&oldDefault);
+               }
+       
+       newDefault                      --> An FSRef that specifies the new current working
+                                                       directory.
+       oldDefault                      <-- The previous current working directory's FSRef.
+       
+       __________
+       
+       Also see:       FSRestoreDefault
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSRestoreDefault
+
+OSErr
+FSRestoreDefault(
+       const FSRef *oldDefault);
+
+/*
+       The FSRestoreDefault function restores the current working directory
+       to the directory specified by oldDefault. The oldDefault parameter was
+       previously obtained from the FSSetDefault function.
+       These two functions are designed to be used as a wrapper around
+       Standard I/O routines where the location of the file is implied to be the
+       current working directory. This is how you should use these functions:
+       
+               result = FSSetDefault(&newDefault, &oldDefault);
+               if ( noErr == result )
+               {
+                       // call the Stdio functions like remove, rename,
+                       // fopen, freopen, etc here!
+
+                       result = FSRestoreDefault(&oldDefault);
+               }
+               
+       oldDefault                      --> The FSRef of the location to restore.
+       
+       __________
+       
+       Also see:       FSSetDefault
+*/
+
+/*****************************************************************************/
+
+#if PRAGMA_STRUCT_ALIGN
+       #pragma options align=reset
+#elif PRAGMA_STRUCT_PACKPUSH
+       #pragma pack(pop)
+#elif PRAGMA_STRUCT_PACK
+       #pragma pack()
+#endif
+
+#ifdef PRAGMA_IMPORT_OFF
+#pragma import off
+#elif PRAGMA_IMPORT
+#pragma import reset
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MOREFILESX__ */
+
diff --git a/Source/Objects.cpp b/Source/Objects.cpp
new file mode 100644 (file)
index 0000000..67feaac
--- /dev/null
@@ -0,0 +1,777 @@
+#include "Objects.h"
+extern XYZ viewer;
+extern float viewdistance;
+extern float lightambient[3],lightbrightness[3];
+extern float fadestart;
+extern int environment;
+extern float texscale;
+extern Light light;
+extern float multiplier;
+extern float gravity;
+extern FRUSTUM frustum;
+extern Terrain terrain;
+extern float terraindetail;
+extern bool foliage;
+extern int detail;
+extern float blurness;
+extern float windvar;
+extern float playerdist;
+extern bool skyboxtexture;
+extern Sprites sprites;
+
+//Functions
+
+bool   Objects::checkcollide(XYZ startpoint,XYZ endpoint,int which){
+       static XYZ colpoint,colviewer,coltarget;
+       static int i;
+
+       startpoint.y+=.1;
+       endpoint.y+=.1;
+       startpoint.y-=.1;
+       endpoint.y-=.1;
+
+       for(i=0;i<numobjects;i++){
+               if(type[i]!=treeleavestype&&type[i]!=treetrunktype&&type[i]!=bushtype&&type[i]!=firetype&&i!=which){
+                       colviewer=startpoint;
+                       coltarget=endpoint;
+                       if(model[i].LineCheck(&colviewer,&coltarget,&colpoint,&position[i],&rotation[i])!=-1)return 1;  
+               }
+       }
+
+       return 0;
+}
+
+void Objects::SphereCheckPossible(XYZ *p1,float radius)
+{
+       static int i,j;
+       static int whichpatchx;
+       static int whichpatchz;
+
+       whichpatchx=p1->x/(terrain.size/subdivision*terrain.scale*terraindetail);
+       whichpatchz=p1->z/(terrain.size/subdivision*terrain.scale*terraindetail);
+
+       if(whichpatchx>=0&&whichpatchz>=0&&whichpatchx<subdivision&&whichpatchz<subdivision)
+               if(terrain.patchobjectnum[whichpatchx][whichpatchz]>0&&terrain.patchobjectnum[whichpatchx][whichpatchz]<500)
+                       for(j=0;j<terrain.patchobjectnum[whichpatchx][whichpatchz];j++){
+                               i=terrain.patchobjects[whichpatchx][whichpatchz][j];
+                               possible[i]=0;
+                               if(model[i].SphereCheckPossible(p1, radius, &position[i], &rotation[i])!=-1){
+                                       possible[i]=1;
+                               }
+                       }
+}
+
+void Objects::Draw()
+{
+       static float distance;
+       static int i,j;
+       static XYZ moved,terrainlight;
+       bool hidden;
+
+       for(i=0;i<numobjects;i++){
+               if(type[i]!=firetype){
+                       moved=DoRotation(model[i].boundingspherecenter,0,rotation[i],0);
+                       if(type[i]==tunneltype||frustum.SphereInFrustum(position[i].x+moved.x,position[i].y+moved.y,position[i].z+moved.z,model[i].boundingsphereradius)){   
+                               distance=findDistancefast(&viewer,&position[i]);
+                               distance*=1.2;
+                               hidden=!(findDistancefastflat(&viewer,&position[i])>playerdist+3||(type[i]!=bushtype&&type[i]!=treeleavestype));
+                               if(!hidden){
+
+                                       if(detail==2&&distance>viewdistance*viewdistance/4&&environment==desertenvironment)glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, blurness );
+                                       else glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
+                                       distance=(viewdistance*viewdistance-(distance-(viewdistance*viewdistance*fadestart))*(1/(1-fadestart)))/viewdistance/viewdistance;
+                                       if(distance>1)distance=1;
+                                       if(distance>0){
+
+                                               /*if(checkcollide(viewer,DoRotation(model[i].vertex[model[i].vertexNum],0,rotation[i],0)*scale[i]+position[i],i)){
+                                               occluded[i]+=1;
+                                               }
+                                               else occluded[i]=0;*/
+                                               if(occluded[i]<6){
+                                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                       glPushMatrix();
+                                                               if(!model[i].color)glEnable(GL_LIGHTING);
+                                                               else glDisable(GL_LIGHTING);
+                                                               glDepthMask(1);
+                                                               glTranslatef(position[i].x,position[i].y,position[i].z);
+                                                               if(type[i]==bushtype){
+                                                                       messedwith[i]-=multiplier;
+                                                                       if(rotxvel[i]||rotx[i]){
+                                                                               if(rotx[i]>0)rotxvel[i]-=multiplier*8*abs(rotx[i]);
+                                                                               if(rotx[i]<0)rotxvel[i]+=multiplier*8*abs(rotx[i]);
+                                                                               if(rotx[i]>0)rotxvel[i]-=multiplier*4;
+                                                                               if(rotx[i]<0)rotxvel[i]+=multiplier*4;
+                                                                               if(rotxvel[i]>0)rotxvel[i]-=multiplier*4;
+                                                                               if(rotxvel[i]<0)rotxvel[i]+=multiplier*4;
+                                                                               if(abs(rotx[i])<multiplier*4)rotx[i]=0;
+                                                                               if(abs(rotxvel[i])<multiplier*4)rotxvel[i]=0;
+
+                                                                               rotx[i]+=rotxvel[i]*multiplier*4;
+                                                                       }
+                                                                       if(rotyvel[i]||roty[i]){
+                                                                               if(roty[i]>0)rotyvel[i]-=multiplier*8*abs(roty[i]);
+                                                                               if(roty[i]<0)rotyvel[i]+=multiplier*8*abs(roty[i]);
+                                                                               if(roty[i]>0)rotyvel[i]-=multiplier*4;
+                                                                               if(roty[i]<0)rotyvel[i]+=multiplier*4;
+                                                                               if(rotyvel[i]>0)rotyvel[i]-=multiplier*4;
+                                                                               if(rotyvel[i]<0)rotyvel[i]+=multiplier*4;
+                                                                               if(abs(roty[i])<multiplier*4)roty[i]=0;
+                                                                               if(abs(rotyvel[i])<multiplier*4)rotyvel[i]=0;
+
+                                                                               roty[i]+=rotyvel[i]*multiplier*4;
+                                                                       }
+                                                                       if(roty[i]){
+                                                                               glRotatef(roty[i],1,0,0);
+                                                                       }
+                                                                       if(rotx[i]){
+                                                                               glRotatef(-rotx[i],0,0,1);
+                                                                       }
+                                                                       if(rotx[i]>10)rotx[i]=10;
+                                                                       if(rotx[i]<-10)rotx[i]=-10;
+                                                                       if(roty[i]>10)roty[i]=10;
+                                                                       if(roty[i]<-10)roty[i]=-10;
+                                                               }
+                                                               if(type[i]==treetrunktype||type[i]==treeleavestype){
+                                                                       if(type[i]==treetrunktype||environment==2){
+                                                                               messedwith[i]-=multiplier;
+                                                                               if(rotxvel[i]||rotx[i]){
+                                                                                       if(rotx[i]>0)rotxvel[i]-=multiplier*8*abs(rotx[i]);
+                                                                                       if(rotx[i]<0)rotxvel[i]+=multiplier*8*abs(rotx[i]);
+                                                                                       if(rotx[i]>0)rotxvel[i]-=multiplier*4;
+                                                                                       if(rotx[i]<0)rotxvel[i]+=multiplier*4;
+                                                                                       if(rotxvel[i]>0)rotxvel[i]-=multiplier*4;
+                                                                                       if(rotxvel[i]<0)rotxvel[i]+=multiplier*4;
+                                                                                       if(abs(rotx[i])<multiplier*4)rotx[i]=0;
+                                                                                       if(abs(rotxvel[i])<multiplier*4)rotxvel[i]=0;
+
+                                                                                       rotx[i]+=rotxvel[i]*multiplier*4;
+                                                                               }
+                                                                               if(rotyvel[i]||roty[i]){
+                                                                                       if(roty[i]>0)rotyvel[i]-=multiplier*8*abs(roty[i]);
+                                                                                       if(roty[i]<0)rotyvel[i]+=multiplier*8*abs(roty[i]);
+                                                                                       if(roty[i]>0)rotyvel[i]-=multiplier*4;
+                                                                                       if(roty[i]<0)rotyvel[i]+=multiplier*4;
+                                                                                       if(rotyvel[i]>0)rotyvel[i]-=multiplier*4;
+                                                                                       if(rotyvel[i]<0)rotyvel[i]+=multiplier*4;
+                                                                                       if(abs(roty[i])<multiplier*4)roty[i]=0;
+                                                                                       if(abs(rotyvel[i])<multiplier*4)rotyvel[i]=0;
+
+                                                                                       roty[i]+=rotyvel[i]*multiplier*4;
+                                                                               }
+                                                                               if(roty[i]){
+                                                                                       glRotatef(roty[i]/6,1,0,0);
+                                                                               }
+                                                                               if(rotx[i]){
+                                                                                       glRotatef(-rotx[i]/6,0,0,1);
+                                                                               }
+                                                                               if(rotx[i]>10)rotx[i]=10;
+                                                                               if(rotx[i]<-10)rotx[i]=-10;
+                                                                               if(roty[i]>10)roty[i]=10;
+                                                                               if(roty[i]<-10)roty[i]=-10;
+                                                                       }
+                                                                       else
+                                                                       {
+                                                                               messedwith[i]-=multiplier;
+                                                                               if(rotxvel[i]||rotx[i]){
+                                                                                       if(rotx[i]>0)rotxvel[i]-=multiplier*8*abs(rotx[i]);
+                                                                                       if(rotx[i]<0)rotxvel[i]+=multiplier*8*abs(rotx[i]);
+                                                                                       if(rotx[i]>0)rotxvel[i]-=multiplier*4;
+                                                                                       if(rotx[i]<0)rotxvel[i]+=multiplier*4;
+                                                                                       if(rotxvel[i]>0)rotxvel[i]-=multiplier*4;
+                                                                                       if(rotxvel[i]<0)rotxvel[i]+=multiplier*4;
+                                                                                       if(abs(rotx[i])<multiplier*4)rotx[i]=0;
+                                                                                       if(abs(rotxvel[i])<multiplier*4)rotxvel[i]=0;
+
+                                                                                       rotx[i]+=rotxvel[i]*multiplier*4;
+                                                                               }
+                                                                               if(rotyvel[i]||roty[i]){
+                                                                                       if(roty[i]>0)rotyvel[i]-=multiplier*8*abs(roty[i]);
+                                                                                       if(roty[i]<0)rotyvel[i]+=multiplier*8*abs(roty[i]);
+                                                                                       if(roty[i]>0)rotyvel[i]-=multiplier*4;
+                                                                                       if(roty[i]<0)rotyvel[i]+=multiplier*4;
+                                                                                       if(rotyvel[i]>0)rotyvel[i]-=multiplier*4;
+                                                                                       if(rotyvel[i]<0)rotyvel[i]+=multiplier*4;
+                                                                                       if(abs(roty[i])<multiplier*4)roty[i]=0;
+                                                                                       if(abs(rotyvel[i])<multiplier*4)rotyvel[i]=0;
+
+                                                                                       roty[i]+=rotyvel[i]*multiplier*4;
+                                                                               }
+                                                                               if(roty[i]){
+                                                                                       glRotatef(roty[i]/4,1,0,0);
+                                                                               }
+                                                                               if(rotx[i]){
+                                                                                       glRotatef(-rotx[i]/4,0,0,1);
+                                                                               }
+                                                                               if(rotx[i]>10)rotx[i]=10;
+                                                                               if(rotx[i]<-10)rotx[i]=-10;
+                                                                               if(roty[i]>10)roty[i]=10;
+                                                                               if(roty[i]<-10)roty[i]=-10;
+                                                                       }
+
+                                                               }
+                                                               if(/*detail==2&&*/environment==snowyenvironment){
+                                                                       if(type[i]==treeleavestype){
+                                                                               glRotatef((sin(windvar+position[i].x*.3)+.5)*1.5*(sin(windvar*2+position[i].x*.3)+1)/2,1,0,0);
+                                                                       }
+                                                                       if(type[i]==treetrunktype){
+                                                                               glRotatef((sin(windvar+position[i].x*.3)+.5)*.5*(sin(windvar*2+position[i].x*.3)+1)/2,1,0,0);
+                                                                       }
+                                                                       if(type[i]==bushtype){
+                                                                               glRotatef((sin(windvar+position[i].x*.3)+.5)*4*(sin(windvar*2+position[i].x*.3)+1)/2,1,0,0);
+                                                                       }
+                                                               }
+                                                               if(/*detail==2&&*/environment==grassyenvironment){
+                                                                       if(type[i]==treeleavestype){
+                                                                               glRotatef((sin(windvar+position[i].x*.3)+.5)*1.5*.5*(sin(windvar*2+position[i].x*.3)+1)/2,1,0,0);
+                                                                       }
+                                                                       if(type[i]==treetrunktype){
+                                                                               glRotatef((sin(windvar+position[i].x*.3)+.5)*.5*.5*(sin(windvar*2+position[i].x*.3)+1)/2,1,0,0);
+                                                                       }
+                                                                       if(type[i]==bushtype){
+                                                                               glRotatef((sin(windvar+position[i].x*.3)+.5)*4*.5*(sin(windvar*2+position[i].x*.3)+1)/2,1,0,0);
+                                                                       }
+                                                               }
+                                                               if(/*detail==2&&*/environment==desertenvironment){
+                                                                       if(type[i]==bushtype){
+                                                                               glRotatef((sin(windvar+position[i].x*.3)+.5)*4*.5*(sin(windvar*2+position[i].x*.3)+1)/2,1,0,0);
+                                                                       }
+                                                               }
+                                                               glRotatef(rotation[i],0,1,0);
+                                                               if(distance>1)distance=1;
+                                                               glColor4f((1-shadowed[i])/2+.5,(1-shadowed[i])/2+.5,(1-shadowed[i])/2+.5,distance);
+                                                               if(distance>=1){
+                                                                       glDisable(GL_BLEND);
+                                                                       glAlphaFunc(GL_GREATER, 0.5);
+                                                               }
+                                                               if(distance<1){
+                                                                       glEnable(GL_BLEND);
+                                                                       glAlphaFunc(GL_GREATER, 0.1);
+                                                               }
+                                                               if(type[i]!=treetrunktype&&type[i]!=treeleavestype&&type[i]!=bushtype&&type[i]!=rocktype){
+                                                                       glEnable(GL_CULL_FACE);
+                                                                       glAlphaFunc(GL_GREATER, 0.0001);
+                                                                       model[i].drawdifftex(boxtextureptr);
+                                                                       model[i].drawdecals(terrain.shadowtexture,terrain.bloodtexture,terrain.bloodtexture2,terrain.breaktexture);
+                                                               }
+                                                               if(type[i]==rocktype){
+                                                                       glEnable(GL_CULL_FACE);
+                                                                       glAlphaFunc(GL_GREATER, 0.0001);
+                                                                       glColor4f((1-shadowed[i])/2+light.ambient[0],(1-shadowed[i])/2+light.ambient[1],(1-shadowed[i])/2+light.ambient[2],distance);
+                                                                       model[i].drawdifftex(rocktextureptr);
+                                                                       model[i].drawdecals(terrain.shadowtexture,terrain.bloodtexture,terrain.bloodtexture2,terrain.breaktexture);
+                                                               }
+                                                               if(type[i]==treeleavestype){
+                                                                       glDisable(GL_CULL_FACE);
+                                                                       glDisable(GL_LIGHTING);
+                                                                       terrainlight=terrain.getLighting(position[i].x,position[i].z);
+                                                                       if(!hidden){
+                                                                               glColor4f(terrainlight.x,terrainlight.y,terrainlight.z,distance);
+                                                                               if(distance<1)glAlphaFunc(GL_GREATER, 0.2);
+                                                                       }
+                                                                       if(hidden){
+                                                                               glDepthMask(0);
+                                                                               glEnable(GL_BLEND);
+                                                                               glColor4f(terrainlight.x,terrainlight.y,terrainlight.z,distance/3);
+                                                                               glAlphaFunc(GL_GREATER, 0);
+                                                                       }
+                                                                       model[i].drawdifftex(treetextureptr);
+                                                               }
+                                                               if(type[i]==bushtype){
+                                                                       glDisable(GL_CULL_FACE);
+                                                                       glDisable(GL_LIGHTING);
+                                                                       terrainlight=terrain.getLighting(position[i].x,position[i].z);
+                                                                       if(!hidden){
+                                                                               glColor4f(terrainlight.x,terrainlight.y,terrainlight.z,distance);
+                                                                               if(distance<1)glAlphaFunc(GL_GREATER, 0.2);
+                                                                       }
+                                                                       if(hidden){
+                                                                               glDepthMask(0);
+                                                                               glEnable(GL_BLEND);
+                                                                               glColor4f(terrainlight.x,terrainlight.y,terrainlight.z,distance/3);
+                                                                               glAlphaFunc(GL_GREATER, 0);
+                                                                       }
+                                                                       model[i].drawdifftex(bushtextureptr);
+                                                               }
+                                                               if(type[i]==treetrunktype){
+                                                                       glEnable(GL_CULL_FACE);
+                                                                       terrainlight=terrain.getLighting(position[i].x,position[i].z);
+                                                                       glColor4f(terrainlight.x,terrainlight.y,terrainlight.z,distance);
+                                                                       model[i].drawdifftex(treetextureptr);
+                                                               }
+                                                       glPopMatrix();
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
+       for(i=0;i<numobjects;i++){
+               if(type[i]==treeleavestype||type[i]==bushtype){
+                       moved=DoRotation(model[i].boundingspherecenter,0,rotation[i],0);
+                       if(frustum.SphereInFrustum(position[i].x+moved.x,position[i].y+moved.y,position[i].z+moved.z,model[i].boundingsphereradius)){   
+                               hidden=findDistancefastflat(&viewer,&position[i])<=playerdist+3;
+                               if(hidden){
+                                       distance=1;
+                                       if(distance>0){
+                                               if(1==1||occluded[i]<6){
+                                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                       glPushMatrix();
+                                                               glEnable(GL_LIGHTING);
+                                                               glDepthMask(1);
+                                                               glTranslatef(position[i].x,position[i].y,position[i].z);
+                                                               if(type[i]==bushtype){
+                                                                       messedwith[i]-=multiplier;
+                                                                       if(rotxvel[i]||rotx[i]){
+                                                                               if(rotx[i]>0)rotxvel[i]-=multiplier*8*abs(rotx[i]);
+                                                                               if(rotx[i]<0)rotxvel[i]+=multiplier*8*abs(rotx[i]);
+                                                                               if(rotx[i]>0)rotxvel[i]-=multiplier*4;
+                                                                               if(rotx[i]<0)rotxvel[i]+=multiplier*4;
+                                                                               if(rotxvel[i]>0)rotxvel[i]-=multiplier*4;
+                                                                               if(rotxvel[i]<0)rotxvel[i]+=multiplier*4;
+                                                                               if(abs(rotx[i])<multiplier*4)rotx[i]=0;
+                                                                               if(abs(rotxvel[i])<multiplier*4)rotxvel[i]=0;
+
+                                                                               rotx[i]+=rotxvel[i]*multiplier*4;
+                                                                       }
+                                                                       if(rotyvel[i]||roty[i]){
+                                                                               if(roty[i]>0)rotyvel[i]-=multiplier*8*abs(roty[i]);
+                                                                               if(roty[i]<0)rotyvel[i]+=multiplier*8*abs(roty[i]);
+                                                                               if(roty[i]>0)rotyvel[i]-=multiplier*4;
+                                                                               if(roty[i]<0)rotyvel[i]+=multiplier*4;
+                                                                               if(rotyvel[i]>0)rotyvel[i]-=multiplier*4;
+                                                                               if(rotyvel[i]<0)rotyvel[i]+=multiplier*4;
+                                                                               if(abs(roty[i])<multiplier*4)roty[i]=0;
+                                                                               if(abs(rotyvel[i])<multiplier*4)rotyvel[i]=0;
+
+                                                                               roty[i]+=rotyvel[i]*multiplier*4;
+                                                                       }
+                                                                       if(roty[i]){
+                                                                               glRotatef(roty[i],1,0,0);
+                                                                       }
+                                                                       if(rotx[i]){
+                                                                               glRotatef(-rotx[i],0,0,1);
+                                                                       }
+                                                                       if(rotx[i]>10)rotx[i]=10;
+                                                                       if(rotx[i]<-10)rotx[i]=-10;
+                                                                       if(roty[i]>10)roty[i]=10;
+                                                                       if(roty[i]<-10)roty[i]=-10;
+                                                               }
+                                                               if(type[i]==treetrunktype||type[i]==treeleavestype){
+                                                                       messedwith[i]-=multiplier;
+                                                                       if(rotxvel[i]||rotx[i]){
+                                                                               if(rotx[i]>0)rotxvel[i]-=multiplier*8*abs(rotx[i]);
+                                                                               if(rotx[i]<0)rotxvel[i]+=multiplier*8*abs(rotx[i]);
+                                                                               if(rotx[i]>0)rotxvel[i]-=multiplier*4;
+                                                                               if(rotx[i]<0)rotxvel[i]+=multiplier*4;
+                                                                               if(rotxvel[i]>0)rotxvel[i]-=multiplier*4;
+                                                                               if(rotxvel[i]<0)rotxvel[i]+=multiplier*4;
+                                                                               if(abs(rotx[i])<multiplier*4)rotx[i]=0;
+                                                                               if(abs(rotxvel[i])<multiplier*4)rotxvel[i]=0;
+
+                                                                               rotx[i]+=rotxvel[i]*multiplier*4;
+                                                                       }
+                                                                       if(rotyvel[i]||roty[i]){
+                                                                               if(roty[i]>0)rotyvel[i]-=multiplier*8*abs(roty[i]);
+                                                                               if(roty[i]<0)rotyvel[i]+=multiplier*8*abs(roty[i]);
+                                                                               if(roty[i]>0)rotyvel[i]-=multiplier*4;
+                                                                               if(roty[i]<0)rotyvel[i]+=multiplier*4;
+                                                                               if(rotyvel[i]>0)rotyvel[i]-=multiplier*4;
+                                                                               if(rotyvel[i]<0)rotyvel[i]+=multiplier*4;
+                                                                               if(abs(roty[i])<multiplier*4)roty[i]=0;
+                                                                               if(abs(rotyvel[i])<multiplier*4)rotyvel[i]=0;
+
+                                                                               roty[i]+=rotyvel[i]*multiplier*4;
+                                                                       }
+                                                                       if(roty[i]){
+                                                                               glRotatef(roty[i]/2,1,0,0);
+                                                                       }
+                                                                       if(rotx[i]){
+                                                                               glRotatef(-rotx[i]/2,0,0,1);
+                                                                       }
+                                                                       if(rotx[i]>10)rotx[i]=10;
+                                                                       if(rotx[i]<-10)rotx[i]=-10;
+                                                                       if(roty[i]>10)roty[i]=10;
+                                                                       if(roty[i]<-10)roty[i]=-10;
+                                                               }
+                                                               if(environment==snowyenvironment){
+                                                                       if(type[i]==treeleavestype){
+                                                                               glRotatef((sin(windvar+position[i].x*.3)+.5)*1.5*(sin(windvar*2+position[i].x*.3)+1)/2,1,0,0);
+                                                                       }
+                                                                       if(type[i]==treetrunktype){
+                                                                               glRotatef((sin(windvar+position[i].x*.3)+.5)*.5*(sin(windvar*2+position[i].x*.3)+1)/2,1,0,0);
+                                                                       }
+                                                                       if(type[i]==bushtype){
+                                                                               glRotatef((sin(windvar+position[i].x*.3)+.5)*4*(sin(windvar*2+position[i].x*.3)+1)/2,1,0,0);
+                                                                       }
+                                                               }
+                                                               if(environment==grassyenvironment){
+                                                                       if(type[i]==treeleavestype){
+                                                                               glRotatef((sin(windvar+position[i].x*.3)+.5)*1.5*.5*(sin(windvar*2+position[i].x*.3)+1)/2,1,0,0);
+                                                                       }
+                                                                       if(type[i]==treetrunktype){
+                                                                               glRotatef((sin(windvar+position[i].x*.3)+.5)*.5*.5*(sin(windvar*2+position[i].x*.3)+1)/2,1,0,0);
+                                                                       }
+                                                                       if(type[i]==bushtype){
+                                                                               glRotatef((sin(windvar+position[i].x*.3)+.5)*4*.5*(sin(windvar*2+position[i].x*.3)+1)/2,1,0,0);
+                                                                       }
+                                                               }
+                                                               glRotatef(rotation[i],0,1,0);
+                                                               glColor4f(1,1,1,distance);
+                                                               if(type[i]==treeleavestype){
+                                                                       glDisable(GL_CULL_FACE);
+                                                                       glDisable(GL_LIGHTING);
+                                                                       terrainlight=terrain.getLighting(position[i].x,position[i].z);
+                                                                       glDepthMask(0);
+                                                                       glEnable(GL_BLEND);
+                                                                       glColor4f(terrainlight.x,terrainlight.y,terrainlight.z,.3);
+                                                                       glAlphaFunc(GL_GREATER, 0);
+                                                                       glDisable(GL_ALPHA_TEST);
+                                                                       model[i].drawdifftex(treetextureptr);
+                                                               }
+                                                               if(type[i]==bushtype){
+                                                                       glDisable(GL_CULL_FACE);
+                                                                       glDisable(GL_LIGHTING);
+                                                                       terrainlight=terrain.getLighting(position[i].x,position[i].z);
+                                                                       glDepthMask(0);
+                                                                       glEnable(GL_BLEND);
+                                                                       glColor4f(terrainlight.x,terrainlight.y,terrainlight.z,.3);
+                                                                       glAlphaFunc(GL_GREATER, 0);
+                                                                       glDisable(GL_ALPHA_TEST);
+                                                                       model[i].drawdifftex(bushtextureptr);
+                                                               }
+                                                       glPopMatrix();
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       if(environment==desertenvironment)glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
+       glEnable(GL_ALPHA_TEST);                                                
+       SetUpLight(&light,0);
+}
+
+void Objects::DeleteObject(int which)
+{
+       type[numobjects-1]=0;
+       rotation[numobjects-1]=0;
+       position[numobjects-1]=0;
+       scale[numobjects-1]=0;
+       friction[numobjects-1]=0;
+
+       numobjects--;
+}
+
+void Objects::MakeObject(int atype, XYZ where, float arotation, float ascale){
+       if((atype!=treeleavestype&&atype!=bushtype)||foliage==1){
+               scale[numobjects]=ascale;
+               if(atype==treeleavestype)scale[numobjects]+=abs((float)(Random()%100)/900)*ascale;
+
+               onfire[numobjects]=0;
+               flamedelay[numobjects]=0;
+               type[numobjects]=atype;
+
+               if(atype==firetype)onfire[numobjects]=1;
+
+               position[numobjects]=where;
+               if(atype==bushtype)position[numobjects].y=terrain.getHeight(position[numobjects].x,position[numobjects].z)-.3;
+               rotation[numobjects]=arotation;
+
+               rotxvel[numobjects]=0;
+               rotyvel[numobjects]=0;
+               rotx[numobjects]=0;
+               roty[numobjects]=0;
+
+               if(atype==boxtype)model[numobjects].loaddecal((char *)":Data:Models:Box.solid",0);
+               if(atype==cooltype)model[numobjects].loaddecal((char *)":Data:Models:Cool.solid",0);
+               if(atype==walltype)model[numobjects].loaddecal((char *)":Data:Models:Wall.solid",0);
+               if(atype==tunneltype)model[numobjects].loaddecal((char *)":Data:Models:Tunnel.solid",0);
+               if(atype==chimneytype)model[numobjects].loaddecal((char *)":Data:Models:Chimney.solid",0);
+               if(atype==spiketype)model[numobjects].load((char *)":Data:Models:Spike.solid",0);
+               if(atype==weirdtype)model[numobjects].loaddecal((char *)":Data:Models:Weird.solid",0);
+               if(atype==rocktype)model[numobjects].loaddecal((char *)":Data:Models:Rock.solid",0);
+               if(atype==treetrunktype)model[numobjects].load((char *)":Data:Models:Treetrunk.solid",0);
+               if(atype==treeleavestype)model[numobjects].load((char *)":Data:Models:Leaves.solid",0);
+               if(atype==bushtype)model[numobjects].load((char *)":Data:Models:Bush.solid",0);
+
+               if(atype==boxtype)friction[numobjects]=1.5;
+               if(atype==cooltype)friction[numobjects]=1.5;
+               if(atype==walltype)friction[numobjects]=1.5;
+               if(atype==platformtype)friction[numobjects]=1.5;
+               if(atype==tunneltype)friction[numobjects]=1.5;
+               if(atype==chimneytype)friction[numobjects]=1.5;
+               if(atype==rocktype)friction[numobjects]=.5;
+               if(atype==rocktype&&ascale>.5)friction[numobjects]=1.5;
+               if(atype==weirdtype)friction[numobjects]=1.5;
+               if(atype==spiketype)friction[numobjects]=.4;
+               if(atype==treetrunktype)friction[numobjects]=.4;
+               if(atype==treeleavestype)friction[numobjects]=0;
+
+               if(atype==platformtype){
+                       model[numobjects].loaddecal((char *)":Data:Models:Platform.solid",0);
+                       model[numobjects].Rotate(90,0,0);
+               }
+
+               if(type[numobjects]==boxtype||type[numobjects]==cooltype||type[numobjects]==spiketype||type[numobjects]==weirdtype||type[numobjects]==walltype||type[numobjects]==chimneytype||type[numobjects]==tunneltype||type[numobjects]==platformtype){
+                       model[numobjects].ScaleTexCoords(scale[numobjects]*1.5);
+               }
+               if(type[numobjects]==rocktype){
+                       model[numobjects].ScaleTexCoords(scale[numobjects]*3);
+               }
+               model[numobjects].flat=1;
+               if(atype==treetrunktype||atype==treeleavestype||atype==rocktype){
+                       model[numobjects].flat=0;
+               }
+               model[numobjects].Scale(.3*scale[numobjects],.3*scale[numobjects],.3*scale[numobjects]);
+               model[numobjects].Rotate(90,1,1);
+               if(type[numobjects]==rocktype){
+                       model[numobjects].Rotate(arotation*5,1,1);
+               }
+               model[numobjects].CalculateNormals(1);
+               model[numobjects].ScaleNormals(-1,-1,-1);
+
+               if(atype==treetrunktype&&position[numobjects].y<terrain.getHeight(position[numobjects].x,position[numobjects].z)+1){
+                       if(detail==2)terrain.MakeDecal(shadowdecalpermanent,position[numobjects],2,.4,0);
+               }       
+
+               if(atype==bushtype&&position[numobjects].y<terrain.getHeight(position[numobjects].x,position[numobjects].z)+1){
+                       if(detail==2)terrain.MakeDecal(shadowdecalpermanent,position[numobjects],1,.4,0);
+               }
+
+               if(atype!=treeleavestype&&atype!=bushtype&&atype!=firetype)
+                       terrain.AddObject(where+DoRotation(model[numobjects].boundingspherecenter,0,arotation,0),model[numobjects].boundingsphereradius,numobjects);
+
+               numobjects++;
+       }       
+}
+
+void Objects::MakeObject(int atype, XYZ where, float arotation, float arotation2, float ascale){
+       if((atype!=treeleavestype&&atype!=bushtype)||foliage==1){
+               scale[numobjects]=ascale;
+               if(atype==treeleavestype)scale[numobjects]+=abs((float)(Random()%100)/900)*ascale;
+
+               onfire[numobjects]=0;
+               flamedelay[numobjects]=0;
+               type[numobjects]=atype;
+
+               if(atype==firetype)onfire[numobjects]=1;
+
+               position[numobjects]=where;
+               if(atype==bushtype)position[numobjects].y=terrain.getHeight(position[numobjects].x,position[numobjects].z)-.3;
+               /*if(atype==firetype){
+               if(position[numobjects].y<terrain.getHeight(position[numobjects].x,position[numobjects].z)-.3)
+               position[numobjects].y=terrain.getHeight(position[numobjects].x,position[numobjects].z)-.3;
+               }*/
+               rotation[numobjects]=arotation;
+               rotation2[numobjects]=arotation2;
+
+               rotxvel[numobjects]=0;
+               rotyvel[numobjects]=0;
+               rotx[numobjects]=0;
+               roty[numobjects]=0;
+
+               if(atype==boxtype)model[numobjects].loaddecal((char *)":Data:Models:Box.solid",0);
+               if(atype==cooltype)model[numobjects].loaddecal((char *)":Data:Models:Cool.solid",0);
+               if(atype==walltype)model[numobjects].loaddecal((char *)":Data:Models:Wall.solid",0);
+               if(atype==tunneltype)model[numobjects].loaddecal((char *)":Data:Models:Tunnel.solid",0);
+               if(atype==chimneytype)model[numobjects].loaddecal((char *)":Data:Models:Chimney.solid",0);
+               if(atype==spiketype)model[numobjects].load((char *)":Data:Models:Spike.solid",0);
+               if(atype==weirdtype)model[numobjects].loaddecal((char *)":Data:Models:Weird.solid",0);
+               if(atype==rocktype)model[numobjects].loaddecal((char *)":Data:Models:Rock.solid",0);
+               if(atype==treetrunktype)model[numobjects].load((char *)":Data:Models:Treetrunk.solid",0);
+               if(atype==treeleavestype)model[numobjects].load((char *)":Data:Models:Leaves.solid",0);
+               if(atype==bushtype)model[numobjects].load((char *)":Data:Models:Bush.solid",0);
+
+               if(atype==boxtype)friction[numobjects]=1.5;
+               if(atype==cooltype)friction[numobjects]=1.5;
+               if(atype==walltype)friction[numobjects]=1.5;
+               if(atype==platformtype)friction[numobjects]=1.5;
+               if(atype==tunneltype)friction[numobjects]=1.5;
+               if(atype==chimneytype)friction[numobjects]=1.5;
+               if(atype==rocktype)friction[numobjects]=.5;
+               if(atype==rocktype&&ascale>.5)friction[numobjects]=1.5;
+               if(atype==weirdtype)friction[numobjects]=1.5;
+               if(atype==spiketype)friction[numobjects]=.4;
+               if(atype==treetrunktype)friction[numobjects]=.4;
+               if(atype==treeleavestype)friction[numobjects]=0;
+
+               if(friction[numobjects]==1.5&&abs(arotation2)>5)friction[numobjects]=.5;
+
+               if(atype==platformtype){
+                       model[numobjects].loaddecal((char *)":Data:Models:Platform.solid",0);
+                       model[numobjects].Rotate(90,0,0);
+               }
+
+               if(type[numobjects]==boxtype||type[numobjects]==cooltype||type[numobjects]==spiketype||type[numobjects]==weirdtype||type[numobjects]==walltype||type[numobjects]==chimneytype||type[numobjects]==tunneltype||type[numobjects]==platformtype){
+                       model[numobjects].ScaleTexCoords(scale[numobjects]*1.5);
+               }
+               if(type[numobjects]==rocktype){
+                       model[numobjects].ScaleTexCoords(scale[numobjects]*3);
+               }
+               model[numobjects].flat=1;
+               if(atype==treetrunktype||atype==treeleavestype||atype==rocktype){
+                       model[numobjects].flat=0;
+               }
+               model[numobjects].Scale(.3*scale[numobjects],.3*scale[numobjects],.3*scale[numobjects]);
+               model[numobjects].Rotate(90,1,1);
+               model[numobjects].Rotate(arotation2,0,0);
+               if(type[numobjects]==rocktype){
+                       model[numobjects].Rotate(arotation*5,0,0);
+               }
+               model[numobjects].CalculateNormals(1);
+               model[numobjects].ScaleNormals(-1,-1,-1);
+
+               if(atype==treetrunktype&&position[numobjects].y<terrain.getHeight(position[numobjects].x,position[numobjects].z)+1){
+                       if(detail==2)terrain.MakeDecal(shadowdecalpermanent,position[numobjects],2,.4,0);
+               }       
+
+               if(atype==bushtype&&position[numobjects].y<terrain.getHeight(position[numobjects].x,position[numobjects].z)+1){
+                       if(detail==2)terrain.MakeDecal(shadowdecalpermanent,position[numobjects],1,.4,0);
+               }
+
+               if(atype!=treeleavestype&&atype!=bushtype&&atype!=firetype)
+                       terrain.AddObject(where+DoRotation(model[numobjects].boundingspherecenter,0,arotation,0),model[numobjects].boundingsphereradius,numobjects);
+
+               numobjects++;
+       }       
+}
+
+void Objects::DoStuff()
+{
+       XYZ spawnpoint;
+       for(int i=0;i<numobjects;i++){
+               /*if(type[i]==firetype){
+               sprites.MakeSprite(weaponshinesprite, position[i],position[i]*0, 1,1,1, 5, 1);
+               }*/
+
+               if(type[i]==firetype)onfire[i]=1;
+               if(onfire[i]){
+                       if(type[i]==bushtype)flamedelay[i]-=multiplier*3;
+                       if(type[i]==firetype)flamedelay[i]-=multiplier*3;
+                       if(type[i]==treeleavestype)flamedelay[i]-=multiplier*4;
+                       while(flamedelay[i]<0&&onfire[i]){
+                               flamedelay[i]+=.006;
+                               if(type[i]==bushtype||type[i]==firetype){
+                                       spawnpoint.x=((float)(Random()%100))/30*scale[i];
+                                       spawnpoint.y=((float)(Random()%100)+60)/30*scale[i];
+                                       spawnpoint.z=0;
+                                       spawnpoint=DoRotation(spawnpoint,0,Random()%360,0);
+                                       spawnpoint+=position[i];
+                                       sprites.MakeSprite(flamesprite, spawnpoint,spawnpoint*0, 1,1,1, (.6+(float)abs(Random()%100)/200-.25)*5*scale[i], 1);
+                               }
+                               if(type[i]==treeleavestype){
+                                       spawnpoint.x=((float)(Random()%100))/80*scale[i];
+                                       spawnpoint.y=((float)(Random()%100)+80)/12*scale[i];
+                                       spawnpoint.z=0;
+                                       spawnpoint=DoRotation(spawnpoint,0,Random()%360,0);
+                                       spawnpoint+=position[i];
+                                       sprites.MakeSprite(flamesprite, spawnpoint,spawnpoint*0, 1,1,1, (.6+(float)abs(Random()%100)/200-.25)*6, 1);
+                               }
+                       }
+
+               }
+       }
+}
+
+void Objects::DoShadows()
+{
+       int i,j,k,l,todivide;
+       static float brightness, total;
+       static XYZ testpoint,testpoint2, terrainpoint,lightloc,col;
+       lightloc=light.location;
+       if(!skyboxtexture)lightloc=0;
+       lightloc.y+=10;
+       Normalise(&lightloc);
+       int patchx,patchz;
+
+       if(numobjects>0)
+               for(i=0;i<numobjects;i++){
+                       if(type[i]!=treeleavestype&&type[i]!=treetrunktype&&type[i]!=bushtype&&type[i]!=firetype){
+                               for(j=0;j<model[i].vertexNum;j++){
+                                       terrainpoint=position[i]+DoRotation(model[i].vertex[j]+model[i].normals[j]*.1,0,rotation[i],0);
+                                       //terrainpoint.y+=model[i].boundingsphereradius;
+                                       shadowed[i]=0;
+                                       patchx=terrainpoint.x/(terrain.size/subdivision*terrain.scale*terraindetail);
+                                       patchz=terrainpoint.z/(terrain.size/subdivision*terrain.scale*terraindetail);
+                                       if(patchx>=0&&patchz>=0&&patchx<subdivision&&patchz<subdivision)
+                                               if(terrain.patchobjectnum[patchx][patchz])
+                                                       for(k=0;k<terrain.patchobjectnum[patchx][patchz];k++){
+                                                               l=terrain.patchobjects[patchx][patchz][k];
+                                                               if(type[l]!=treetrunktype/*&&l!=i*/){
+                                                                       testpoint=terrainpoint;
+                                                                       testpoint2=terrainpoint+lightloc*50*(1-shadowed[i]);
+                                                                       if(model[l].LineCheck(&testpoint,&testpoint2,&col,&position[l],&rotation[l])!=-1){
+                                                                               shadowed[i]=1-(findDistance(&terrainpoint,&col)/50);    
+                                                                       }
+                                                               }
+                                                       }
+                                                       if(shadowed[i]>0){
+                                                               col=model[i].normals[j]-DoRotation(lightloc*shadowed[i],0,-rotation[i],0);
+                                                               Normalise(&col);
+                                                               for(k=0;k<model[i].TriangleNum;k++){
+                                                                       if(model[i].Triangles[k].vertex[0]==j){
+                                                                               l=k*24;
+                                                                               model[i].vArray[l+2]=col.x;
+                                                                               model[i].vArray[l+3]=col.y;
+                                                                               model[i].vArray[l+4]=col.z;
+                                                                       }
+                                                                       if(model[i].Triangles[k].vertex[1]==j){
+                                                                               l=k*24;
+                                                                               model[i].vArray[l+10]=col.x;
+                                                                               model[i].vArray[l+11]=col.y;
+                                                                               model[i].vArray[l+12]=col.z;
+                                                                       }
+                                                                       if(model[i].Triangles[k].vertex[2]==j){
+                                                                               l=k*24;
+                                                                               model[i].vArray[l+18]=col.x;
+                                                                               model[i].vArray[l+19]=col.y;
+                                                                               model[i].vArray[l+20]=col.z;
+                                                                       }
+                                                               }
+                                                       }
+                               }
+                       }
+                       shadowed[i]=0;
+               }
+}
+
+Objects::Objects()
+{
+       center = 0;
+       radius = 0;
+       numobjects = 0;
+       boxtextureptr = 0;
+       treetextureptr = 0;
+       bushtextureptr = 0;
+       rocktextureptr = 0;
+
+       memset(position, 0, sizeof(position));
+       memset(type, 0, sizeof(type));
+       memset(rotation, 0, sizeof(rotation));
+       memset(rotation2, 0, sizeof(rotation2));
+       memset(rotx, 0, sizeof(rotx));
+       memset(rotxvel, 0, sizeof(rotxvel));
+       memset(roty, 0, sizeof(roty));
+       memset(rotyvel, 0, sizeof(rotyvel));
+       memset(possible, 0, sizeof(possible));
+       memset(model, 0, sizeof(model));
+       memset(displaymodel, 0, sizeof(displaymodel));
+       memset(friction, 0, sizeof(friction));
+       memset(scale, 0, sizeof(scale));
+       memset(messedwith, 0, sizeof(messedwith));
+       memset(checked, 0, sizeof(checked));
+       memset(shadowed, 0, sizeof(shadowed));
+       memset(occluded, 0, sizeof(occluded));
+       memset(onfire, 0, sizeof(onfire));
+       memset(flamedelay, 0, sizeof(flamedelay));
+}      
+
+Objects::~Objects()
+{
+       if (boxtextureptr) glDeleteTextures( 1, (const unsigned long *)&boxtextureptr );
+       if (treetextureptr) glDeleteTextures( 1, (const unsigned long *)&treetextureptr );
+       if (bushtextureptr) glDeleteTextures( 1, (const unsigned long *)&bushtextureptr );
+       if (rocktextureptr) glDeleteTextures( 1, (const unsigned long *)&rocktextureptr );
+};
diff --git a/Source/Objects.h b/Source/Objects.h
new file mode 100644 (file)
index 0000000..d81cda4
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef _OBJECTS_H_
+#define _OBJECTS_H_
+
+#include "Quaternions.h"
+#include "gl.h"
+#include "TGALoader.h"
+#include "Quaternions.h"
+#include "Frustum.h"
+#include "Lights.h"
+#include "Models.h"
+#include "Terrain.h"
+#include "Sprites.h"
+#include <vector>
+//
+// Model Structures
+//
+
+#define max_objects 300
+
+#define boxtype 0
+#define weirdtype 1
+#define spiketype 2
+#define treetrunktype 3
+#define treeleavestype 4
+#define bushtype 5
+#define rocktype 6
+#define walltype 7
+#define chimneytype 8
+#define platformtype 9
+#define tunneltype 11
+#define cooltype 12
+#define firetype 13
+
+
+class Objects{
+public:
+       XYZ center;
+       float radius;
+       XYZ position[max_objects];
+       int type[max_objects];
+       float rotation[max_objects];
+       float rotation2[max_objects];
+       float rotx[max_objects];
+       float rotxvel[max_objects];
+       float roty[max_objects];
+       float rotyvel[max_objects];
+       int numobjects;
+       bool possible[max_objects];
+       Model model[max_objects];
+       Model displaymodel[max_objects];
+       float friction[max_objects];
+       float scale[max_objects];
+       float messedwith[max_objects];
+       float checked[max_objects];
+       GLuint  boxtextureptr;
+       GLuint  treetextureptr;
+       GLuint  bushtextureptr;
+       GLuint  rocktextureptr;
+       float shadowed[max_objects];
+       float occluded[max_objects];
+       bool checkcollide(XYZ startpoint, XYZ endpoint,int which);
+       bool onfire[max_objects];
+       float flamedelay[max_objects];
+
+       void SphereCheckPossible(XYZ *p1,float radius);
+       void DeleteObject(int which);
+       void MakeObject(int atype, XYZ where, float arotation, float ascale);
+       void MakeObject(int atype, XYZ where, float arotation, float arotation2, float ascale);
+       void Draw();
+       void DoShadows();
+       void DoStuff();
+
+       Objects();
+       ~Objects();
+};
+
+#endif
diff --git a/Source/OpenGL_Full_Screen.cpp b/Source/OpenGL_Full_Screen.cpp
new file mode 100644 (file)
index 0000000..694ffd5
--- /dev/null
@@ -0,0 +1,1770 @@
+#include "Game.h"
+#include "nommgr.h"
+
+extern bool buttons[3];
+extern float multiplier;
+extern float screenwidth,screenheight;
+extern float sps;
+extern float realmultiplier;
+extern int slomo;
+extern bool ismotionblur;
+extern float usermousesensitivity;
+extern int detail;
+extern bool floatjump;
+extern bool cellophane;
+extern int terraindetail;
+extern int texdetail;
+extern int bloodtoggle;
+extern bool osx;
+extern bool autoslomo;
+extern bool foliage;
+extern bool musictoggle;
+extern bool trilinear;
+extern float gamespeed;
+extern int difficulty;
+extern bool damageeffects;
+extern int numplayers;
+extern bool decals;
+extern bool invertmouse;
+extern bool texttoggle;
+extern bool ambientsound;
+extern bool mousejump;
+extern bool freeze;
+extern Person player[maxplayers];
+extern bool vblsync;
+extern bool stillloading;
+extern bool showpoints;
+extern bool alwaysblur;
+extern bool immediate;
+extern bool velocityblur;
+extern bool debugmode;
+extern int mainmenu;
+extern int kBitsPerPixel;
+extern float slomospeed;
+extern float slomofreq;
+extern float oldgamespeed;
+
+ #define kUseAGLFullScreenX 1
+ #define kUseFades 1
+// system includes ----------------------------------------------------------
+
+#ifdef __APPLE_CC__
+    #include "Carbon Include.h"
+    #include <Carbon/Carbon.h>
+    
+    #include <DrawSprocket/DrawSprocket.h>
+       #include <AGL/agl.h>
+       #include <AGL/aglRenderers.h>
+       #include <OpenGL/gl.h>
+       #include <OpenGL/glu.h>
+#else
+    #include <DrawSprocket.h>
+    
+    #include <Devices.h>
+    #include <Dialogs.h>
+    #include <DriverServices.h>
+    #include <Events.h>
+    #include <Gestalt.h>
+    #include <LowMem.h>
+    #include <Sound.h>
+    #include <TextEdit.h>
+    #include <ToolUtils.h>
+    #include <Windows.h>
+
+    // profile
+    #include <Profiler.h>
+
+       #include "agl.h"
+    #include "gl.h"
+       #include "glu.h"
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <Folders.h>
+#include <fstream.h>
+// project includes ---------------------------------------------------------
+
+#include "aglString.h"
+#include "MacInput.h"
+
+// functions (internal/private) ---------------------------------------------
+
+static UInt32 CheckMacOSX (void);
+void CToPStr (StringPtr outString, const char *inString);
+void ReportError (char * strError);
+OSStatus DSpDebugStr (OSStatus error);
+GLenum aglDebugStr (void);
+GLenum glDebugStr (void);
+
+CGrafPtr SetupDSpFullScreen (GDHandle hGD);
+void ShutdownDSp (CGrafPtr pDSpPort);
+
+AGLContext SetupAGL (GDHandle hGD, AGLDrawable win);
+AGLContext SetupAGLFullScreen (GDHandle display, short * pDepth, short * pWidth, short * pHeight);
+void CleanupAGL (AGLContext ctx);
+void DrawGL (Rect * pRectPort);
+
+void InitToolbox(void);
+void CreateGLWindow (void);
+Boolean SetUp (void);
+void DoMenu (SInt32 menuResult);
+void DoKey (SInt8 theKey, SInt8 theCode);
+void DoUpdate (void);
+
+pascal void IdleTimer (EventLoopTimerRef inTimer, void* userData);
+EventLoopTimerUPP GetTimerUPP (void);
+static Boolean RunningOnCarbonX(void);
+
+void DoEvent (void);
+void CleanUp (void);
+
+// profile wrappers
+Boolean WaitNextEventWrapper (EventMask eventMask, EventRecord *theEvent, unsigned long sleep,RgnHandle mouseRgn);
+OSStatus DSpProcessEventWrapper (EventRecord *inEvent, Boolean *outEventWasProcessed);
+void UpdateWrapper (EventRecord *theEvent);
+
+// statics/globals (internal only) ------------------------------------------
+
+Point delta;
+
+// Menu defs
+enum 
+{
+       kMenuApple = 128,
+       kMenuFile = 129,
+       
+       kAppleAbout = 1,
+       kFileQuit = 1
+};
+
+enum 
+{
+       kForegroundSleep = 10,
+       kBackgroundSleep = 10000
+};
+EventLoopTimerRef gTimer = NULL;
+
+int kContextWidth;
+int kContextHeight;
+
+const RGBColor rgbBlack = { 0x0000, 0x0000, 0x0000 };
+
+NumVersion gVersionDSp;
+DSpContextAttributes gContextAttributes;
+DSpContextReference gContext = 0;
+extern AGLContext gaglContext;
+GLuint gFontList;
+char gcstrMode [256] = "";
+
+AGLDrawable gpDSpPort = NULL; // will be NULL for full screen under X
+Rect gRectPort = {0, 0, 0, 0};
+
+UInt32 gSleepTime = kForegroundSleep;
+Boolean gDone = false, gfFrontProcess = true;
+
+Game game;
+
+// profile
+#if __profile__
+OSErr gProfErr = noErr;
+#endif
+
+#pragma mark -
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+// are we running on Mac OS X
+// returns 0 if < Mac OS X or version number of Mac OS X (10.0 for GM)
+
+static UInt32 CheckMacOSX (void)
+{
+       UInt32 response;
+    
+       if ((Gestalt(gestaltSystemVersion, (SInt32 *) &response) == noErr) && (response >= 0x01000))
+               return response;
+       else
+               return 0;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+// Copy C string to Pascal string
+
+void CToPStr (StringPtr outString, const char *inString)
+{      
+       unsigned char x = 0;
+       do
+               *(((char*)outString) + x + 1) = *(inString + x++);
+       while ((*(inString + x) != 0)  && (x < 256));
+       *((char*)outString) = (char) x;                                                                 
+}
+
+// --------------------------------------------------------------------------
+
+void ReportError (char * strError)
+{
+       char errMsgCStr [256];
+       Str255 strErr;
+
+       sprintf (errMsgCStr, "%s", strError); 
+
+       // out as debug string
+       CToPStr (strErr, errMsgCStr);
+       DebugStr (strErr);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+OSStatus DSpDebugStr (OSStatus error)
+{
+       switch (error)
+       {
+               case noErr:
+                       break;
+               case kDSpNotInitializedErr:
+                       ReportError ("DSp Error: Not initialized");
+                       break;
+               case kDSpSystemSWTooOldErr:
+                       ReportError ("DSp Error: system Software too old");
+                       break;
+               case kDSpInvalidContextErr:
+                       ReportError ("DSp Error: Invalid context");
+                       break;
+               case kDSpInvalidAttributesErr:
+                       ReportError ("DSp Error: Invalid attributes");
+                       break;
+               case kDSpContextAlreadyReservedErr:
+                       ReportError ("DSp Error: Context already reserved");
+                       break;
+               case kDSpContextNotReservedErr:
+                       ReportError ("DSp Error: Context not reserved");
+                       break;
+               case kDSpContextNotFoundErr:
+                       ReportError ("DSp Error: Context not found");
+                       break;
+               case kDSpFrameRateNotReadyErr:
+                       ReportError ("DSp Error: Frame rate not ready");
+                       break;
+               case kDSpConfirmSwitchWarning:
+//                     ReportError ("DSp Warning: Must confirm switch"); // removed since it is just a warning, add back for debugging
+                       return 0; // don't want to fail on this warning
+                       break;
+               case kDSpInternalErr:
+                       ReportError ("DSp Error: Internal error");
+                       break;
+               case kDSpStereoContextErr:
+                       ReportError ("DSp Error: Stereo context");
+                       break;
+       }
+       return error;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+// if error dump agl errors to debugger string, return error
+
+GLenum aglDebugStr (void)
+{
+       GLenum err = aglGetError();
+       if (AGL_NO_ERROR != err)
+               ReportError ((char *)aglErrorString(err));
+       return err;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+// if error dump agl errors to debugger string, return error
+
+GLenum glDebugStr (void)
+{
+       GLenum err = glGetError();
+       if (GL_NO_ERROR != err)
+               ReportError ((char *)gluErrorString(err));
+       return err;
+}
+
+#pragma mark -
+//-----------------------------------------------------------------------------------------------------------------------
+
+// Set up DSp screen on graphics device requested
+// side effect: sets both gpDSpWindow and gpPort
+
+CGrafPtr SetupDSpFullScreen (GDHandle hGD)
+{
+       DSpContextAttributes foundAttributes;
+       DisplayIDType displayID = NULL;
+       
+       if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpGetVersion) 
+       {
+               ReportError ("DrawSprocket not installed.");
+               return NULL;
+       }
+       else
+               gVersionDSp = DSpGetVersion ();
+
+       if ((gVersionDSp.majorRev == 0x01) && (gVersionDSp.minorAndBugRev < 0x99))
+       {
+               // this version of DrawSprocket is not completely functional on Mac OS X
+               if (CheckMacOSX ())
+               {
+                       ReportError ("DrawSprocket 1.99 or greate required on Mac OS X, please update to at least Mac OS X 10.1.");
+                       return NULL;
+               }
+       }
+                       
+       // Note: DSp < 1.7.3 REQUIRES the back buffer attributes even if only one buffer is required
+       memset(&gContextAttributes, 0, sizeof (DSpContextAttributes));
+       gContextAttributes.displayWidth                 = kContextWidth;
+       gContextAttributes.displayHeight                = kContextHeight;
+       gContextAttributes.colorNeeds                   = kDSpColorNeeds_Require;
+       gContextAttributes.displayBestDepth             = kBitsPerPixel;
+       gContextAttributes.backBufferBestDepth  = kBitsPerPixel;
+       gContextAttributes.displayDepthMask             = kDSpDepthMask_All;
+       gContextAttributes.backBufferDepthMask  = kDSpDepthMask_All;
+       gContextAttributes.pageCount                    = 1;                                                            // only the front buffer is needed
+       
+       screenwidth=kContextWidth;
+       screenheight=kContextHeight;
+       
+       DMGetDisplayIDByGDevice (hGD, &displayID, true);
+       
+       if (noErr != DSpDebugStr (DSpFindBestContextOnDisplayID (&gContextAttributes, &gContext, displayID)))
+       {
+               ReportError ("DSpFindBestContext() had an error.");
+               return NULL;
+       }
+
+       if (noErr != DSpDebugStr (DSpContext_GetAttributes (gContext, &foundAttributes))) // see what we actually found
+       {
+               ReportError ("DSpContext_GetAttributes() had an error.");
+               return NULL;
+       }
+
+       // reset width and height to full screen and handle our own centering
+       // HWA will not correctly center less than full screen size contexts
+       gContextAttributes.displayWidth         = foundAttributes.displayWidth;
+       gContextAttributes.displayHeight        = foundAttributes.displayHeight;
+       gContextAttributes.pageCount            = 1;                                                                    // only the front buffer is needed
+       gContextAttributes.contextOptions       = 0 | kDSpContextOption_DontSyncVBL;    // no page flipping and no VBL sync needed
+
+       DSpSetBlankingColor(&rgbBlack);
+
+       if (noErr !=  DSpDebugStr (DSpContext_Reserve ( gContext, &gContextAttributes))) // reserve our context
+       {
+               ReportError ("DSpContext_Reserve() had an error.");
+               return NULL;
+       }
+       HideCursor ();
+
+       if (noErr != DSpDebugStr (DSpContext_SetState (gContext, kDSpContextState_Active))) // activate our context
+       {
+               ReportError ("DSpContext_SetState() had an error.");
+               return NULL;
+       }
+
+
+       if ((CheckMacOSX ()) && !((gVersionDSp.majorRev > 0x01) || ((gVersionDSp.majorRev == 0x01) && (gVersionDSp.minorAndBugRev >= 0x99))))// DSp should be supported in version after 1.98
+       {
+               ReportError ("Mac OS X with DSp < 1.99 does not support DrawSprocket for OpenGL full screen");
+               return NULL;
+       }
+       else if (CheckMacOSX ()) // DSp should be supported in versions 1.99 and later
+       {
+               CGrafPtr pPort;
+               // use DSp's front buffer on Mac OS X
+               if (noErr != DSpDebugStr (DSpContext_GetFrontBuffer (gContext, &pPort)))
+               {
+                       ReportError ("DSpContext_GetFrontBuffer() had an error.");
+                       return NULL;
+               }
+               // there is a problem in Mac OS X 10.0 GM CoreGraphics that may not size the port pixmap correctly
+               // this will check the vertical sizes and offset if required to fix the problem
+               // this will not center ports that are smaller then a particular resolution
+               {
+                       long deltaV, deltaH;
+                       Rect portBounds;
+                       PixMapHandle hPix = GetPortPixMap (pPort);
+                       Rect pixBounds = (**hPix).bounds;
+                       GetPortBounds (pPort, &portBounds);
+                       deltaV = (portBounds.bottom - portBounds.top) - (pixBounds.bottom - pixBounds.top) +
+                                (portBounds.bottom - portBounds.top - kContextHeight) / 2;
+                       deltaH = -(portBounds.right - portBounds.left - kContextWidth) / 2;
+                       if (deltaV || deltaH)
+                       {
+                               GrafPtr pPortSave;
+                               GetPort (&pPortSave);
+                               SetPort ((GrafPtr)pPort);
+                               // set origin to account for CG offset and if requested drawable smaller than screen rez
+                               SetOrigin (deltaH, deltaV);
+                               SetPort (pPortSave);
+                       }
+               }
+               return pPort;
+       }
+       else // Mac OS 9 or less
+       {
+               WindowPtr pWindow;
+               Rect rectWin;
+               RGBColor rgbSave;
+               GrafPtr pGrafSave;
+               // create a new window in our context 
+               // note: OpenGL is expecting a window so it can enumerate the devices it spans, 
+               // center window in our context's gdevice
+               rectWin.top  = (short) ((**hGD).gdRect.top + ((**hGD).gdRect.bottom - (**hGD).gdRect.top) / 2);         // h center
+               rectWin.top  -= (short) (kContextHeight / 2);
+               rectWin.left  = (short) ((**hGD).gdRect.left + ((**hGD).gdRect.right - (**hGD).gdRect.left) / 2);       // v center
+               rectWin.left  -= (short) (kContextWidth / 2);
+               rectWin.right = (short) (rectWin.left + kContextWidth);
+               rectWin.bottom = (short) (rectWin.top + kContextHeight);
+               
+               pWindow = NewCWindow (NULL, &rectWin, "\p", 0, plainDBox, (WindowPtr)-1, 0, 0);
+
+               // paint back ground black before fade in to avoid white background flash
+               ShowWindow(pWindow);
+               GetPort (&pGrafSave);
+               SetPortWindowPort (pWindow);
+               GetForeColor (&rgbSave);
+               RGBForeColor (&rgbBlack);
+               {
+                       Rect paintRect;
+                       GetWindowPortBounds (pWindow, &paintRect);
+                       PaintRect (&paintRect);
+               }
+               RGBForeColor (&rgbSave);                // ensure color is reset for proper blitting
+               SetPort (pGrafSave);
+               return (GetWindowPort (pWindow));
+       }
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+// clean up DSp
+
+void ShutdownDSp (CGrafPtr pDSpPort)
+{
+       if ((NULL != pDSpPort) && !CheckMacOSX ())
+               DisposeWindow (GetWindowFromPort (pDSpPort));
+       DSpContext_SetState( gContext, kDSpContextState_Inactive);
+       DSpContext_Release (gContext);
+}
+
+#pragma mark -
+//-----------------------------------------------------------------------------------------------------------------------
+
+// OpenGL Setup
+
+
+AGLContext SetupAGL (GDHandle hGD, AGLDrawable drawable)
+{
+       GLint                   attrib[64];
+       
+       AGLPixelFormat  fmt;
+       AGLContext      ctx;
+
+// different possible pixel format choices for different renderers 
+// basics requirements are RGBA and double buffer
+// OpenGLz will select acclerated context if available
+
+       short i = 0;
+       attrib [i++] = AGL_RGBA; // red green blue and alpha
+       attrib [i++] = AGL_DOUBLEBUFFER; // double buffered
+       attrib [i++] = AGL_DEPTH_SIZE; 
+       attrib [i++] = 8; 
+       attrib [i++] = AGL_ACCELERATED; // HWA pixel format only
+       attrib [i++] = AGL_NONE;
+
+       if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL
+       {
+               ReportError ("OpenGL not installed");
+               return NULL;
+       }       
+
+       if (hGD)
+               fmt = aglChoosePixelFormat (&hGD, 1, attrib); // get an appropriate pixel format
+       else
+               fmt = aglChoosePixelFormat(NULL, 0, attrib); // get an appropriate pixel format
+       aglDebugStr ();
+       if (NULL == fmt) 
+       {
+               ReportError("Could not find valid pixel format");
+               return NULL;
+       }
+
+       ctx = aglCreateContext (fmt, NULL); // Create an AGL context
+       aglDebugStr ();
+       if (NULL == ctx)
+       {
+               ReportError ("Could not create context");
+               return NULL;
+       }
+
+       if (!aglSetDrawable (ctx, drawable)) // attach the window to the context
+       {
+               ReportError ("SetDrawable failed");
+               aglDebugStr ();
+               return NULL;
+       }
+
+
+       if (!aglSetCurrentContext (ctx)) // make the context the current context
+       {
+               aglDebugStr ();
+               aglSetDrawable (ctx, NULL);
+               return NULL;
+       }
+
+       aglDestroyPixelFormat(fmt); // pixel format is no longer needed
+
+       return ctx;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+// OpenGL Setup
+
+AGLContext SetupAGLFullScreen (GDHandle display, short * pDepth, short * pWidth, short * pHeight)
+{
+       //GLint                 attrib[64];
+       GLint attrib[] ={AGL_RGBA, AGL_DOUBLEBUFFER,AGL_DEPTH_SIZE, 16, AGL_FULLSCREEN,AGL_ALL_RENDERERS, AGL_NONE};
+
+       AGLPixelFormat  fmt;
+       AGLContext      ctx;
+
+
+       if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL
+       {
+               ReportError ("OpenGL not installed");
+               return NULL;
+       }       
+
+       fmt = aglChoosePixelFormat(&display, 1, attrib); // this may fail if looking for acclerated across multiple monitors
+       if (NULL == fmt) 
+       {
+               ReportError("Could not find valid pixel format");
+               aglDebugStr ();
+               return NULL;
+       }
+
+       ctx = aglCreateContext (fmt, NULL); // Create an AGL context
+       if (NULL == ctx)
+       {
+               ReportError ("Could not create context");
+               aglDebugStr ();
+               return NULL;
+       }
+
+       if (!aglSetFullScreen (ctx, *pWidth, *pHeight, 60, 0))
+       {
+               ReportError ("SetFullScreen failed");
+               aglDebugStr ();
+               return NULL;
+       }
+
+       if (!aglSetCurrentContext (ctx)) // make the context the current context
+       {
+               ReportError ("SetCurrentContext failed");
+               aglDebugStr ();
+               aglSetDrawable (ctx, NULL); // turn off full screen
+               return NULL;
+       }
+
+       aglDestroyPixelFormat(fmt); // pixel format is no longer needed
+
+       return ctx;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+// OpenGL Cleanup
+
+void CleanupAGL(AGLContext ctx)
+{
+       aglSetDrawable (ctx, NULL);
+       aglSetCurrentContext (NULL);
+       aglDestroyContext (ctx);
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+// OpenGL Drawing
+
+void DrawGL (Rect * pRectPort)
+{
+       if (gaglContext == 0)
+               return;
+       aglSetCurrentContext (gaglContext); // ensure our context is current prior to drawing
+       
+    {
+        GLint width = pRectPort->right - pRectPort->left;
+        GLint height = pRectPort->bottom - pRectPort->top;
+        screenwidth=width;
+        screenheight=height;
+       /* glViewport ((width - (width * 1)) / 2, (height - (height * 1)) / 2,
+                    width * 1, height * 1);*/
+     }
+    
+       game.DrawGLScene();
+       
+       
+       //glDebugStr ();
+
+       // draw info
+       /*{
+               GLint matrixMode;
+        glViewport (0, 0, pRectPort->right - pRectPort->left, pRectPort->bottom - pRectPort->top);
+               glGetIntegerv (GL_MATRIX_MODE, &matrixMode);
+               glMatrixMode (GL_PROJECTION);
+               glPushMatrix();
+                       glLoadIdentity ();
+                       glMatrixMode (GL_MODELVIEW);
+                       glPushMatrix();
+                               glLoadIdentity ();
+                               glScalef (2.0 / (pRectPort->right - pRectPort->left), -2.0 /  (pRectPort->bottom - pRectPort->top), 1.0);
+                               glTranslatef (-(pRectPort->right - pRectPort->left) / 2.0, -(pRectPort->bottom - pRectPort->top) / 2.0, 0.0);
+                               glColor3f (1.0, 1.0, 1.0);
+                               glRasterPos3d (10, 12, 0); 
+                               DrawFrameRate (gFontList);
+                               glRasterPos3d (10, 24, 0); 
+                               DrawCStringGL (gcstrMode, gFontList);
+                               glRasterPos3d (10, (pRectPort->bottom - pRectPort->top) - 15, 0); 
+                               DrawCStringGL ((char*) glGetString (GL_VENDOR), gFontList);
+                               glRasterPos3d (10, (pRectPort->bottom - pRectPort->top) - 3, 0); 
+                               DrawCStringGL ((char*) glGetString (GL_RENDERER), gFontList);
+                               static char aChar[256] = "";
+                               sprintf (aChar, "     Mac OS X: %d",  RunningOnCarbonX());
+                               DrawCStringGL (aChar, gFontList);
+                       glPopMatrix();
+                       glMatrixMode (GL_PROJECTION);
+               glPopMatrix();
+               glMatrixMode (matrixMode);
+       }*/
+       //glDebugStr ();
+       //aglSwapBuffers(gaglContext); // send swap command
+}
+
+#pragma mark -
+//-----------------------------------------------------------------------------------------------------------------------
+
+static pascal OSErr QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEvent* reply, SInt32 refcon )
+{
+       #pragma unused (appleEvt, reply, refcon)
+       //gDone =  true;
+       game.tryquit=1;
+       return false;
+}
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+void InitToolbox(void)
+{
+       OSErr err;
+       long response;
+       MenuHandle menu;
+       
+       InitCursor();
+       
+// profile
+#if __profile__
+//     prototype:
+//             ProfilerInit (collection method, time base, num funcs, stack depth)
+       // default call
+       gProfErr = ProfilerInit (collectDetailed, bestTimeBase, 20, 10); // set up profiling
+       // something that you may need to do (may need more memory)
+//     gProfErr = ProfilerInit (collectSummary, bestTimeBase, 1000, 100); // set up profiling
+// Note: application will likely run slower, but still should be useful info
+       if (noErr == gProfErr)
+               ProfilerSetStatus(FALSE);
+#endif
+       
+       // Init Menus
+       menu = NewMenu (kMenuApple, "\p\024");                  // new  apple menu
+       InsertMenu (menu, 0);                                                   // add menu to end
+
+       menu = NewMenu (kMenuFile, "\pFile");                   // new menu
+       InsertMenu (menu, 0);                                                   // add menu to end
+
+       // insert application menus here
+       
+       // add quit if not under Mac OS X
+       err = Gestalt (gestaltMenuMgrAttr, &response);
+       if ((err == noErr) && !(response & gestaltMenuMgrAquaLayoutMask))
+                       AppendMenu (menu, "\pQuit/Q");                                  // add quit
+
+       DrawMenuBar();
+       err = AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(QuitAppleEventHandler), 0, false );
+       if (err != noErr)
+               ExitToShell();
+}
+
+// --------------------------------------------------------------------------
+
+static Point gMidPoint;
+
+Boolean SetUp (void)
+{
+       char string[10];
+       
+       SetQDGlobalsRandomSeed(TickCount());
+       
+       osx = 0;
+       if(CheckMacOSX ())osx = 1;
+       ifstream ipstream(":Data:config.txt");
+       detail=1;
+       ismotionblur=0;
+       usermousesensitivity=1;
+       kContextWidth=640;
+       kContextHeight=480;
+       kBitsPerPixel = 32;
+       floatjump=0;
+       cellophane=0;
+       texdetail=4;
+       autoslomo=1;
+       decals=1;
+       invertmouse=0;
+       bloodtoggle=0;
+       terraindetail=2;
+       foliage=1;
+       musictoggle=1;
+       trilinear=1;
+       gamespeed=1;
+       difficulty=1;
+       damageeffects=0;
+       texttoggle=1;
+       alwaysblur=0;
+       showpoints=0;
+       immediate=0;
+       velocityblur=0;
+       slomospeed=0.25;
+       slomofreq=8012;
+       
+       game.crouchkey=MAC_SHIFT_KEY;
+    game.jumpkey=MAC_SPACE_KEY;
+    game.leftkey=MAC_A_KEY;
+    game.forwardkey=MAC_W_KEY;
+    game.backkey=MAC_S_KEY;
+    game.rightkey=MAC_D_KEY;
+    game.drawkey=MAC_E_KEY;
+    game.throwkey=MAC_Q_KEY;
+    game.attackkey=MAC_MOUSEBUTTON1;
+    game.chatkey=MAC_T_KEY;
+    numplayers=1;
+    ambientsound=1;
+    vblsync=0;
+    debugmode=0;
+    if(!ipstream) {
+        ofstream opstream(":Data:config.txt"); 
+        opstream << "Screenwidth:\n";
+        opstream << kContextWidth;
+        opstream << "\nScreenheight:\n";
+           opstream << kContextHeight;
+           opstream << "\nMouse sensitivity:\n";
+           opstream << usermousesensitivity;
+           opstream << "\nBlur(0,1):\n";
+           opstream << ismotionblur;
+               opstream << "\nOverall Detail(0,1,2) higher=better:\n";
+           opstream << detail;
+           opstream << "\nFloating jump:\n";
+           opstream << floatjump;
+           opstream << "\nMouse jump:\n";
+           opstream << mousejump;
+           opstream << "\nAmbient sound:\n";
+           opstream << ambientsound;
+               opstream << "\nBlood (0,1,2):\n";
+        opstream << bloodtoggle;
+        opstream << "\nAuto slomo:\n";
+        opstream << autoslomo;
+           opstream << "\nFoliage:\n";
+        opstream << foliage;
+        opstream << "\nMusic:\n";
+        opstream << musictoggle;
+        opstream << "\nTrilinear:\n";
+        opstream << trilinear;
+           opstream << "\nDecals(shadows,blood puddles,etc):\n";
+        opstream << decals;
+           opstream << "\nInvert mouse:\n";
+        opstream << invertmouse;
+           opstream << "\nGamespeed:\n";
+        opstream << gamespeed;
+        opstream << "\nDifficulty(0,1,2) higher=harder:\n";
+        opstream << difficulty;
+        opstream << "\nDamage effects(blackout, doublevision):\n";
+        opstream << damageeffects;
+           opstream << "\nText:\n";
+        opstream << texttoggle;
+           opstream << "\nDebug:\n";
+        opstream << debugmode;
+           opstream << "\nVBL Sync:\n";
+        opstream << vblsync;
+        opstream << "\nShow Points:\n";
+        opstream << showpoints;
+        opstream << "\nAlways Blur:\n";
+        opstream << alwaysblur;
+           opstream << "\nImmediate mode (turn on on G5):\n";
+        opstream << immediate;
+           opstream << "\nVelocity blur:\n";
+        opstream << velocityblur;
+           opstream << "\nForward key:\n";
+           opstream << KeyToChar(game.forwardkey);
+           opstream << "\nBack key:\n";
+           opstream << KeyToChar(game.backkey);
+           opstream << "\nLeft key:\n";
+           opstream << KeyToChar(game.leftkey);
+           opstream << "\nRight key:\n";
+           opstream << KeyToChar(game.rightkey);
+           opstream << "\nJump key:\n";
+           opstream << KeyToChar(game.jumpkey);
+           opstream << "\nCrouch key:\n";
+           opstream << KeyToChar(game.crouchkey);
+           opstream << "\nDraw key:\n";
+           opstream << KeyToChar(game.drawkey);
+           opstream << "\nThrow key:\n";
+           opstream << KeyToChar(game.throwkey);
+           opstream << "\nAttack key:\n";
+           opstream << KeyToChar(game.attackkey);
+           opstream << "\nChat key:\n";
+           opstream << KeyToChar(game.chatkey);
+           opstream.close();
+    }
+    if(ipstream){
+               ipstream.ignore(256,'\n');
+           ipstream >> kContextWidth;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> kContextHeight;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> usermousesensitivity;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> ismotionblur;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> detail;
+           if(detail!=0)kBitsPerPixel=32;
+           else kBitsPerPixel=16;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> floatjump;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> mousejump;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> ambientsound;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> bloodtoggle;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> autoslomo;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> foliage;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> musictoggle;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> trilinear;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> decals;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> invertmouse;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> gamespeed;
+           oldgamespeed=gamespeed;
+           if(oldgamespeed==0){
+               gamespeed=1;
+               oldgamespeed=1;
+           }
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> difficulty;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> damageeffects;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> texttoggle;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> debugmode;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> vblsync;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> showpoints;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> alwaysblur;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> immediate;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> velocityblur;
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n'); 
+           ipstream >> string;
+           game.forwardkey=CharToKey(string);
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> string;
+           game.backkey=CharToKey(string);
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> string;
+           game.leftkey=CharToKey(string);
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> string;
+           game.rightkey=CharToKey(string);
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> string;
+           game.jumpkey=CharToKey(string);
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> string;
+           game.crouchkey=CharToKey(string);
+           ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> string;
+           game.drawkey=CharToKey(string);
+            ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> string;
+           game.throwkey=CharToKey(string);
+             ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> string;
+           game.attackkey=CharToKey(string);
+            ipstream.ignore(256,'\n');
+           ipstream.ignore(256,'\n');
+           ipstream >> string;
+           game.chatkey=CharToKey(string);
+           ipstream.close();
+           
+           if(detail>2)detail=2;
+           if(detail<0)detail=0;
+           if(screenwidth>3000)screenwidth=640;
+               if(screenwidth<0)screenwidth=640;
+               if(screenheight>3000)screenheight=480;
+               if(screenheight<0)screenheight=480;
+       }
+
+       
+       if(vblsync){    
+               GLint swapInt = 1;
+               aglSetInteger(gaglContext, AGL_SWAP_INTERVAL, &swapInt);
+       }
+       
+       if(kBitsPerPixel!=32&&kBitsPerPixel!=16){
+               kBitsPerPixel=16;
+       }
+
+       
+       GDHandle hGD, hTargetDevice = NULL;
+       short numDevices = 0;
+       short fNum = 0;
+       short whichDevice = 0; // number of device to try (0 = 1st device)
+
+       InitToolbox ();
+       
+       gpDSpPort = NULL;
+       gaglContext = 0;
+       
+       // check for DSp
+       if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) DSpStartup) 
+               ReportError ("DSp not installed");
+
+       if (noErr != DSpDebugStr (DSpStartup()))
+               return NULL;
+//     DSpSetDebugMode (true);
+#if defined kUseFades
+       DSpDebugStr (DSpContext_FadeGammaOut (NULL, NULL)); // fade display, remove for debug
+#endif
+       
+       hGD = DMGetFirstScreenDevice (true); // check number of screens
+       hTargetDevice = hGD; // default to first device                                                 
+       do
+       {
+               if (numDevices == whichDevice)
+                       hTargetDevice = hGD; // if device number matches                                                
+               numDevices++;
+               hGD = DMGetNextScreenDevice (hGD, true);
+       }
+       while (hGD);
+
+#if defined (kUseAGLFullScreenX)
+       if (CheckMacOSX ()) // Try AGL full screen on Mac OS X
+       {
+               short depth = kBitsPerPixel, width = kContextWidth, height = kContextHeight; 
+               gaglContext = SetupAGLFullScreen (hTargetDevice, &depth, &width, &height); // Setup the OpenGL context
+               SetRect (&gRectPort, 0, 0, width, height); // l, t, r, b
+               sprintf (gcstrMode, "AGL Full Screen: %d x %d x %d", width, height, depth);
+       }
+#endif
+       if (!gaglContext) //try DSp
+       {
+               if (NULL != (gpDSpPort = SetupDSpFullScreen (hTargetDevice))) // Setup DSp for OpenGL sets hTargetDeviceto device actually used 
+               {
+                       GetPortBounds (gpDSpPort, &gRectPort);
+                       sprintf (gcstrMode, "DrawSprocket Full Screen: %d x %d x %d", gRectPort.right - gRectPort.left, gRectPort.bottom - gRectPort.top, (**(**hTargetDevice).gdPMap).pixelSize);
+                       gaglContext = SetupAGL (hTargetDevice, gpDSpPort);
+               }
+       }
+       if (gaglContext)
+       {
+               GetFNum("\pMonaco", &fNum);                                                                     // build font
+               gFontList = BuildFontGL (gaglContext, fNum, normal, 9);
+               //InstallEventLoopTimer (GetCurrentEventLoop(), 0, 0.0001, GetTimerUPP (), 0, &gTimer);
+       }
+       
+       //gMidPoint.h = (gRectPort.left + gRectPort.right)/2;
+       //gMidPoint.v = (gRectPort.top + gRectPort.bottom)/2;
+       gMidPoint.h = 200;
+       gMidPoint.v = 200;
+       GLint swapInt = 1;
+       //aglSetInteger(gaglContext, AGL_SWAP_INTERVAL, &swapInt);
+       
+#if defined kUseFades
+       DSpDebugStr (DSpContext_FadeGammaIn (NULL, NULL));
+#endif
+       
+       
+       HideCursor();
+       
+       
+    GLint width = gRectPort.right - gRectPort.left;
+    GLint height = gRectPort.bottom - gRectPort.top;
+    screenwidth=width;
+    screenheight=height;
+     
+    game.newdetail=detail;
+       game.newscreenwidth=screenwidth;
+       game.newscreenheight=screenheight;
+     
+       game.InitGame();
+       
+       if (gaglContext)
+               return true;
+       else
+               return false;
+       
+}
+
+static Boolean RunningOnCarbonX(void)
+{
+       static Boolean first = true;
+       static Boolean result = false;
+
+       if (first)
+       {
+               UInt32 response;
+
+               first = false;
+
+               result = (Gestalt(gestaltSystemVersion, 
+                    (SInt32 *) &response) == noErr)
+                && (response >= 0x01000);
+       }
+    return result;
+}
+
+static OSStatus LoadFrameworkBundle(CFStringRef pFrameworkCFStrRef, CFBundleRef *pFrameworkCFBndlRef)
+{
+       OSStatus        err;
+       FSRef           frameworksFolderRef;
+       CFURLRef        baseURL;
+       CFURLRef        bundleURL;
+       
+       if (nil == pFrameworkCFBndlRef) return paramErr;
+       
+       *pFrameworkCFBndlRef = nil;
+       
+       baseURL = nil;
+       bundleURL = nil;
+       
+       err = FSFindFolder(kOnAppropriateDisk, kFrameworksFolderType, true, &frameworksFolderRef);
+       if (err == noErr) {
+               baseURL = CFURLCreateFromFSRef(kCFAllocatorSystemDefault, &frameworksFolderRef);
+               if (baseURL == nil) {
+                       err = coreFoundationUnknownErr;
+               }
+       }
+       if (err == noErr) {
+               bundleURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, pFrameworkCFStrRef, false);
+               if (bundleURL == nil) {
+                       err = coreFoundationUnknownErr;
+               }
+       }
+       if (err == noErr) {
+               *pFrameworkCFBndlRef = CFBundleCreate(kCFAllocatorSystemDefault, bundleURL);
+               if (*pFrameworkCFBndlRef == nil) {
+                       err = coreFoundationUnknownErr;
+               }
+       }
+       if (err == noErr) {
+           if ( ! CFBundleLoadExecutable( *pFrameworkCFBndlRef ) ) {
+                       err = coreFoundationUnknownErr;
+           }
+       }
+
+       // Clean up.
+       
+       if (err != noErr && *pFrameworkCFBndlRef != nil) {
+               CFRelease(*pFrameworkCFBndlRef);
+               *pFrameworkCFBndlRef = nil;
+       }
+       if (bundleURL != nil) {
+               CFRelease(bundleURL);
+       }       
+       if (baseURL != nil) {
+               CFRelease(baseURL);
+       }       
+       
+       return err;
+}
+
+
+
+static CFragConnectionID gCFragConnectionID = 0;
+
+typedef pascal OSErr (*CDM_NewDeviceProcPtr)(CursorDevicePtr * ourDevice);
+
+static OSErr MyCursorDeviceNewDevice(CursorDevicePtr * ourDevice)
+{
+       static CDM_NewDeviceProcPtr sCDM_NewDeviceProcPtr = nil;
+       OSStatus anErr = noErr;
+
+       if (nil == ourDevice) return paramErr;
+
+       if (!RunningOnCarbonX())
+       {
+               if (!sCDM_NewDeviceProcPtr)
+               {
+                       if (!gCFragConnectionID)
+                       {
+                               Ptr             mainAddr;
+                               Str255  errName;
+
+                               anErr = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch,
+                                        kFindCFrag, &gCFragConnectionID, &mainAddr, errName);
+                               if (noErr != anErr) return anErr;
+                       }
+
+                       if (gCFragConnectionID)
+                       {
+                               CFragSymbolClass symClass;
+
+                               anErr = FindSymbol(gCFragConnectionID, "\pCrsrDevNewDevice",
+                                       (Ptr*) &sCDM_NewDeviceProcPtr, &symClass);
+                               if (noErr != anErr) return anErr;
+                       }
+               }
+               if (sCDM_NewDeviceProcPtr)
+                       anErr = (*sCDM_NewDeviceProcPtr)(ourDevice);
+               else
+                       anErr = paramErr;
+       }
+
+       return anErr;
+}
+
+typedef pascal OSErr (*CDM_CursorDeviceMoveToProcPtr)(
+                                                       CursorDevicePtr   ourDevice,
+                                                       long              absX,
+                                                       long              absY);
+
+typedef UInt32 (*CGWarpMouseCursorPositionProcPtr)(CGPoint newCursorPosition);
+typedef UInt32 (*CGSetLocalEventsSuppressionIntervalProcPtr)(double pSeconds);
+
+static OSErr MyCursorDeviceMoveTo(     CursorDevicePtr   ourDevice,
+                                                       long              absX,
+                                                       long              absY)
+{
+       OSStatus anErr = noErr;
+
+       if (RunningOnCarbonX())
+       {
+               static CGWarpMouseCursorPositionProcPtr sCGWarpMouseCursorPositionProcPtr = nil;
+
+               if (nil == sCGWarpMouseCursorPositionProcPtr)
+               {
+                       CFBundleRef tCFBundleRef;
+
+                       anErr = LoadFrameworkBundle(CFSTR("ApplicationServices.framework"), &tCFBundleRef);
+
+                       if (noErr == anErr)
+                       {
+                               CGSetLocalEventsSuppressionIntervalProcPtr tCGSetLocalEventsSuppressionIntervalProcPtr = nil;
+
+                               sCGWarpMouseCursorPositionProcPtr = (CGWarpMouseCursorPositionProcPtr)
+                                       CFBundleGetFunctionPointerForName( tCFBundleRef, CFSTR("CGWarpMouseCursorPosition") );
+                               if (nil == sCGWarpMouseCursorPositionProcPtr)
+                                       anErr = cfragNoSymbolErr;
+
+                               tCGSetLocalEventsSuppressionIntervalProcPtr = (CGSetLocalEventsSuppressionIntervalProcPtr)
+                                       CFBundleGetFunctionPointerForName(tCFBundleRef,CFSTR("CGSetLocalEventsSuppressionInterval"));
+                               if (nil != tCGSetLocalEventsSuppressionIntervalProcPtr)
+                                       (*tCGSetLocalEventsSuppressionIntervalProcPtr)(0.0f);
+                       }
+               }
+
+               if (nil != sCGWarpMouseCursorPositionProcPtr)
+               {
+                       CGPoint tCGPoint;
+
+                       tCGPoint.x = absX;
+                       tCGPoint.y = absY;
+
+                       (*sCGWarpMouseCursorPositionProcPtr)(tCGPoint);
+               }
+       }
+       else
+       {
+               static CDM_CursorDeviceMoveToProcPtr sCDM_CursorDeviceMoveToProcPtr = nil;
+
+               if (!ourDevice) return paramErr;
+
+               if (!sCDM_CursorDeviceMoveToProcPtr)
+               {
+                       if (!gCFragConnectionID)
+                       {
+                               Ptr             mainAddr;
+                               Str255  errName;
+
+                               anErr = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch,
+                                        kFindCFrag, &gCFragConnectionID, &mainAddr, errName);
+                               if (noErr != anErr) return anErr;
+                       }
+
+                       if (gCFragConnectionID)
+                       {
+                               CFragSymbolClass symClass;
+
+                               anErr = FindSymbol(gCFragConnectionID, "\pCrsrDevMoveTo",
+                                       (Ptr*) &sCDM_CursorDeviceMoveToProcPtr, &symClass);
+                               if (noErr != anErr) return anErr;
+                       }
+               }
+               if (sCDM_CursorDeviceMoveToProcPtr)
+                       anErr = (*sCDM_CursorDeviceMoveToProcPtr)(ourDevice,absX,absY);
+               else
+                       anErr = paramErr;
+       }
+
+       return anErr;
+}
+
+static void DoMouse(void)
+{
+       static CursorDevicePtr virtualCursorDevicePtr = nil;
+       OSStatus anErr = noErr;
+
+        HideCursor();
+
+       if (nil == virtualCursorDevicePtr)
+               anErr = MyCursorDeviceNewDevice(&virtualCursorDevicePtr);
+
+       {
+               static Point lastMouse = {-1,-1};
+               Point globalMouse;
+
+               GetGlobalMouse(&globalMouse);
+       
+               if (EqualPt(lastMouse, globalMouse))
+               {
+                       game.deltah=0;
+                       game.deltav=0;
+               }
+
+               if (!EqualPt(lastMouse, globalMouse))
+               {
+                       static Point virtualMouse = {0,0};
+                       delta = globalMouse;
+
+                       SubPt(lastMouse, &delta);
+                       GetGlobalMouse(&lastMouse);
+                       //AddPt(delta, &virtualMouse);
+                       
+                       if(mainmenu||(abs(delta.h)<10*realmultiplier*1000&&abs(delta.v)<10*realmultiplier*1000)){
+                       game.deltah=delta.h*usermousesensitivity;
+                       game.deltav=delta.v*usermousesensitivity;
+                       game.mousecoordh=globalMouse.h;
+                       game.mousecoordv=globalMouse.v;
+                       }
+#if 1
+                       //printf("\nMouse Moved: {%d,%d}.",globalMouse.h,globalMouse.v);
+                       //printf("\tdelta: {%d,%d}.",delta.h,delta.v);
+                       //printf("\tvirtual: {%d,%d}.",virtualMouse.h,virtualMouse.v);
+#endif
+                       if(!mainmenu)
+                       if(lastMouse.h>gMidPoint.h+100||lastMouse.h<gMidPoint.h-100||lastMouse.v>gMidPoint.v+100||lastMouse.v<gMidPoint.v-100){
+                               MyCursorDeviceMoveTo(virtualCursorDevicePtr,gMidPoint.h,gMidPoint.v);
+                               lastMouse = gMidPoint;
+                       }
+               }
+       }
+}
+
+
+// --------------------------------------------------------------------------
+
+void DoMenu (SInt32 menuResult)
+{
+       SInt16 theMenu;
+       SInt16 theItem;
+       MenuRef theMenuHandle;
+               
+       theMenu = HiWord(menuResult);
+       theItem = LoWord(menuResult);
+       theMenuHandle = GetMenuHandle(theMenu);
+
+       switch (theMenu)
+       {
+               case kMenuApple:
+                       switch (theItem)
+                       {
+                               case kAppleAbout:
+                                       break;
+                               default:
+                                       break;
+                       }
+                       break;
+               case kMenuFile:
+                       switch (theItem)
+                       {
+                               case kFileQuit:
+                                       game.quit = true;
+                                       break;
+                       }
+                       break;
+       }
+       HiliteMenu(0);
+       DrawMenuBar();
+}
+
+// --------------------------------------------------------------------------
+
+void DoKey (SInt8 theKey, SInt8 theCode)
+{
+       #pragma unused (theCode, theKey)
+    /*if ((theKey == '=') || (theKey == '+'))
+        gfScale *= 1.1;
+    if (theKey == '-')
+        gfScale /= 1.1;*/
+       // do nothing
+}
+
+// --------------------------------------------------------------------------
+
+
+
+/*void DoUpdate (void)
+{
+       static float sps=200;
+       static int count;
+       static float oldmult;
+
+       DoFrameRate();
+       
+       count = multiplier*sps;
+       if(count<2)count=2;
+       
+       oldmult=multiplier;
+       multiplier/=count;
+       
+       for(int i=0;i<count;i++){
+               game.Tick();
+       }
+       multiplier=oldmult;
+       
+       game.TickOnce();
+       
+       DoMouse();
+
+       DrawGL (&gRectPort);
+}*/
+
+void DoUpdate (void)
+{
+       static float sps=200;
+       static int count;
+       static float oldmult;
+       
+       DoFrameRate(1);
+       
+       if(multiplier>.6)multiplier=.6;
+       
+       game.fps=1/multiplier;
+
+       count = multiplier*sps;
+       if(count<2)count=2;
+       //if(count>10)count=10;
+       
+       realmultiplier=multiplier;
+       multiplier*=gamespeed;
+       if(difficulty==1)multiplier*=.9;
+       if(difficulty==0)multiplier*=.8;
+       
+       if(game.loading==4)multiplier*=.00001;
+
+       //multiplier*.9;
+       if(slomo&&!mainmenu)multiplier*=slomospeed;
+       //if(freeze)multiplier*=0.00001;
+       oldmult=multiplier;
+       multiplier/=(float)count;
+       
+       DoMouse();
+       
+       game.TickOnce();
+       
+       for(int i=0;i<count;i++){
+               game.Tick();
+       }
+       multiplier=oldmult;
+       
+       game.TickOnceAfter();
+       
+       DrawGL (&gRectPort);
+}
+
+// --------------------------------------------------------------------------
+
+Boolean WaitNextEventWrapper (EventMask eventMask, EventRecord *theEvent, unsigned long sleep,RgnHandle mouseRgn)
+{
+       return WaitNextEvent (eventMask, theEvent, sleep, mouseRgn);
+}
+
+// --------------------------------------------------------------------------
+
+OSStatus DSpProcessEventWrapper (EventRecord *inEvent, Boolean *outEventWasProcessed)
+{
+       return DSpProcessEvent (inEvent, outEventWasProcessed);
+}
+
+// --------------------------------------------------------------------------
+
+void UpdateWrapper (EventRecord *theEvent)
+{
+       WindowRef whichWindow;
+       GrafPtr pGrafSave;
+       
+       whichWindow = (WindowRef) theEvent->message;
+       GetPort (&pGrafSave);
+       SetPort((GrafPtr) GetWindowPort(whichWindow));
+       BeginUpdate(whichWindow);
+       DoUpdate();
+       SetPort((GrafPtr) GetWindowPort(whichWindow));
+       EndUpdate(whichWindow);
+       SetPort (pGrafSave);
+}
+
+// --------------------------------------------------------------------------
+
+pascal void IdleTimer (EventLoopTimerRef inTimer, void* userData)
+{
+       #pragma unused (inTimer, userData)
+       if(!stillloading)DoUpdate ();
+}
+
+// --------------------------------------------------------------------------
+
+EventLoopTimerUPP GetTimerUPP (void)
+{
+       static EventLoopTimerUPP        sTimerUPP = NULL;
+       
+       if (sTimerUPP == NULL)
+               sTimerUPP = NewEventLoopTimerUPP (IdleTimer);
+       
+       return sTimerUPP;
+}
+
+// --------------------------------------------------------------------------
+
+pascal OSStatus mDown (EventHandlerCallRef ref, EventRef e,void * thedata) {
+       EventMouseButton button;
+       OSStatus status;
+       
+       status = GetEventParameter (e, kEventParamMouseButton, typeMouseButton, NULL, 
+               sizeof (button), NULL, &button);
+       
+       buttons[button-1] = true;               
+       
+       return eventNotHandledErr;
+}
+
+pascal OSStatus mUp (EventHandlerCallRef ref, EventRef e,void * thedata) {
+       EventMouseButton button = 0;
+       OSStatus status;
+       
+       status = GetEventParameter (e, kEventParamMouseButton, typeMouseButton, NULL, 
+               sizeof (EventMouseButton), NULL, &button);
+       
+       buttons[button-1] = false;      
+       
+       return eventNotHandledErr;      
+}
+
+void InstallHandlers(void){
+       OSStatus status;
+       EventTypeSpec spec;
+       
+       spec.eventClass = kEventClassMouse;
+       spec.eventKind = kEventMouseDown;
+
+       status = InstallEventHandler (GetApplicationEventTarget(), 
+               NewEventHandlerUPP (mDown), 1, &spec, NULL, NULL);
+       
+       
+       spec.eventKind = kEventMouseUp;
+       
+       status = InstallEventHandler (GetApplicationEventTarget(), 
+               NewEventHandlerUPP (mUp), 1, &spec, NULL, NULL);
+
+}
+
+void NewEvent(void) {
+       EventRecord e;
+       OSStatus s;
+       
+       
+       /*ReceiveNextEvent (0, NULL, 1, true, &er);
+       
+       s = SendEventToEventTarget (er, GetEventDispatcherTarget());*/
+       WaitNextEvent (everyEvent, &e, 0, NULL);
+       
+       DoUpdate();
+}
+
+void DoEvent (void)
+{
+       EventRecord theEvent;
+       WindowRef whichWindow;
+       SInt16 whatPart;
+       Boolean fProcessed;
+       
+// profile
+#if __profile__
+       if (noErr == gProfErr)
+               ProfilerSetStatus(TRUE); // turn on profiling
+#endif
+
+       if (WaitNextEventWrapper (everyEvent, &theEvent, gSleepTime, NULL))
+       {
+               DSpProcessEventWrapper (&theEvent, &fProcessed);
+               if (!fProcessed)
+               {
+                       switch (theEvent.what)
+                       {
+                               case mouseDown:
+                                       whatPart = FindWindow (theEvent.where, &whichWindow);
+                                       switch (whatPart)
+                                       {
+                                               case inContent:
+//                                                     if (GetWindowFromPort (gpDSpPort) != FrontWindow()) 
+//                                                             SelectWindow (GetWindowFromPort (gpDSpPort));
+                                                       break;
+                                               case inMenuBar:
+                                               {
+                                                       SInt32 menuResult = MenuSelect (theEvent.where);
+                                                       if (HiWord (menuResult) != 0)
+                                                               DoMenu (menuResult);
+                                               }
+                                                       break;
+                                               case inDrag:
+                                                       {
+                                                               // full screen no drag
+                                                       }
+                                                       break;
+                                               case inGrow:
+                                                       {
+                                                               // full screen no grow
+                                                       }
+                                                       break;
+                                               case inGoAway:
+                                                       {
+                                                               // full screen no go away
+                                                       }
+                                                       break;
+                                               case inZoomIn:
+                                               case inZoomOut:
+                                                       {
+                                                               // full screen no zoom
+                                                       }
+                                                       break;
+                                               case inSysWindow:
+                                                       break;
+                                       }
+                                       break;
+                               case keyDown:
+                               case autoKey:
+                               {
+                                       SInt8 theKey;
+                                       SInt8 theCode;
+                                       theKey = theEvent.message & charCodeMask;
+                                       theCode = (theEvent.message & keyCodeMask) >> 8;
+                                       if ((theEvent.modifiers & cmdKey) != 0)
+                                       {
+                                               SInt32 menuResult = MenuKey (theKey);
+                                               if (HiWord(menuResult) != 0)
+                                                       DoMenu (menuResult);
+                                       }
+                                       else
+                                               DoKey (theKey, theCode);
+                               }
+                                       break;
+                               case updateEvt:
+                               {
+                                       UpdateWrapper (&theEvent);
+                               }
+                                       break;
+                               case diskEvt:
+                                       break;
+                               /*case osEvt:
+                                       if (theEvent.message & 0x01000000)              //      Suspend/resume event
+                                       {
+                                               if (theEvent.message & 0x00000001)      //      Resume
+                                               {
+                                                       gSleepTime = kForegroundSleep;  
+                                                       gfFrontProcess = true;
+                                               }
+                                               else
+                                               {
+                                                       gSleepTime = kBackgroundSleep;  //      Suspend
+                                                       gfFrontProcess = false;
+                                               }
+                                       }
+                                       break;*/
+
+                               case kHighLevelEvent:
+                                       AEProcessAppleEvent (&theEvent);
+                                       break;
+                       }
+               }
+       }
+// profile
+#if __profile__
+       if (noErr == gProfErr)
+               ProfilerSetStatus(FALSE); // turn profiling off again
+#endif
+}
+
+// --------------------------------------------------------------------------
+
+void CleanUp (void)
+{
+       MenuHandle hMenu;
+       
+// profile
+#if __profile__
+       if (noErr == gProfErr)
+       {
+               ProfilerDump ("\pGL DSp Carbon.prof");
+               ProfilerTerm ();
+       }
+#endif
+
+       game.Dispose();
+       
+#if defined kUseFades
+       DSpDebugStr (DSpContext_FadeGammaOut (NULL, NULL)); // fade display, remove for debug
+#endif
+
+       RemoveEventLoopTimer(gTimer);
+       gTimer = NULL;
+
+       DeleteFontGL (gFontList);
+       CleanupAGL (gaglContext); // Cleanup the OpenGL context
+       gaglContext = 0;
+       if (gpDSpPort)
+       {
+               ShutdownDSp (gpDSpPort); // DSp shutdown
+               gpDSpPort = NULL;
+       }
+
+       
+       hMenu = GetMenuHandle (kMenuFile);
+       DeleteMenu (kMenuFile);
+       DisposeMenu (hMenu);
+
+       hMenu = GetMenuHandle (kMenuApple);
+       DeleteMenu (kMenuApple);
+       DisposeMenu (hMenu);
+
+#if defined kUseFades
+       DSpDebugStr (DSpContext_FadeGammaIn (NULL, NULL)); // fade display, remove for debug
+#endif
+       DSpShutdown ();
+       
+       ShowCursor();
+}
+
+// --------------------------------------------------------------------------
+#include <iostream>
+#include <InternetConfig.h>
+
+/*void openURL()
+{
+#ifdef Q_WS_MAC
+       QString url("http://www.wolfire.com/");
+       ICInstance icInstance
+       OSType psiSignature = 'Psi ';
+       OSStatus error = ::ICStart( &icInstance, psiSignature);
+       if(error=noErr){
+               ConstStr255Param hint( 0x0 );
+               const char* data = url.latin1();
+               long length = url.length();
+               long start( 0 );
+               long end( length );
+               ::ICLaunchURL( icInstance, hint, data, length, &start, &end);
+               ICStop( icInstance);
+       }
+       #endif
+}*/
+
+void LaunchURL(char *url)
+{
+       ICInstance gICInstance;
+       ICStart (&gICInstance, 0);
+       long int start,fin;
+       start=0;
+       fin=strlen(url);
+       ICLaunchURL(gICInstance, "\p" ,url, fin, &start, &fin);
+}
+       
+       
+       
+int main (void)
+{
+       try { 
+               if (SetUp ())   {
+                       InstallHandlers();
+                       while (!gDone&&!game.quit&&(!game.tryquit||!game.registered)) {
+                               NewEvent ();
+                       }
+               }
+               CleanUp ();
+               if(game.registernow){
+                       char url[100];
+                       sprintf(url,"http://www.wolfire.com/register.html");
+                       LaunchURL(url);
+               }
+               return 0;
+       } catch (const std::exception& error) { 
+               ofstream opstream("error.txt"); 
+        opstream << "Caught exception: " << error.what() << std::endl;
+           opstream.close();
+       }       
+}
\ No newline at end of file
diff --git a/Source/OpenGL_Windows.cpp b/Source/OpenGL_Windows.cpp
new file mode 100644 (file)
index 0000000..ae73a83
--- /dev/null
@@ -0,0 +1,1876 @@
+#include <vld.h>
+#include "Game.h"
+
+// ADDED GWC
+#pragma comment(lib, "opengl32.lib")
+#pragma comment(lib, "glu32.lib")
+#pragma comment(lib, "glaux.lib")
+
+extern bool buttons[3];
+extern float multiplier;
+extern float screenwidth,screenheight;
+extern float sps;
+extern float realmultiplier;
+extern int slomo;
+extern bool ismotionblur;
+extern float usermousesensitivity;
+extern int detail;
+extern bool floatjump;
+extern bool cellophane;
+// MODIFIED GWC
+//extern int terraindetail;
+//extern int texdetail;
+extern float terraindetail;
+extern float texdetail;
+extern int bloodtoggle;
+extern bool osx;
+extern bool autoslomo;
+extern bool foliage;
+extern bool musictoggle;
+extern bool trilinear;
+extern float gamespeed;
+extern int difficulty;
+extern bool damageeffects;
+extern int numplayers;
+extern bool decals;
+extern bool invertmouse;
+extern bool texttoggle;
+extern bool ambientsound;
+extern bool mousejump;
+extern bool freeze;
+extern Person player[maxplayers];
+extern bool vblsync;
+extern bool stillloading;
+extern bool showpoints;
+extern bool alwaysblur;
+extern bool immediate;
+extern bool velocityblur;
+extern bool debugmode;
+extern int mainmenu;
+/*extern*/ bool gameFocused;
+extern int kBitsPerPixel;
+extern float slomospeed;
+extern float slomofreq;
+extern float oldgamespeed;
+extern float volume;
+
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <fstream>
+#include <iostream>
+#include "gl.h"
+#include "WinDefs.h"
+#include <shellapi.h>
+#include "fmod.h"
+
+#include "res/resource.h"
+
+using namespace std;
+
+
+unsigned int resolutionDepths[8][2] = {0};
+
+bool selectDetail(int & width, int & height, int & bpp, int & detail);
+int closestResolution(int width, int height);
+int resolutionID(int width, int height);
+
+void ReportError (char * strError);
+
+void SetupDSpFullScreen();
+void ShutdownDSp();
+
+void DrawGL(Game & game);
+
+void CreateGLWindow (void);
+Boolean SetUp (Game & game);
+void DoKey (SInt8 theKey, SInt8 theCode);
+void DoUpdate (Game & game);
+
+void DoEvent (void);
+void CleanUp (void);
+
+
+// statics/globals (internal only) ------------------------------------------
+
+Point delta;
+
+static const char g_wndClassName[]={ "LUGARUWINDOWCLASS" };
+
+static HINSTANCE g_appInstance;
+static HWND g_windowHandle;
+static HGLRC hRC;
+static bool g_button, fullscreen = true;
+
+
+// Menu defs
+enum 
+{
+       kFileQuit = 1
+};
+
+enum 
+{
+       kForegroundSleep = 10,
+       kBackgroundSleep = 10000
+};
+
+
+int kContextWidth;
+int kContextHeight;
+
+const RGBColor rgbBlack = { 0x0000, 0x0000, 0x0000 };
+
+extern HDC hDC;
+GLuint gFontList;
+char gcstrMode [256] = "";
+
+UInt32 gSleepTime = kForegroundSleep;
+Boolean gDone = false, gfFrontProcess = true;
+
+Game * pgame = 0;
+
+// --------------------------------------------------------------------------
+
+void ReportError (char * strError)
+{
+       throw std::exception( strError);
+
+       /*      char errMsgCStr [256];
+       Str255 strErr;
+
+       sprintf (errMsgCStr, "%s", strError); 
+
+       // out as debug string
+       CToPStr (strErr, errMsgCStr);
+       DebugStr (strErr);
+       */
+}
+
+void SetupDSpFullScreen ()
+{
+       LOGFUNC;
+
+       if (fullscreen)
+       {
+               DEVMODE dmScreenSettings;
+               memset( &dmScreenSettings, 0, sizeof( dmScreenSettings));
+               dmScreenSettings.dmSize = sizeof( dmScreenSettings);
+               dmScreenSettings.dmPelsWidth    = kContextWidth;
+               dmScreenSettings.dmPelsHeight   = kContextHeight;
+               dmScreenSettings.dmBitsPerPel   = kBitsPerPixel;
+               dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
+
+               // set video mode
+               if (ChangeDisplaySettings( &dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
+               {
+                       ReportError( "Could not set display mode");
+                       return;
+               }
+       }
+
+       ShowCursor(FALSE);
+}
+
+
+void ShutdownDSp ()
+{
+       LOGFUNC;
+
+       if (fullscreen)
+       {
+               ChangeDisplaySettings( NULL, 0);
+       }
+
+       ShowCursor(TRUE);
+}
+
+
+//-----------------------------------------------------------------------------------------------------------------------
+
+// OpenGL Drawing
+
+void DrawGL (Game & game)
+{
+       if (hDC == 0)
+               return;
+
+       game.DrawGLScene();
+}
+
+
+
+// --------------------------------------------------------------------------
+
+static Point gMidPoint;
+
+Boolean SetUp (Game & game)
+{
+       char string[10];
+
+       LOGFUNC;
+
+       randSeed = UpTime().lo;
+
+       osx = 0;
+//     ifstream ipstream(":Data:config.txt", std::ios::in /*| std::ios::nocreate*/);
+       ifstream ipstream("./Data/config.txt", std::ios::in /*| std::ios::nocreate*/);
+       detail=1;
+       ismotionblur=0;
+       usermousesensitivity=1;
+       kContextWidth=640;
+       kContextHeight=480;
+       kBitsPerPixel = 32;
+       floatjump=0;
+       cellophane=0;
+       texdetail=4;
+       autoslomo=1;
+       decals=1;
+       invertmouse=0;
+       bloodtoggle=0;
+       terraindetail=2;
+       foliage=1;
+       musictoggle=1;
+       trilinear=1;
+       gamespeed=1;
+       difficulty=1;
+       damageeffects=0;
+       texttoggle=1;
+       alwaysblur=0;
+       showpoints=0;
+       immediate=0;
+       velocityblur=0;
+
+       slomospeed=0.25;
+       slomofreq=8012;
+
+       volume = 0.8f;
+
+       game.crouchkey=MAC_SHIFT_KEY;
+       game.jumpkey=MAC_SPACE_KEY;
+       game.leftkey=MAC_A_KEY;
+       game.forwardkey=MAC_W_KEY;
+       game.backkey=MAC_S_KEY;
+       game.rightkey=MAC_D_KEY;
+       game.drawkey=MAC_E_KEY;
+       game.throwkey=MAC_Q_KEY;
+       game.attackkey=MAC_MOUSEBUTTON1;
+       game.chatkey=MAC_T_KEY;
+       numplayers=1;
+       ambientsound=1;
+       vblsync=0;
+       debugmode=0;
+
+       selectDetail(kContextWidth, kContextHeight, kBitsPerPixel, detail);
+
+       if(!ipstream) {
+               //ofstream opstream(":Data:config.txt"); 
+               ofstream opstream("./Data/config.txt"); 
+               opstream << "Screenwidth:\n";
+               opstream << kContextWidth;
+               opstream << "\nScreenheight:\n";
+               opstream << kContextHeight;
+               opstream << "\nMouse sensitivity:\n";
+               opstream << usermousesensitivity;
+               opstream << "\nBlur(0,1):\n";
+               opstream << ismotionblur;
+               opstream << "\nOverall Detail(0,1,2) higher=better:\n";
+               opstream << detail;
+               opstream << "\nFloating jump:\n";
+               opstream << floatjump;
+               opstream << "\nMouse jump:\n";
+               opstream << mousejump;
+               opstream << "\nAmbient sound:\n";
+               opstream << ambientsound;
+               opstream << "\nBlood (0,1,2):\n";
+               opstream << bloodtoggle;
+               opstream << "\nAuto slomo:\n";
+               opstream << autoslomo;
+               opstream << "\nFoliage:\n";
+               opstream << foliage;
+               opstream << "\nMusic:\n";
+               opstream << musictoggle;
+               opstream << "\nTrilinear:\n";
+               opstream << trilinear;
+               opstream << "\nDecals(shadows,blood puddles,etc):\n";
+               opstream << decals;
+               opstream << "\nInvert mouse:\n";
+               opstream << invertmouse;
+               opstream << "\nGamespeed:\n";
+               opstream << gamespeed;
+               opstream << "\nDifficulty(0,1,2) higher=harder:\n";
+               opstream << difficulty;
+               opstream << "\nDamage effects(blackout, doublevision):\n";
+               opstream << damageeffects;
+               opstream << "\nText:\n";
+               opstream << texttoggle;
+               opstream << "\nDebug:\n";
+               opstream << debugmode;
+               opstream << "\nVBL Sync:\n";
+               opstream << vblsync;
+               opstream << "\nShow Points:\n";
+               opstream << showpoints;
+               opstream << "\nAlways Blur:\n";
+               opstream << alwaysblur;
+               opstream << "\nImmediate mode (turn on on G5):\n";
+               opstream << immediate;
+               opstream << "\nVelocity blur:\n";
+               opstream << velocityblur;
+               opstream << "\nVolume:\n";
+               opstream << volume;
+               opstream << "\nForward key:\n";
+               opstream << KeyToChar(game.forwardkey);
+               opstream << "\nBack key:\n";
+               opstream << KeyToChar(game.backkey);
+               opstream << "\nLeft key:\n";
+               opstream << KeyToChar(game.leftkey);
+               opstream << "\nRight key:\n";
+               opstream << KeyToChar(game.rightkey);
+               opstream << "\nJump key:\n";
+               opstream << KeyToChar(game.jumpkey);
+               opstream << "\nCrouch key:\n";
+               opstream << KeyToChar(game.crouchkey);
+               opstream << "\nDraw key:\n";
+               opstream << KeyToChar(game.drawkey);
+               opstream << "\nThrow key:\n";
+               opstream << KeyToChar(game.throwkey);
+               opstream << "\nAttack key:\n";
+               opstream << KeyToChar(game.attackkey);
+               opstream << "\nChat key:\n";
+               opstream << KeyToChar(game.chatkey);
+               opstream.close();
+       }
+       if(ipstream){
+               int i;
+               ipstream.ignore(256,'\n');
+               ipstream >> kContextWidth;
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> kContextHeight;
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> usermousesensitivity;
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               ismotionblur = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> detail;
+               if(detail!=0)kBitsPerPixel=32;
+               else kBitsPerPixel=16;
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               floatjump = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               mousejump = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               ambientsound = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> bloodtoggle;
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               autoslomo = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               foliage = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               musictoggle = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               trilinear = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               decals = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               invertmouse = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> gamespeed;
+               oldgamespeed=gamespeed;
+               if(oldgamespeed==0){
+                       gamespeed=1;
+                       oldgamespeed=1;
+               }
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> difficulty;
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               damageeffects = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               texttoggle = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               debugmode = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               vblsync = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               showpoints = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               alwaysblur = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               immediate = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> i;
+               velocityblur = (i != 0);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n'); 
+               ipstream >> volume;
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n'); 
+               ipstream >> string;
+               game.forwardkey=CharToKey(string);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> string;
+               game.backkey=CharToKey(string);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> string;
+               game.leftkey=CharToKey(string);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> string;
+               game.rightkey=CharToKey(string);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> string;
+               game.jumpkey=CharToKey(string);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> string;
+               game.crouchkey=CharToKey(string);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> string;
+               game.drawkey=CharToKey(string);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> string;
+               game.throwkey=CharToKey(string);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> string;
+               game.attackkey=CharToKey(string);
+               ipstream.ignore(256,'\n');
+               ipstream.ignore(256,'\n');
+               ipstream >> string;
+               game.chatkey=CharToKey(string);
+               ipstream.close();
+
+               if(detail>2)detail=2;
+               if(detail<0)detail=0;
+               if(screenwidth>3000)screenwidth=640;
+               if(screenwidth<0)screenwidth=640;
+               if(screenheight>3000)screenheight=480;
+               if(screenheight<0)screenheight=480;
+       }
+       if(kBitsPerPixel!=32&&kBitsPerPixel!=16){
+               kBitsPerPixel=16;
+       }
+
+
+       selectDetail(kContextWidth, kContextHeight, kBitsPerPixel, detail);
+
+       SetupDSpFullScreen();
+
+       //------------------------------------------------------------------
+       // create window
+       int x = 0, y = 0;
+       RECT r = {0, 0, kContextWidth-1, kContextHeight-1};
+       DWORD dwStyle = WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE;
+       DWORD dwExStyle = WS_EX_APPWINDOW;
+
+       if (fullscreen)
+       {
+               dwStyle |= WS_POPUP;
+       }
+       else
+       {
+
+               dwStyle |= WS_OVERLAPPEDWINDOW;
+               dwExStyle |= WS_EX_WINDOWEDGE;
+       }
+
+       AdjustWindowRectEx(&r, dwStyle, FALSE, dwExStyle);
+
+       if (!fullscreen)
+       {
+               x = (GetSystemMetrics(SM_CXSCREEN) >> 1) - ((r.right - r.left + 1) >> 1);
+               y = (GetSystemMetrics(SM_CYSCREEN) >> 1) - ((r.bottom - r.top + 1) >> 1);
+       }
+
+       g_windowHandle=CreateWindowEx(
+               dwExStyle,
+               g_wndClassName, "Lugaru", dwStyle,
+               x, y,
+//             kContextWidth, kContextHeight,
+               r.right - r.left + 1, r.bottom - r.top + 1,
+               NULL,NULL,g_appInstance,NULL );
+       if (!g_windowHandle)
+       {
+               ReportError("Could not create window");
+               return false;
+       }
+
+
+       //------------------------------------------------------------------
+       // setup OpenGL
+
+       static PIXELFORMATDESCRIPTOR pfd =
+       {
+               sizeof(PIXELFORMATDESCRIPTOR),                          // Size Of This Pixel Format Descriptor
+                       1,                                                                                      // Version Number
+                       PFD_DRAW_TO_WINDOW |                                            // Format Must Support Window
+                       PFD_SUPPORT_OPENGL |                                            // Format Must Support OpenGL
+                       PFD_DOUBLEBUFFER,                                                       // Must Support Double Buffering
+                       PFD_TYPE_RGBA,                                                          // Request An RGBA Format
+                       kBitsPerPixel,                                                          // Select Our Color Depth
+                       0, 0, 0, 0, 0, 0,                                                       // Color Bits Ignored
+                       0,                                                                                      // No Alpha Buffer
+                       0,                                                                                      // Shift Bit Ignored
+                       0,                                                                                      // No Accumulation Buffer
+                       0, 0, 0, 0,                                                                     // Accumulation Bits Ignored
+                       16,                                                                                     // 16Bit Z-Buffer (Depth Buffer)  
+                       0,                                                                                      // No Stencil Buffer
+                       0,                                                                                      // No Auxiliary Buffer
+                       PFD_MAIN_PLANE,                                                         // Main Drawing Layer
+                       0,                                                                                      // Reserved
+                       0, 0, 0                                                                         // Layer Masks Ignored
+       };
+
+       if (!(hDC = GetDC( g_windowHandle)))
+               ReportError( "Could not get device context");
+
+       GLuint PixelFormat;
+       if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd)))
+       {
+               ReportError( "Could not find appropriate pixel format");
+               return false;
+       }
+
+       if (!DescribePixelFormat(hDC, PixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd))
+       {
+               ReportError( "Could not retrieve pixel format");
+               return false;
+       }
+
+       if (!SetPixelFormat( hDC, PixelFormat, &pfd))
+       {
+               ReportError( "Could not set pixel format");
+               return false;
+       }
+
+       if (!(hRC = wglCreateContext(hDC)))
+       {
+               ReportError( "Could not create rendering context");
+               return false;
+       }
+
+       if (!wglMakeCurrent(hDC, hRC))
+       {
+               ReportError( "Could not activate rendering context");
+               return false;
+       }
+
+       if (fullscreen)
+       {
+               // Place the window above all topmost windows
+               SetWindowPos( g_windowHandle, HWND_TOPMOST, 0,0,0,0,
+                       SWP_NOMOVE | SWP_NOSIZE );
+       }
+
+       SetForegroundWindow(g_windowHandle);
+       SetFocus(g_windowHandle);
+
+       glClear( GL_COLOR_BUFFER_BIT );
+       SwapBuffers( hDC );
+
+       // clear all states
+       glDisable( GL_ALPHA_TEST);
+       glDisable( GL_BLEND);
+       glDisable( GL_DEPTH_TEST);
+       //      glDisable( GL_DITHER);
+       glDisable( GL_FOG);
+       glDisable( GL_LIGHTING);
+       glDisable( GL_LOGIC_OP);
+       glDisable( GL_STENCIL_TEST);
+       glDisable( GL_TEXTURE_1D);
+       glDisable( GL_TEXTURE_2D);
+       glPixelTransferi( GL_MAP_COLOR, GL_FALSE);
+       glPixelTransferi( GL_RED_SCALE, 1);
+       glPixelTransferi( GL_RED_BIAS, 0);
+       glPixelTransferi( GL_GREEN_SCALE, 1);
+       glPixelTransferi( GL_GREEN_BIAS, 0);
+       glPixelTransferi( GL_BLUE_SCALE, 1);
+       glPixelTransferi( GL_BLUE_BIAS, 0);
+       glPixelTransferi( GL_ALPHA_SCALE, 1);
+       glPixelTransferi( GL_ALPHA_BIAS, 0);
+
+       // set initial rendering states
+       glShadeModel( GL_SMOOTH);
+       glClearDepth( 1.0f);
+       glDepthFunc( GL_LEQUAL);
+       glDepthMask( GL_TRUE);
+       //      glDepthRange( FRONT_CLIP, BACK_CLIP);
+       glEnable( GL_DEPTH_TEST);
+       glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
+       glCullFace( GL_FRONT);
+       glEnable( GL_CULL_FACE);
+       glEnable( GL_LIGHTING);
+//     glEnable( GL_LIGHT_MODEL_AMBIENT);
+       glEnable( GL_DITHER);
+       glEnable( GL_COLOR_MATERIAL);
+       glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+       glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+       glAlphaFunc( GL_GREATER, 0.5f);
+
+       if (ilGetInteger(IL_VERSION_NUM) < IL_VERSION ||
+               iluGetInteger(ILU_VERSION_NUM) < ILU_VERSION ||
+               ilutGetInteger(ILUT_VERSION_NUM) < ILUT_VERSION)
+       {
+               ReportError("DevIL version is different...exiting!\n");
+               return false;
+       }
+
+       ilInit();
+       iluInit();
+       ilutInit();
+
+       ilutRenderer(ILUT_OPENGL);
+
+       ilEnable(IL_ORIGIN_SET);
+       ilOriginFunc(IL_ORIGIN_LOWER_LEFT);
+
+       GLint width = kContextWidth;
+       GLint height = kContextHeight;
+       gMidPoint.h = width / 2;
+       gMidPoint.v = height / 2;
+       screenwidth=width;
+       screenheight=height;
+
+       game.newdetail=detail;
+       game.newscreenwidth=screenwidth;
+       game.newscreenheight=screenheight;
+
+       game.InitGame();
+
+       return true;
+}
+
+
+static void DoMouse(Game & game)
+{
+       static Point lastMouse = {-1,-1};
+       Point globalMouse;
+
+       POINT pos;
+       GetCursorPos(&pos);
+       ScreenToClient(g_windowHandle, &pos);
+       globalMouse.h = pos.x;
+       globalMouse.v = pos.y;
+
+       if (lastMouse.h == globalMouse.h && lastMouse.v == globalMouse.v)
+       {
+               game.deltah=0;
+               game.deltav=0;
+       }
+       else
+       {
+               static Point virtualMouse = {0,0};
+               delta = globalMouse;
+
+               delta.h -= lastMouse.h;
+               delta.v -= lastMouse.v;
+               lastMouse.h = pos.x;
+               lastMouse.v = pos.y;
+
+               if(mainmenu||(abs(delta.h)<10*realmultiplier*1000&&abs(delta.v)<10*realmultiplier*1000)){
+                       game.deltah=delta.h*usermousesensitivity;
+                       game.deltav=delta.v*usermousesensitivity;
+                       game.mousecoordh=globalMouse.h;
+                       game.mousecoordv=globalMouse.v;
+               }
+
+               if(!mainmenu)
+               {
+                       if(lastMouse.h>gMidPoint.h+100||lastMouse.h<gMidPoint.h-100||lastMouse.v>gMidPoint.v+100||lastMouse.v<gMidPoint.v-100){
+                               pos.x = gMidPoint.h;
+                               pos.y = gMidPoint.v;
+                               ClientToScreen(g_windowHandle, &pos);
+                               //SetCursorPos( gMidPoint.h,gMidPoint.v);
+                               SetCursorPos(pos.x, pos.y);
+                               lastMouse = gMidPoint;
+                       }
+               }
+       }
+}
+
+
+
+// --------------------------------------------------------------------------
+
+void DoKey (SInt8 theKey, SInt8 theCode)
+{
+       // do nothing
+}
+
+// --------------------------------------------------------------------------
+
+
+
+void DoFrameRate (int update)
+{      
+       static long frames = 0;
+
+       static AbsoluteTime time = {0,0};
+       static AbsoluteTime frametime = {0,0};
+       AbsoluteTime currTime = UpTime ();
+       double deltaTime = (float) AbsoluteDeltaToDuration (currTime, frametime);
+
+       if (0 > deltaTime)      // if negative microseconds
+               deltaTime /= -1000000.0;
+       else                            // else milliseconds
+               deltaTime /= 1000.0;
+
+       multiplier=deltaTime;
+       if(multiplier<.001)multiplier=.001;
+       if(multiplier>10)multiplier=10;
+       if(update)frametime = currTime; // reset for next time interval
+
+       deltaTime = (float) AbsoluteDeltaToDuration (currTime, time);
+
+       if (0 > deltaTime)      // if negative microseconds
+               deltaTime /= -1000000.0;
+       else                            // else milliseconds
+               deltaTime /= 1000.0;
+       frames++;
+       if (0.001 <= deltaTime) // has update interval passed
+       {
+               if(update){
+                       time = currTime;        // reset for next time interval
+                       frames = 0;
+               }
+       }
+}
+
+
+void DoUpdate (Game & game)
+{
+       static float sps=200;
+       static int count;
+       static float oldmult;
+
+       DoFrameRate(1);
+       if(multiplier>.6)multiplier=.6;
+
+       game.fps=1/multiplier;
+
+       count = multiplier*sps;
+       if(count<2)count=2;
+       //if(count>10)count=10;
+
+       realmultiplier=multiplier;
+       multiplier*=gamespeed;
+       if(difficulty==1)multiplier*=.9;
+       if(difficulty==0)multiplier*=.8;
+
+       if(game.loading==4)multiplier*=.00001;
+       //multiplier*.9;
+       if(slomo&&!mainmenu)multiplier*=slomospeed;
+       //if(freeze)multiplier*=0.00001;
+       oldmult=multiplier;
+       multiplier/=(float)count;
+
+       DoMouse(game);
+
+       game.TickOnce();
+
+       for(int i=0;i<count;i++)
+       {
+               game.Tick();
+       }
+       multiplier=oldmult;
+
+       game.TickOnceAfter();
+/* - Debug code to test how many channels were active on average per frame
+       static long frames = 0;
+
+       static AbsoluteTime start = {0,0};
+       AbsoluteTime currTime = UpTime ();
+       static int num_channels = 0;
+       
+       num_channels += FSOUND_GetChannelsPlaying();
+       double deltaTime = (float) AbsoluteDeltaToDuration (currTime, start);
+
+       if (0 > deltaTime)      // if negative microseconds
+               deltaTime /= -1000000.0;
+       else                            // else milliseconds
+               deltaTime /= 1000.0;
+
+       ++frames;
+
+       if (deltaTime >= 1)
+       {
+               start = currTime;
+               float avg_channels = (float)num_channels / (float)frames;
+
+               ofstream opstream("log.txt",ios::app); 
+               opstream << "Average frame count: ";
+               opstream << frames;
+               opstream << " frames - ";
+               opstream << avg_channels;
+               opstream << " per frame.\n";
+               opstream.close();
+
+               frames = 0;
+               num_channels = 0;
+       }
+*/
+       DrawGL (game);
+}
+
+// --------------------------------------------------------------------------
+
+
+void CleanUp (void)
+{
+       LOGFUNC;
+
+//     game.Dispose();
+
+       ilShutDown();
+
+       if (hRC)
+       {
+               wglMakeCurrent( NULL, NULL);
+               wglDeleteContext( hRC);
+               hRC = NULL;
+       }
+
+       if (hDC)
+       {
+               ReleaseDC( g_windowHandle, hDC);
+               hDC = NULL;
+       }
+
+       if (g_windowHandle)
+       {
+               ShowWindow( g_windowHandle, SW_HIDE );
+               DestroyWindow( g_windowHandle);
+               g_windowHandle = NULL;
+       }
+
+       ShutdownDSp ();
+       ClipCursor(NULL);
+}
+
+// --------------------------------------------------------------------------
+
+static bool g_focused = true;
+
+
+static bool IsFocused()
+{
+       if (!g_focused)
+               return false;
+
+       if (GetActiveWindow() != g_windowHandle)
+               return false;
+
+       if (IsIconic( g_windowHandle))
+               return false;
+
+       return true;
+}
+
+
+int main (void)
+{
+       LOGFUNC;
+
+       try
+       {
+               bool regnow = false;
+               {
+                       Game game;
+                       pgame = &game;
+
+                       //ofstream os("error.txt");
+                       //os.close();
+                       //ofstream os("log.txt");
+                       //os.close();
+
+                       SetUp (game);
+
+                       while (!gDone&&!game.quit&&(!game.tryquit||!game.registered))
+                       {
+                               if (IsFocused())
+                               {
+                                       gameFocused = true;
+
+                                       // check windows messages
+                                       MSG msg;
+                                       // message pump
+                                       while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD ) )
+                                       {
+                                               if( msg.message == WM_QUIT )
+                                               {
+                                                       gDone=true;
+                                                       break;
+                                               }
+                                               else
+                                               {
+                                                       TranslateMessage( &msg );
+                                                       DispatchMessage( &msg );
+                                               }
+                                       }
+
+                                       // game
+                                       DoUpdate(game);
+                               }
+                               else
+                               {
+                                       if (gameFocused)
+                                       {
+                                               // allow game chance to pause
+                                               gameFocused = false;
+                                               DoUpdate(game);
+                                       }
+
+                                       // game is not in focus, give CPU time to other apps by waiting for messages instead of 'peeking'
+                                       MSG msg;
+                                       BOOL bRet;
+                                       //if (GetMessage( &msg, g_windowHandle, 0, 0 ))
+                                       /*if (GetMessage( &msg, NULL, 0, 0 ))
+                                       {
+                                               TranslateMessage(&msg);
+                                               DispatchMessage(&msg);
+                                       }*/
+                                       if ( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
+                                       { 
+                                               if (bRet <= 0)
+                                               {
+                                                       // handle the error and possibly exit
+                                                       gDone=true;
+                                               }
+                                               else
+                                               {
+                                                       TranslateMessage(&msg); 
+                                                       DispatchMessage(&msg); 
+                                               }
+                                       }
+                               }
+                       }
+
+                       regnow = game.registernow;
+               }
+               pgame = 0;
+
+               CleanUp ();
+//             if(game.registernow){
+               if(regnow)
+               {
+                       char url[100];
+                       sprintf(url,"http://www.wolfire.com/registerpc.html");
+                       //                      LaunchURL(url);
+                       ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
+               }
+               return 0;
+       }
+       catch (const std::exception& error)
+       {
+               CleanUp();
+
+               std::string e = "Caught exception: ";
+               e += error.what();
+
+               LOG(e, Logger::LOG_ERR);
+
+               MessageBox(g_windowHandle, error.what(), "ERROR", MB_OK | MB_ICONEXCLAMATION);
+       }
+
+       CleanUp();
+
+       return -1;
+}
+
+
+
+       // --------------------------------------------------------------------------
+
+
+#define MAX_WINKEYS 256
+       static unsigned short KeyTable[MAX_WINKEYS]=
+       {
+               0xffff,  // (0)
+                       MAC_MOUSEBUTTON1,  // VK_LBUTTON        (1)
+                       MAC_MOUSEBUTTON2,  // VK_RBUTTON        (2)
+                       0xffff,  // VK_CANCEL   (3)
+                       0xffff,  // VK_MBUTTON  (4)
+                       0xffff,  // (5)
+                       0xffff,  // (6)
+                       0xffff,  // (7)
+                       MAC_DELETE_KEY,  // VK_BACK     (8)
+                       MAC_TAB_KEY,  // VK_TAB (9)
+                       0xffff,  // (10)
+                       0xffff,  // (11)
+                       0xffff,  // VK_CLEAR    (12)
+                       MAC_RETURN_KEY,  // VK_RETURN   (13)
+                       0xffff,  // (14)
+                       0xffff,  // (15)
+                       MAC_SHIFT_KEY,  // VK_SHIFT     (16)
+                       MAC_CONTROL_KEY,  // VK_CONTROL (17)
+                       MAC_OPTION_KEY,  // VK_MENU     (18)
+                       0xffff,  // VK_PAUSE    (19)
+                       MAC_CAPS_LOCK_KEY,  // #define VK_CAPITAL       (20)
+                       0xffff,  // (21)
+                       0xffff,  // (22)
+                       0xffff,  // (23)
+                       0xffff,  // (24)
+                       0xffff,  // (25)
+                       0xffff,  // (26)
+                       MAC_ESCAPE_KEY,  // VK_ESCAPE   (27)
+                       0xffff,  // (28)
+                       0xffff,  // (29)
+                       0xffff,  // (30)
+                       0xffff,  // (31)
+                       MAC_SPACE_KEY,  // VK_SPACE     (32)
+                       MAC_PAGE_UP_KEY,  // VK_PRIOR   (33)
+                       MAC_PAGE_DOWN_KEY,  // VK_NEXT  (34)
+                       MAC_END_KEY,  // VK_END (35)
+                       MAC_HOME_KEY,  // VK_HOME       (36)
+                       MAC_ARROW_LEFT_KEY,  // VK_LEFT (37)
+                       MAC_ARROW_UP_KEY,  // VK_UP     (38)
+                       MAC_ARROW_RIGHT_KEY,  // VK_RIGHT       (39)
+                       MAC_ARROW_DOWN_KEY,  // VK_DOWN (40)
+                       0xffff,  // VK_SELECT   (41)
+                       0xffff,  // VK_PRINT    (42)
+                       0xffff,  // VK_EXECUTE  (43)
+                       0xffff,  // VK_SNAPSHOT (44)
+                       MAC_INSERT_KEY,  // VK_INSERT   (45)
+                       MAC_DEL_KEY,  // VK_DELETE      (46)
+                       0xffff,  // VK_HELP     (47)
+                       MAC_0_KEY,  // VK_0     (48)
+                       MAC_1_KEY,  // VK_1     (49)
+                       MAC_2_KEY,  // VK_2     (50)
+                       MAC_3_KEY,  // VK_3     (51)
+                       MAC_4_KEY,  // VK_4     (52)
+                       MAC_5_KEY,  // VK_5     (53)
+                       MAC_6_KEY,  // VK_6     (54)
+                       MAC_7_KEY,  // VK_7     (55)
+                       MAC_8_KEY,  // VK_8     (56)
+                       MAC_9_KEY,  // VK_9     (57)
+                       0xffff,  // (58)
+                       0xffff,  // (59)
+                       0xffff,  // (60)
+                       0xffff,  // (61)
+                       0xffff,  // (62)
+                       0xffff,  // (63)
+                       0xffff,  // (64)
+                       MAC_A_KEY,  // VK_A     (65)
+                       MAC_B_KEY,  // VK_B     (66)
+                       MAC_C_KEY,  // VK_C     (67)
+                       MAC_D_KEY,  // VK_D     (68)
+                       MAC_E_KEY,  // VK_E     (69)
+                       MAC_F_KEY,  // VK_F     (70)
+                       MAC_G_KEY,  // VK_G     (71)
+                       MAC_H_KEY,  // VK_H     (72)
+                       MAC_I_KEY,  // VK_I     (73)
+                       MAC_J_KEY,  // VK_J     (74)
+                       MAC_K_KEY,  // VK_K     (75)
+                       MAC_L_KEY,  // VK_L     (76)
+                       MAC_M_KEY,  // VK_M     (77)
+                       MAC_N_KEY,  // VK_N     (78)
+                       MAC_O_KEY,  // VK_O     (79)
+                       MAC_P_KEY,  // VK_P     (80)
+                       MAC_Q_KEY,  // VK_Q     (81)
+                       MAC_R_KEY,  // VK_R     (82)
+                       MAC_S_KEY,  // VK_S     (83)
+                       MAC_T_KEY,  // VK_T     (84)
+                       MAC_U_KEY,  // VK_U     (85)
+                       MAC_V_KEY,  // VK_V     (86)
+                       MAC_W_KEY,  // VK_W     (87)
+                       MAC_X_KEY,  // VK_X     (88)
+                       MAC_Y_KEY,  // VK_Y     (89)
+                       MAC_Z_KEY,  // VK_Z     (90)
+                       0xffff,  // (91)
+                       0xffff,  // (92)
+                       0xffff,  // (93)
+                       0xffff,  // (94)
+                       0xffff,  // (95)
+                       MAC_NUMPAD_0_KEY,  // VK_NUMPAD0        (96)
+                       MAC_NUMPAD_1_KEY,  // VK_NUMPAD1        (97)
+                       MAC_NUMPAD_2_KEY,  // VK_NUMPAD2        (98)
+                       MAC_NUMPAD_3_KEY,  // VK_NUMPAD3        (99)
+                       MAC_NUMPAD_4_KEY,  // VK_NUMPAD4        (100)
+                       MAC_NUMPAD_5_KEY,  // VK_NUMPAD5        (101)
+                       MAC_NUMPAD_6_KEY,  // VK_NUMPAD6        (102)
+                       MAC_NUMPAD_7_KEY,  // VK_NUMPAD7        (103)
+                       MAC_NUMPAD_8_KEY,  // VK_NUMPAD8        (104)
+                       MAC_NUMPAD_9_KEY,  // VK_NUMPAD9        (105)
+                       MAC_NUMPAD_ASTERISK_KEY,  // VK_MULTIPLY        (106)
+                       MAC_NUMPAD_PLUS_KEY,  // VK_ADD (107)
+                       MAC_NUMPAD_ENTER_KEY,  // VK_SEPARATOR  (108)
+                       MAC_NUMPAD_MINUS_KEY,  // VK_SUBTRACT   (109)
+                       MAC_NUMPAD_PERIOD_KEY,  // VK_DECIMAL   (110)
+                       MAC_NUMPAD_SLASH_KEY,  // VK_DIVIDE     (111)
+                       MAC_F1_KEY,  // VK_F1   (112)
+                       MAC_F2_KEY,  // VK_F2   (113)
+                       MAC_F3_KEY,  // VK_F3   (114)
+                       MAC_F4_KEY,  // VK_F4   (115)
+                       MAC_F5_KEY,  // VK_F5   (116)
+                       MAC_F6_KEY,  // VK_F6   (117)
+                       MAC_F7_KEY,  // VK_F7   (118)
+                       MAC_F8_KEY,  // VK_F8   (119)
+                       MAC_F9_KEY,  // VK_F9   (120)
+                       MAC_F10_KEY,  // VK_F10 (121)
+                       MAC_F11_KEY,  // VK_F11 (122)
+                       MAC_F12_KEY,  // VK_F12 (123)
+                       0xffff,  // (124)
+                       0xffff,  // (125)
+                       0xffff,  // (126)
+                       0xffff,  // (127)
+                       0xffff,  // (128)
+                       0xffff,  // (129)
+                       0xffff,  // (130)
+                       0xffff,  // (131)
+                       0xffff,  // (132)
+                       0xffff,  // (133)
+                       0xffff,  // (134)
+                       0xffff,  // (135)
+                       0xffff,  // (136)
+                       0xffff,  // (137)
+                       0xffff,  // (138)
+                       0xffff,  // (139)
+                       0xffff,  // (130)
+                       0xffff,  // (141)
+                       0xffff,  // (142)
+                       0xffff,  // (143)
+                       0xffff,  // VK_NUMLOCK  (144)
+                       0xffff,  // VK_SCROLL   (145)
+                       0xffff,  // (146)
+                       0xffff,  // (147)
+                       0xffff,  // (148)
+                       0xffff,  // (149)
+                       0xffff,  // (150)
+                       0xffff,  // (151)
+                       0xffff,  // (152)
+                       0xffff,  // (153)
+                       0xffff,  // (154)
+                       0xffff,  // (155)
+                       0xffff,  // (156)
+                       0xffff,  // (157)
+                       0xffff,  // (158)
+                       0xffff,  // (159)
+                       MAC_SHIFT_KEY,  // VK_LSHIFT    (160)
+                       MAC_SHIFT_KEY,  // VK_RSHIFT    (161)
+                       MAC_CONTROL_KEY,  // VK_LCONTROL        (162)
+                       MAC_CONTROL_KEY,  // VK_RCONTROL        (163)
+                       MAC_OPTION_KEY,  // VK_LMENU    (164)
+                       MAC_OPTION_KEY,  // VK_RMENU    (165)
+                       0xffff,  // (166)
+                       0xffff,  // (167)
+                       0xffff,  // (168)
+                       0xffff,  // (169)
+                       0xffff,  // (170)
+                       0xffff,  // (171)
+                       0xffff,  // (172)
+                       0xffff,  // (173)
+                       0xffff,  // (174)
+                       0xffff,  // (175)
+                       0xffff,  // (176)
+                       0xffff,  // (177)
+                       0xffff,  // (178)
+                       0xffff,  // (179)
+                       0xffff,  // (180)
+                       0xffff,  // (181)
+                       0xffff,  // (182)
+                       0xffff,  // (183)
+                       0xffff,  // (184)
+                       0xffff,  // (185)
+                       MAC_SEMICOLON_KEY,  // (186)
+                       MAC_PLUS_KEY,  // (187)
+                       MAC_COMMA_KEY,  // (188)
+                       MAC_MINUS_KEY,  // (189)
+                       MAC_PERIOD_KEY,  // (190)
+                       MAC_SLASH_KEY,  // (191)
+                       MAC_TILDE_KEY,  // (192)
+                       0xffff,  // (193)
+                       0xffff,  // (194)
+                       0xffff,  // (195)
+                       0xffff,  // (196)
+                       0xffff,  // (197)
+                       0xffff,  // (198)
+                       0xffff,  // (199)
+                       0xffff,  // (200)
+                       0xffff,  // (201)
+                       0xffff,  // (202)
+                       0xffff,  // (203)
+                       0xffff,  // (204)
+                       0xffff,  // (205)
+                       0xffff,  // (206)
+                       0xffff,  // (207)
+                       0xffff,  // (208)
+                       0xffff,  // (209)
+                       0xffff,  // (210)
+                       0xffff,  // (211)
+                       0xffff,  // (212)
+                       0xffff,  // (213)
+                       0xffff,  // (214)
+                       0xffff,  // (215)
+                       0xffff,  // (216)
+                       0xffff,  // (217)
+                       0xffff,  // (218)
+                       MAC_LEFTBRACKET_KEY,  // (219)
+                       MAC_BACKSLASH_KEY,  // (220)
+                       MAC_RIGHTBRACKET_KEY,  // (221)
+                       MAC_APOSTROPHE_KEY,  // (222)
+                       0xffff,  // (223)
+                       0xffff,  // (224)
+                       0xffff,  // (225)
+                       0xffff,  // (226)
+                       0xffff,  // (227)
+                       0xffff,  // (228)
+                       0xffff,  // (229)
+                       0xffff,  // (230)
+                       0xffff,  // (231)
+                       0xffff,  // (232)
+                       0xffff,  // (233)
+                       0xffff,  // (234)
+                       0xffff,  // (235)
+                       0xffff,  // (236)
+                       0xffff,  // (237)
+                       0xffff,  // (238)
+                       0xffff,  // (239)
+                       0xffff,  // (240)
+                       0xffff,  // (241)
+                       0xffff,  // (242)
+                       0xffff,  // (243)
+                       0xffff,  // (244)
+                       0xffff,  // (245)
+                       0xffff,  // (246)
+                       0xffff,  // (247)
+                       0xffff,  // (248)
+                       0xffff,  // (249)
+                       0xffff,  // (250)
+                       0xffff,  // (251)
+                       0xffff,  // (252)
+                       0xffff,  // (253)
+                       0xffff,  // (254)
+                       0xffff,  // (255)
+       };
+
+
+       static KeyMap g_theKeys;
+
+       void SetKey( int key)
+       {
+               g_theKeys[ key >> 3] |= (1 << (key & 7));
+       }
+
+       void ClearKey( int key)
+       {
+               g_theKeys[ key >> 3] &= (0xff ^ (1 << (key & 7)));
+       }
+
+       void GetKeys(  unsigned char theKeys[16])
+       {
+               memcpy( theKeys, &g_theKeys, 16);
+       }
+
+       Boolean Button()
+       {
+               return g_button;
+       }
+
+
+       void ClipMouseToWindow(HWND window)
+       {
+               RECT wRect;
+
+               GetClientRect(window, &wRect);
+
+               ClientToScreen(window, (LPPOINT)&wRect.left);
+               ClientToScreen(window, (LPPOINT)&wRect.right);
+
+               ClipCursor(&wRect);
+
+               return;
+       }
+
+       LRESULT FAR PASCAL AppWndProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
+       {
+               /* this is where we receive all messages concerning this window
+               * we can either process a message or pass it on to the default
+               * message handler of windows */
+
+               static PAINTSTRUCT ps;
+
+               switch(msg)
+               {
+               case WM_ACTIVATE:       // Watch For Window Activate Message
+                       {
+                               // Check Minimization State
+                               BOOL iconified = HIWORD(wParam) ? TRUE : FALSE;
+
+                               if (LOWORD(wParam) == WA_INACTIVE)
+                               {
+                                       ClipCursor(NULL);
+
+                                       if (fullscreen)
+                                       {
+                                               if( !iconified )
+                                               {
+                                                       // Minimize window
+                                                       CloseWindow( hWnd );
+
+                                                       // The window is now iconified
+                                                       iconified = GL_TRUE;
+                                               }
+                                       }
+
+                                       ShutdownDSp();
+
+                                       g_focused=false;                                // Program Is Active
+                               }
+                               else
+                               {
+                                       SetupDSpFullScreen();
+
+                                       if( iconified )
+                                       {
+                                               // Minimize window
+                                               OpenIcon( hWnd );
+
+                                               // The window is now iconified
+                                               iconified = GL_FALSE;
+
+                                               // Activate window
+                                               ShowWindow( hWnd, SW_SHOW );
+                                               SetForegroundWindow( hWnd );
+                                               SetFocus( hWnd );
+                                       }
+
+                                       ClipMouseToWindow(hWnd);
+                                       g_focused=true;                 // Program Is No Longer Active
+                               }
+
+                               return 0;                                               // Return To The Message Loop
+                       }
+
+               case WM_KEYDOWN:
+               case WM_SYSKEYDOWN:
+                       {
+                               // check for Alt-F4 (exit hotkey)
+                               if (wParam == VK_F4)
+                               {
+                                       if (GetKeyState( VK_MENU) & 0x8080)
+                                       {
+                                               gDone = true;
+                                               break;
+                                       }
+                               }
+                               if (wParam < MAX_WINKEYS)
+                               {
+                                       if (KeyTable[wParam] != 0xffff)
+                                               SetKey( KeyTable[wParam]);
+                               }
+                               return (0);
+                       }
+
+               case WM_KEYUP:
+               case WM_SYSKEYUP:
+                       {
+                               if (wParam < MAX_WINKEYS)
+                                       if (KeyTable[wParam] != 0xffff)
+                                               ClearKey( KeyTable[wParam]);
+                               return (0);
+                       }
+
+               case WM_CHAR:
+               case WM_DEADCHAR:
+               case WM_SYSCHAR:
+               case WM_SYSDEADCHAR:
+                       return (0);
+
+               case WM_NCLBUTTONDOWN:
+               case WM_LBUTTONDOWN:
+                       {
+                               g_button = true;
+                               buttons[ 0] = true;
+                       }
+                       return (0);
+
+               case WM_NCRBUTTONDOWN:
+               case WM_RBUTTONDOWN:
+                       {
+                               buttons[ 1] = true;
+                       }
+                       return (0);
+
+               case WM_NCMBUTTONDOWN:
+               case WM_MBUTTONDOWN:
+                       {
+                               buttons[ 2] = true;
+                       }
+                       return (0);
+
+               case WM_NCLBUTTONUP:
+               case WM_LBUTTONUP:
+                       {
+                               g_button = false;
+                               buttons[ 0] = false;
+                       }
+                       return (0);
+
+               case WM_NCRBUTTONUP:
+               case WM_RBUTTONUP:
+                       {
+                               buttons[ 1] = false;
+                       }
+                       return (0);
+
+               case WM_NCMBUTTONUP:
+               case WM_MBUTTONUP:
+                       {
+                               buttons[ 2] = false;
+                       }
+                       return (0);
+
+               case WM_NCLBUTTONDBLCLK:
+               case WM_NCRBUTTONDBLCLK:
+               case WM_NCMBUTTONDBLCLK:
+               case WM_LBUTTONDBLCLK:
+                       return (0);
+               case WM_RBUTTONDBLCLK:
+               case WM_MBUTTONDBLCLK:
+                       return (0);
+
+               case WM_NCMOUSEMOVE:
+               case WM_MOUSEMOVE:
+                       /*                      ((WindowInfo *)g_lastWindow->GetInfo())->m_mouseX = (signed short)(lParam & 0xffff);
+                       ((WindowInfo *)g_lastWindow->GetInfo())->m_mouseY = (signed short)(lParam >> 16);
+                       if (g_lastWindow->m_mouseCallbacksEnabled) g_lastWindow->MouseMoveCallback();
+                       *///                    goto winmessage;
+                       return (0);
+
+               case WM_SYSCOMMAND:                                             // Intercept System Commands
+                       {
+                               switch (wParam)                                         // Check System Calls
+                               {
+                               case SC_SCREENSAVE:                             // Screensaver Trying To Start?
+                               case SC_MONITORPOWER:                   // Monitor Trying To Enter Powersave?
+                                       return 0;                                       // Prevent From Happening
+
+                                       // User trying to access application menu using ALT?
+                               case SC_KEYMENU:
+                                       return 0;
+                               }
+                       }
+                       break;
+
+               case WM_MOVE:
+//                     {
+//                             ReleaseCapture();
+//                             ClipMouseToWindow(hWnd);
+//                     }
+                       break;
+
+               case WM_SIZE:
+                       break;
+
+               case WM_CLOSE:
+                       {
+                               //gDone =  true;
+                               //game.tryquit=1;
+                       }
+                       //return (0);
+
+               case WM_DESTROY:
+                       {
+                               //ClipCursor(NULL);
+                               PostQuitMessage(0);  /* Terminate Application */
+                       }
+                       return (0);
+
+               case WM_ERASEBKGND:
+                       break;
+
+               case WM_PAINT:
+//                     BeginPaint( g_windowHandle,&ps);
+//                     EndPaint( g_windowHandle,&ps);
+                       break;
+
+               default:
+                       break;
+               }
+
+               /* We processed the message and there
+               * is no processing by Windows necessary */
+
+               /* We didn't process the message so let Windows do it */
+               return DefWindowProc(hWnd,msg,wParam,lParam);
+       }
+
+
+       static BOOL RegisterWindowClasses(HINSTANCE hFirstInstance)
+       {
+               WNDCLASSEX wc;
+               memset( &wc, 0, sizeof( wc));
+
+               /* Register the window class. */
+               wc.cbSize = sizeof(wc);
+#undef style
+               wc.style = (CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW | CS_OWNDC);  /* Combination of Class Styles */
+               wc.lpfnWndProc = AppWndProc;       /* Adress of Window Procedure */
+               wc.cbClsExtra = 0;                 /* Extra Bytes allocated for this Class */
+               wc.cbWndExtra = 0;                 /* Extra Bytes allocated for each Window */
+               wc.hInstance = hFirstInstance;     /* Handle of program instance */
+               wc.hIcon = LoadIcon( hFirstInstance, MAKEINTRESOURCE(IDI_LUGARU) );
+               wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+               wc.hbrBackground = NULL;
+               wc.lpszMenuName  = NULL;
+               wc.lpszClassName = g_wndClassName; /* Name of the Window Class */
+               wc.hIconSm = LoadIcon( hFirstInstance, MAKEINTRESOURCE(IDI_LUGARU) );
+
+               if (!RegisterClassEx(&wc)) return FALSE;  /* Register Class failed */
+
+               return TRUE;
+       }
+
+       int resolutionID(int width, int height)
+       {
+               int whichres;
+               whichres=-1;
+               if(width==640 && height==480)whichres=0;
+               if(width==800 && height==600)whichres=1;
+               if(width==1024 && height==768)whichres=2;
+               if(width==1280 && height==1024)whichres=3;
+               if(width==1600 && height==1200)whichres=4;
+               if(width==840 && height==524)whichres=5;
+               if(width==1024 && height==640)whichres=6;
+               if(width==1344 && height==840)whichres=7;
+
+               return whichres;
+       }
+
+       int closestResolution(int width, int height)
+       {
+               int whichres;
+               whichres=-1;
+               if(width>=640 && height>=480)whichres=0;
+               if(width>=800 && height>=600)whichres=1;
+               if(width>=1024 && height>=768)whichres=2;
+               if(width>=1280 && height>=1024)whichres=3;
+               if(width>=1600 && height>=1200)whichres=4;
+               if(width==840 && height==524)whichres=5;
+               if(width==1024 && height==640)whichres=6;
+               if(width==1344 && height==840)whichres=7;
+
+               return whichres;
+       }
+
+       bool selectDetail(int & width, int & height, int & bpp, int & detail)
+       {
+               bool res = true;
+               int whichres = closestResolution(width, height);
+
+               while (true)
+               {
+                       if(whichres<=0 || whichres>7){
+                               whichres = 0;
+                               width=640;
+                               height=480;
+                       }
+                       if(whichres==1){
+                               width=800;
+                               height=600;
+                       }
+                       if(whichres==2){
+                               width=1024;
+                               height=768;
+                       }
+                       if(whichres==3){
+                               width=1280;
+                               height=1024;
+                       }
+                       if(whichres==4){
+                               width=1600;
+                               height=1200;
+                       }
+                       if(whichres==5){
+                               width=840;
+                               height=524;
+                       }
+                       if(whichres==6){
+                               width=1024;
+                               height=640;
+                       }
+                       if(whichres==7){
+                               width=1344;
+                               height=840;
+                       }
+
+                       if ((detail != 0) && (resolutionDepths[whichres][1] != 0))
+                       {
+                               break;
+                       }
+                       else if ((detail == 0) && (resolutionDepths[whichres][0] != 0))
+                       {
+                               break;
+                       }
+                       else if ((detail != 0) && (resolutionDepths[whichres][0] != 0))
+                       {
+                               res = false;
+                               detail = 0;
+                               break;
+                       }
+                       else if (0 == whichres)
+                       {
+                               break;
+                       }
+
+                       --whichres;
+               }
+
+               bpp = resolutionDepths[whichres][(detail != 0)];
+
+               return res;
+       }
+
+       int __stdcall WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
+       {
+               int argc = 0;
+               LPWSTR * cl = CommandLineToArgvW(GetCommandLineW(), &argc);
+               if (argc > 1)
+               {
+                       if (0 == _wcsicmp(cl[1], L"-windowed"))
+                       {
+                               fullscreen = false;
+                       }
+               }
+
+               logger.start(true);
+
+               memset( &g_theKeys, 0, sizeof( KeyMap));
+
+               unsigned int i = 0;
+               DEVMODE mode;
+               memset(&mode, 0, sizeof(mode));
+               mode.dmSize = sizeof(mode);
+               while (EnumDisplaySettings(NULL, i++, &mode))
+               {
+                       if (mode.dmBitsPerPel < 16)
+                       {
+                               continue;
+                       }
+
+                       int res = resolutionID(mode.dmPelsWidth, mode.dmPelsHeight);
+
+                       if (res > -1 && res < 8)
+                       {
+                               if (DISP_CHANGE_SUCCESSFUL != ChangeDisplaySettings(&mode, CDS_TEST))
+                               {
+                                       continue;
+                               }
+
+                               switch(mode.dmBitsPerPel)
+                               {
+                               case 32:
+                               case 24:
+                                       resolutionDepths[res][1] = mode.dmBitsPerPel;
+                                       break;
+                               case 16:
+                                       resolutionDepths[res][0] = mode.dmBitsPerPel;
+                                       break;
+                               }
+                       }
+               }
+
+               /* if there is no Instance of our program in memory then register the window class */
+               if (hPrevInstance == NULL && !RegisterWindowClasses(hInstance))
+                       return FALSE;  /* registration failed! */
+
+               g_appInstance=hInstance;
+
+               main();
+
+               UnregisterClass( g_wndClassName, hInstance);
+
+               return TRUE;
+
+       }
+
+       extern int channels[100];
+       extern FSOUND_SAMPLE * samp[100];
+       extern FSOUND_STREAM * strm[10];
+
+       extern "C" void PlaySoundEx(int chan, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused)
+       {
+               const FSOUND_SAMPLE * currSample = FSOUND_GetCurrentSample(channels[chan]);
+               if (currSample && currSample == samp[chan])
+               {
+                       if (FSOUND_GetPaused(channels[chan]))
+                       {
+                               FSOUND_StopSound(channels[chan]);
+                               channels[chan] = FSOUND_FREE;
+                       }
+                       else if (FSOUND_IsPlaying(channels[chan]))
+                       {
+                               int loop_mode = FSOUND_GetLoopMode(channels[chan]);
+                               if (loop_mode & FSOUND_LOOP_OFF)
+                               {
+                                       channels[chan] = FSOUND_FREE;
+                               }
+                       }
+               }
+               else
+               {
+                       channels[chan] = FSOUND_FREE;
+               }
+
+               channels[chan] = FSOUND_PlaySoundEx(channels[chan], sptr, dsp, startpaused);
+               if (channels[chan] < 0)
+               {
+                       channels[chan] = FSOUND_PlaySoundEx(FSOUND_FREE, sptr, dsp, startpaused);
+               }
+       }
+
+       extern "C" void PlayStreamEx(int chan, FSOUND_STREAM *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused)
+       {
+               const FSOUND_SAMPLE * currSample = FSOUND_GetCurrentSample(channels[chan]);
+               if (currSample && currSample == FSOUND_Stream_GetSample(sptr))
+               {
+                               FSOUND_StopSound(channels[chan]);
+                               FSOUND_Stream_Stop(sptr);
+               }
+               else
+               {
+                       FSOUND_Stream_Stop(sptr);
+                       channels[chan] = FSOUND_FREE;
+               }
+
+               channels[chan] = FSOUND_Stream_PlayEx(channels[chan], sptr, dsp, startpaused);
+               if (channels[chan] < 0)
+               {
+                       channels[chan] = FSOUND_Stream_PlayEx(FSOUND_FREE, sptr, dsp, startpaused);
+               }
+       }
+
+       bool LoadImage(const char * fname, TGAImageRec & tex)
+       {
+               bool res = true;
+
+               if ( tex.data == NULL )
+               {
+                       return false;
+               }
+
+               ILstring f = strdup(ConvertFileName(fname));
+               if (!f)
+               {
+                       return false;
+               }
+
+               ILuint iid=0;
+               ilGenImages(1, &iid);
+               ilBindImage(iid);
+               if (ilLoadImage(f))
+               {
+                       //iluFlipImage();
+                       tex.sizeX = ilGetInteger(IL_IMAGE_WIDTH);
+                       tex.sizeY = ilGetInteger(IL_IMAGE_HEIGHT);
+                       tex.bpp = ilGetInteger(IL_IMAGE_BITS_PER_PIXEL);
+                       ILuint Bpp = ilGetInteger(IL_IMAGE_BYTES_PER_PIXEL),
+                               imageSize = tex.sizeX * tex.sizeY * Bpp;
+                       ILubyte *Data = ilGetData();
+                       memcpy(tex.data, Data, imageSize);
+
+                       // Truvision Targa files are stored as BGR colors
+                       // We want RGB so Blue and Red bytes are switched
+                       if (IL_TGA == ilGetInteger(IL_IMAGE_FORMAT))
+                       {
+                               // Loop Through The Image Data
+                               for (GLuint i = 0; i < int(imageSize); i += Bpp)
+                               {
+                                       // Swaps The 1st And 3rd Bytes ('R'ed and 'B'lue)
+                                       GLbyte temp;                                            // Temporary Variable
+                                       temp = tex.data[i];                                     // Temporarily Store The Value At Image Data 'i'
+                                       tex.data[i] = tex.data[i + 2];          // Set The 1st Byte To The Value Of The 3rd Byte
+                                       tex.data[i + 2] = temp;                         // Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
+                               }
+                       }
+               }
+               else
+               {
+                       res = false;
+               }
+               ilDeleteImages(1, &iid);
+/*
+               if (tid)
+               {
+                       GLuint texid = ilutGLLoadImage(f);
+                       *tid = texid;
+               }
+               else if (mip)
+               {
+                       ilutGLBuildMipmaps()
+               }
+               else
+               {
+                       ilutGLTexImage(0);
+               }
+*/
+               free(f);
+
+               return res;
+       }
+
+       void ScreenShot(const char * fname)
+       {
+               ILstring f = strdup(fname);
+               if (!f)
+               {
+                       return;
+               }
+
+               ILuint iid;
+               ilGenImages(1, &iid);
+               ilBindImage(iid);
+               if (ilutGLScreen())
+               {
+                       ilSaveImage(f);
+               }
+               ilDeleteImages(1, &iid);
+
+               free(f);
+       }
diff --git a/Source/Person.cpp b/Source/Person.cpp
new file mode 100644 (file)
index 0000000..fd63f7b
--- /dev/null
@@ -0,0 +1,7983 @@
+/**> HEADER FILES <**/
+#include "Person.h"
+
+extern float multiplier;
+extern Animation animation[animation_count];
+extern FSOUND_SAMPLE   *samp[100];
+extern int channels[100];
+extern Terrain terrain;
+extern float gravity;
+extern int environment;
+extern Sprites sprites;
+extern int detail;
+extern FRUSTUM frustum;
+extern XYZ viewer;
+extern float realmultiplier;
+extern int slomo;
+extern float slomodelay;
+extern bool cellophane;
+extern float texdetail;
+extern float realtexdetail;
+extern GLubyte bloodText[512*512*3];
+extern GLubyte wolfbloodText[512*512*3];
+extern int bloodtoggle;
+extern Objects objects;
+extern bool osx;
+extern bool autoslomo;
+extern float camerashake;
+extern float woozy;
+extern float terraindetail;
+extern float viewdistance;
+extern float blackout;
+extern int difficulty;
+extern Weapons weapons;
+extern bool decals;
+extern float fadestart;
+extern Person player[maxplayers];
+extern int numplayers;
+extern bool freeze;
+extern bool winfreeze;
+extern float flashamount,flashr,flashg,flashb;
+extern int flashdelay;
+extern bool showpoints;
+extern bool immediate;
+extern int test;
+extern bool tilt2weird;
+extern bool tiltweird;
+extern bool midweird;
+extern bool proportionweird;
+extern bool vertexweird[6];
+extern GLubyte texturearray[512*512*3];
+extern XYZ envsound[30];
+extern float envsoundvol[30];
+extern float envsoundlife[30];
+extern int numenvsounds;
+extern int bonus;
+extern float bonusvalue;
+extern float bonustotal;
+extern float bonustime;
+extern int tutoriallevel;
+extern float smoketex;
+extern int tutorialstage;
+extern bool reversaltrain;
+extern bool canattack;
+extern bool cananger;
+extern float damagedealt;
+extern float damagetaken;
+extern int hostile;
+extern float hostiletime;
+
+extern int mainmenu;
+
+extern int numfalls;
+extern int numflipfail;
+extern int numseen;
+extern int numswordattack;
+extern int numknifeattack;
+extern int numunarmedattack;
+extern int numescaped;
+extern int numflipped;
+extern int numwallflipped;
+extern int numthrowkill;
+extern int numafterkill;
+extern int numreversals;
+extern int numattacks;
+extern int maxalarmed;
+extern int indialogue;
+
+extern bool gamestarted;
+
+extern FSOUND_STREAM * strm[10];
+extern "C"     void PlaySoundEx(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused);
+extern "C" void PlayStreamEx(int chan, FSOUND_STREAM *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused);
+
+void Person::CheckKick(){
+       static XYZ relative;
+       static int i;
+
+       float damagemult=1*power;
+       if(creature==wolftype)damagemult=2.5*power;
+       damagemult*=power;
+
+       if(hasvictim)
+               if(targetanimation==rabbitkickanim&&victim&&victim!=this&&currentframe>=2&&currentanimation==rabbitkickanim){
+                       if(findDistancefast(&coords,&victim->coords)<1.2){
+                               if(!victim->skeleton.free){
+                                       relative=velocity;
+                                       Normalise(&relative);
+                                       relative=coords+relative*1;
+                                       if(animation[victim->targetanimation].height!=lowheight){
+                                               victim->spurt=1;
+                                               DoBlood(.2,250);
+                                               float gLoc[3];
+                                               float vel[3];
+                                               gLoc[0]=victim->coords.x;
+                                               gLoc[1]=victim->coords.y;
+                                               gLoc[2]=victim->coords.z;
+                                               vel[0]=velocity.x;
+                                               vel[1]=velocity.y;
+                                               vel[2]=velocity.z;
+                                               if(tutoriallevel!=1){
+                                                       PlaySoundEx( heavyimpactsound, samp[heavyimpactsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[heavyimpactsound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[heavyimpactsound], 128);
+                                                       FSOUND_SetPaused(channels[heavyimpactsound], FALSE);
+                                               }
+                                               victim->RagDoll(0);
+                                               relative=velocity;
+                                               relative.y=0;
+                                               Normalise(&relative);
+                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                       victim->skeleton.joints[i].velocity+=relative*120*damagemult;
+                                               }
+                                               victim->Puff(neck);
+                                               victim->DoDamage(100*damagemult/victim->protectionhigh);
+                                               if(id==0)camerashake+=.4;
+
+                                               target=0;
+                                               currentframe=3;
+                                               targetanimation=backflipanim;
+                                               targetframe=4;
+                                               velocity=facing*-10;
+                                               velocity.y=5;
+                                               skeleton.free=0;
+                                               if(id==0)FSOUND_SetPaused(channels[whooshsound], FALSE);
+
+                                               //if(victim->damage>victim->damagetolerance){
+                                               if(id==0){
+                                                       bonus=cannon;
+                                                       bonustime=0;
+                                                       bonusvalue=100;
+                                               }
+                                               //}
+                                       }
+                                       else if (victim->isCrouch()){
+                                               targetanimation=rabbitkickreversedanim;
+                                               currentanimation=rabbitkickreversedanim;
+                                               victim->currentanimation=rabbitkickreversalanim;
+                                               victim->targetanimation=rabbitkickreversalanim;
+                                               targettilt2=0;
+                                               currentframe=0;
+                                               targetframe=1;
+                                               target=0;
+                                               velocity=0;
+                                               victim->oldcoords=victim->coords;
+                                               coords=victim->coords;
+                                               victim->targetrotation=targetrotation;
+                                               victim->victim=this;
+                                       }
+                               }
+                       }
+               }
+}
+
+void Person::CatchFire(){
+       XYZ flatfacing,flatvelocity;
+       int howmany;
+       for(int i=0;i<10;i++){
+               howmany=abs(Random()%(skeleton.num_joints));
+               if(!skeleton.free)flatvelocity=velocity;
+               if(skeleton.free)flatvelocity=skeleton.joints[howmany].velocity;
+               if(!skeleton.free)flatfacing=DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position,0,0,tilt),tilt2,0,0),0,rotation,0)*scale+coords;
+               if(skeleton.free)flatfacing=skeleton.joints[howmany].position*scale+coords;
+               sprites.MakeSprite(flamesprite, flatfacing,flatvelocity, 1,1,1, 2, 1);
+       }
+
+       onfiredelay=0.5;
+
+       float gLoc[3];
+       float vel[3];
+       gLoc[0]=coords.x;
+       gLoc[1]=coords.y;
+       gLoc[2]=coords.z;
+       vel[0]=0;
+       vel[1]=0;
+       vel[2]=0;
+       PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+       FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+       FSOUND_SetVolume(channels[firestartsound], 256);
+       FSOUND_SetPaused(channels[firestartsound], FALSE);
+
+       vel[0]=velocity.x;
+       vel[1]=velocity.y;
+       vel[2]=velocity.z;
+       //PlaySoundEx( firesound, samp[firesound], NULL, TRUE);
+       PlayStreamEx( stream_firesound, strm[stream_firesound], NULL, TRUE);
+       FSOUND_3D_SetAttributes(channels[stream_firesound], gLoc, vel);
+       FSOUND_SetVolume(channels[stream_firesound], 256);
+       FSOUND_SetPaused(channels[stream_firesound], FALSE);
+
+       flamedelay=0;
+
+       onfire=1;
+}
+
+bool Person::isIdle(){
+       if(targetanimation==sleepanim||targetanimation==sitanim||targetanimation==talkidleanim||targetanimation==hurtidleanim||targetanimation==bounceidleanim||targetanimation==talkidleanim||targetanimation==fightidleanim||targetanimation==knifefightidleanim||targetanimation==swordfightidleanim||targetanimation==swordfightidlebothanim||targetanimation==fightsidestep||targetanimation==wolfidle)return 1;
+       else return 0;
+}
+
+bool Person::isSitting(){
+       if(targetanimation==sitanim)return 1;
+       if(targetanimation==sitwallanim)return 1;
+       else return 0;
+}
+
+bool Person::isSleeping(){
+       if(targetanimation==sleepanim)return 1;
+       if(targetanimation==dead1anim)return 1;
+       if(targetanimation==dead2anim)return 1;
+       if(targetanimation==dead3anim)return 1;
+       if(targetanimation==dead4anim)return 1;
+       else return 0;
+}
+
+bool Person::wasIdle(){
+       if(currentanimation==sleepanim||currentanimation==talkidleanim||currentanimation==sitanim||currentanimation==hurtidleanim||currentanimation==bounceidleanim||currentanimation==fightidleanim||currentanimation==swordfightidleanim||currentanimation==swordfightidlebothanim||currentanimation==knifefightidleanim||currentanimation==fightsidestep||currentanimation==wolfidle)return 1;
+       else return 0;
+}
+int Person::getIdle(){
+       if(indialogue!=-1&&howactive==typeactive&&creature==rabbittype)return talkidleanim;
+       if(hasvictim&&victim!=this/*||(id==0&&attackkeydown)*/)if(/*(id==0&&attackkeydown)||*/(!victim->dead&&victim->aitype!=passivetype&&victim->aitype!=searchtype&&aitype!=passivetype&&aitype!=searchtype&&victim->id<numplayers)){
+               if((aitype==playercontrolled&&stunned<=0&&weaponactive==-1)||pause){
+                       if(creature==rabbittype)return fightidleanim;
+                       if(creature==wolftype)return wolfidle;
+               }
+               if(aitype==playercontrolled&&stunned<=0&&weaponactive!=-1){
+                       if(weapons.type[weaponids[weaponactive]]==knife)return knifefightidleanim;
+                       if(weapons.type[weaponids[weaponactive]]==sword&&victim->weaponactive!=-1)return swordfightidlebothanim;
+                       if(weapons.type[weaponids[weaponactive]]==sword)return swordfightidleanim;
+                       if(weapons.type[weaponids[weaponactive]]==staff)return swordfightidleanim;
+               }
+               if(aitype!=playercontrolled&&stunned<=0&&creature!=wolftype&&!pause)return fightsidestep;
+       }
+       if((damage>permanentdamage||damage>damagetolerance*.8||deathbleeding>0)&&creature!=wolftype)return hurtidleanim;
+       if(howactive==typesitting)return sitanim;
+       if(howactive==typesittingwall)return sitwallanim;
+       if(howactive==typesleeping)return sleepanim;
+       if(howactive==typedead1)return dead1anim;
+       if(howactive==typedead2)return dead2anim;
+       if(howactive==typedead3)return dead3anim;
+       if(howactive==typedead4)return dead4anim;
+       if(creature==rabbittype)return bounceidleanim;
+       if(creature==wolftype)return wolfidle;
+       return 0;
+}
+
+bool Person::isCrouch(){
+       if(targetanimation==crouchanim||targetanimation==wolfcrouchanim)return 1;
+       else return 0;
+}
+
+
+bool Person::wasCrouch(){
+       if(currentanimation==crouchanim||currentanimation==wolfcrouchanim)return 1;
+       else return 0;
+}
+int Person::getCrouch(){
+       if(creature==rabbittype)return crouchanim;
+       if(creature==wolftype)return wolfcrouchanim;
+       return 0;
+}
+
+bool Person::isRun(){
+       if(targetanimation==runanim||targetanimation==wolfrunanim||targetanimation==wolfrunninganim||targetanimation==rabbitrunninganim)return 1;
+       else return 0;
+}
+
+
+bool Person::wasRun(){
+       if(currentanimation==runanim||currentanimation==wolfrunanim||currentanimation==wolfrunninganim||currentanimation==rabbitrunninganim)return 1;
+       else return 0;
+}
+int Person::getRun(){
+       if(creature==rabbittype&&(!superruntoggle||weaponactive!=-1))return runanim;
+       if(creature==wolftype&&(!superruntoggle))return wolfrunanim;
+
+       if(creature==rabbittype&&(superruntoggle&&weaponactive==-1))return rabbitrunninganim;
+       if(creature==wolftype&&(superruntoggle))return wolfrunninganim;
+       return 0;
+}
+
+bool Person::isStop(){
+       if(targetanimation==stopanim||targetanimation==wolfstopanim)return 1;
+       else return 0;
+}
+
+
+bool Person::wasStop(){
+       if(currentanimation==stopanim||currentanimation==wolfstopanim)return 1;
+       else return 0;
+}
+int Person::getStop(){
+       if(creature==rabbittype)return stopanim;
+       if(creature==wolftype)return wolfstopanim;
+       return 0;
+}
+
+
+bool Person::isLanding(){
+       if(targetanimation==landanim||targetanimation==wolflandanim)return 1;
+       else return 0;
+}
+
+
+bool Person::wasLanding(){
+       if(currentanimation==landanim||currentanimation==wolflandanim)return 1;
+       else return 0;
+}
+int Person::getLanding(){
+       if(creature==rabbittype)return landanim;
+       if(creature==wolftype)return wolflandanim;
+       return 0;
+}
+
+
+bool Person::isLandhard(){
+       if(targetanimation==landhardanim||targetanimation==wolflandhardanim)return 1;
+       else return 0;
+}
+
+
+bool Person::wasLandhard(){
+       if(currentanimation==landhardanim||currentanimation==wolflandhardanim)return 1;
+       else return 0;
+}
+int Person::getLandhard(){
+       if(creature==rabbittype)return landhardanim;
+       if(creature==wolftype)return wolflandhardanim;
+       return 0;
+}
+
+
+bool Person::isFlip(){
+       if(targetanimation==flipanim||targetanimation==frontflipanim||targetanimation==backflipanim||targetanimation==rightflipanim||targetanimation==leftflipanim||targetanimation==walljumprightkickanim||targetanimation==walljumpleftkickanim)return 1;
+       else return 0;
+}
+
+bool Person::wasFlip(){
+       if(currentanimation==flipanim||currentanimation==frontflipanim||currentanimation==backflipanim||currentanimation==rightflipanim||currentanimation==leftflipanim||currentanimation==walljumprightkickanim||currentanimation==walljumpleftkickanim)return 1;
+       else return 0;
+}
+
+bool Person::isWallJump(){
+       if(targetanimation==walljumpfrontanim||targetanimation==walljumpbackanim||targetanimation==walljumpleftanim||targetanimation==walljumprightanim)return 1;
+       else return 0;
+}
+
+void SolidHitBonus();
+void SolidHitBonus(){
+       if(bonustime<1.5&&(bonus==fourxcombo||bonus==megacombo)){
+               bonus=megacombo;
+               bonustime=0;
+               bonusvalue=160;
+       }
+       else if(bonustime<1.5&&bonus==threexcombo){
+               bonus=fourxcombo;
+               bonustime=0;
+               bonusvalue=80;
+       }
+       else if(bonustime<1.5&&bonus==twoxcombo){
+               bonus=threexcombo;
+               bonustime=0;
+               bonusvalue=40;
+       }
+       else if(bonustime<1.5&&bonus==solidhit){
+               bonus=twoxcombo;
+               bonustime=0;
+               bonusvalue=20;
+       }
+       else {
+               bonus=solidhit;
+               bonustime=0;
+               bonusvalue=10;
+       }
+}
+
+void Person::DoBlood(float howmuch,int which){
+       static int bleedxint,bleedyint;
+       static XYZ bloodvel;
+       //if(howmuch&&id==0)blooddimamount=1;
+       if(bloodtoggle&&tutoriallevel!=1){
+               if(bleeding<=0&&spurt){
+                       spurt=0;
+                       for(int i=0;i<3;i++){
+                               bloodvel=0;
+                               if(!skeleton.free){
+                                       bloodvel.z=10;
+                                       bloodvel=DoRotation(bloodvel,((float)(Random()%100))/4,rotation+((float)(Random()%100))/4,0)*scale;
+                               }
+                               if(skeleton.free){
+                                       bloodvel-=DoRotation(skeleton.forward*10*scale,((float)(Random()%100))/4,((float)(Random()%100))/4,0);
+                               }
+                               if(skeleton.free)bloodvel+=DoRotation(skeleton.joints[skeleton.jointlabels[head]].velocity,((float)(Random()%100))/4,rotation+((float)(Random()%100))/4,0)*scale;
+                               if(!skeleton.free)bloodvel+=DoRotation(velocity,((float)(Random()%100))/4,((float)(Random()%100))/4,0)*scale;
+                               if(skeleton.free){
+                                       sprites.MakeSprite(bloodsprite, skeleton.joints[skeleton.jointlabels[head]].position*scale+coords,bloodvel, 1,1,1, .05, 1);
+                                       sprites.MakeSprite(bloodflamesprite, skeleton.joints[skeleton.jointlabels[head]].position*scale+coords,bloodvel, 1,1,1, .3, 1);
+                               }
+                               if(!skeleton.free){
+                                       sprites.MakeSprite(bloodsprite, DoRotation((skeleton.joints[skeleton.jointlabels[head]].position+skeleton.joints[skeleton.jointlabels[neck]].position)/2,0,rotation,0)*scale+coords,bloodvel, 1,1,1, .05, 1);
+                                       sprites.MakeSprite(bloodflamesprite, DoRotation((skeleton.joints[skeleton.jointlabels[head]].position+skeleton.joints[skeleton.jointlabels[neck]].position)/2,0,rotation,0)*scale+coords,bloodvel, 1,1,1, .3, 1);
+                               }               
+                       }
+                       if(Random()%2==0)
+                               for(int i=0;i<3;i++){
+                                       if(Random()%2!=0){
+                                               bloodvel=0;
+                                               if(!skeleton.free){
+                                                       bloodvel.z=10;
+                                                       bloodvel=DoRotation(bloodvel,((float)(Random()%100))/4,rotation+((float)(Random()%100))/4,0)*scale;
+                                               }
+                                               if(skeleton.free){
+                                                       bloodvel-=DoRotation(skeleton.forward*10*scale,((float)(Random()%100))/4,((float)(Random()%100))/4,0);
+                                               }
+                                               if(skeleton.free)bloodvel+=DoRotation(skeleton.joints[skeleton.jointlabels[head]].velocity,((float)(Random()%100))/4,rotation+((float)(Random()%100))/4,0)*scale;
+                                               if(!skeleton.free)bloodvel+=DoRotation(velocity,((float)(Random()%100))/4,((float)(Random()%100))/4,0)*scale;
+                                               bloodvel*=.2;
+                                               if(skeleton.free){
+                                                       sprites.MakeSprite(splintersprite, skeleton.joints[skeleton.jointlabels[head]].position*scale+coords,bloodvel, 1,1,1, .05, 1);
+                                                       sprites.special[sprites.numsprites-1]=3;
+                                               }
+                                               if(!skeleton.free){
+                                                       sprites.MakeSprite(splintersprite, DoRotation((skeleton.joints[skeleton.jointlabels[head]].position+skeleton.joints[skeleton.jointlabels[neck]].position)/2,0,rotation,0)*scale+coords,bloodvel, 1,1,1, .05, 1);
+                                                       sprites.special[sprites.numsprites-1]=3;
+                                               }
+                                       }
+                               }
+               }
+               if(decals){
+                       bleeding=howmuch+(float)abs(Random()%100)/200-.25;
+                       bleedxint=0;
+                       bleedyint=0;
+                       int texdetailint=realtexdetail;
+                       if(creature==rabbittype)
+                               while(bloodText[bleedxint*512*3+bleedyint*3+0]>which+4||bloodText[bleedxint*512*3+bleedyint*3+0]<which-4||bleedxint<10||bleedyint<10||bleedxint>500||bleedyint>500){
+                                       bleedxint=abs(Random()%512);
+                                       bleedyint=abs(Random()%512);
+                               }
+                               if(creature==wolftype)
+                                       while(wolfbloodText[bleedxint*512*3+bleedyint*3+0]>which+4||wolfbloodText[bleedxint*512*3+bleedyint*3+0]<which-4||bleedxint<10||bleedyint<10||bleedxint>500||bleedyint>500){
+                                               bleedxint=abs(Random()%512);
+                                               bleedyint=abs(Random()%512);
+                                       }
+                                       bleedy=bleedxint;
+                                       bleedx=bleedyint;
+                                       bleedy/=realtexdetail;
+                                       bleedx/=realtexdetail;
+                                       direction=abs(Random()%2)*2-1;
+               }
+
+       }
+       if(bleeding>2)bleeding=2;
+}
+
+void Person::DoBloodBig(float howmuch,int which){
+       static int bleedxint,bleedyint,i,j;
+       static XYZ bloodvel;
+       if(howmuch&&id==0)blooddimamount=1;
+
+       if(tutoriallevel!=1||id==0)
+               if(aitype!=playercontrolled&&howmuch>0){
+                       int whichsound=-1;
+                       float gLoc[3];
+                       float vel[3];
+                       gLoc[0]=coords.x;
+                       gLoc[1]=coords.y;
+                       gLoc[2]=coords.z;
+                       vel[0]=velocity.x;
+                       vel[1]=velocity.y;
+                       vel[2]=velocity.z;
+
+                       if(creature==wolftype){
+                               int i=abs(Random()%2);
+                               if(i==0)whichsound=snarlsound;
+                               if(i==1)whichsound=snarl2sound;
+                               envsound[numenvsounds]=coords;
+                               envsoundvol[numenvsounds]=16;
+                               envsoundlife[numenvsounds]=.4;
+                               numenvsounds++;
+                       }
+                       if(creature==rabbittype){
+                               int i=abs(Random()%2);
+                               if(i==0)whichsound=rabbitpainsound;
+                               if(i==1&&howmuch>=2)whichsound=rabbitpain1sound;
+                               envsound[numenvsounds]=coords;
+                               envsoundvol[numenvsounds]=16;
+                               envsoundlife[numenvsounds]=.4;
+                               numenvsounds++;
+                               //if(i==2)whichsound=rabbitpain2sound;
+                       }
+
+                       if(whichsound!=-1){
+                               PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[whichsound], 512);
+                               FSOUND_SetPaused(channels[whichsound], FALSE);
+                       }
+               }
+
+               if(id==0&&howmuch>0){
+                       flashamount=.5;
+                       flashr=1;
+                       flashg=0;
+                       flashb=0;
+                       flashdelay=0;
+               }
+
+               if(bloodtoggle&&decals&&tutoriallevel!=1){
+                       if(bleeding<=0&&spurt){
+                               spurt=0;
+                               for(int i=0;i<3;i++){
+                                       bloodvel=0;
+                                       if(!skeleton.free){
+                                               bloodvel.z=10;
+                                               bloodvel=DoRotation(bloodvel,((float)(Random()%100))/4,rotation+((float)(Random()%100))/4,0)*scale;
+                                       }
+                                       if(skeleton.free){
+                                               bloodvel-=DoRotation(skeleton.forward*10*scale,((float)(Random()%100))/4,((float)(Random()%100))/4,0);
+                                       }
+                                       if(skeleton.free)bloodvel+=DoRotation(skeleton.joints[skeleton.jointlabels[head]].velocity,((float)(Random()%100))/4,rotation+((float)(Random()%100))/4,0)*scale;
+                                       if(!skeleton.free)bloodvel+=DoRotation(velocity,((float)(Random()%100))/4,((float)(Random()%100))/4,0)*scale;
+                                       if(skeleton.free){
+                                               sprites.MakeSprite(bloodsprite, skeleton.joints[skeleton.jointlabels[head]].position*scale+coords,bloodvel, 1,1,1, .05, 1);
+                                               sprites.MakeSprite(bloodflamesprite, skeleton.joints[skeleton.jointlabels[head]].position*scale+coords,bloodvel, 1,1,1, .3, 1);
+                                       }
+                                       if(!skeleton.free){
+                                               sprites.MakeSprite(bloodsprite, DoRotation((skeleton.joints[skeleton.jointlabels[head]].position+skeleton.joints[skeleton.jointlabels[neck]].position)/2,0,rotation,0)*scale+coords,bloodvel, 1,1,1, .05, 1);
+                                               sprites.MakeSprite(bloodflamesprite, DoRotation((skeleton.joints[skeleton.jointlabels[head]].position+skeleton.joints[skeleton.jointlabels[neck]].position)/2,0,rotation,0)*scale+coords,bloodvel, 1,1,1, .3, 1);
+                                       }       
+                               }
+                       }
+                       int offsetx=0,offsety=0;
+                       if(which==225){
+                               offsety=Random()%40;
+                               offsetx=abs(Random()%60);
+                       }
+                       if(which==190||which==185){
+                               offsety=Random()%40;
+                               offsetx=abs(Random()%100)-20;
+                       }
+                       if(which==175){
+                               offsety=Random()%10;
+                               offsetx=Random()%10;
+                       }
+                       if(which==170){
+                               offsety=Random()%20;
+                               offsetx=Random()%20;
+                       }
+                       if(which==220||which==215){
+                               //offsety=Random()%20;
+                               offsetx=20;
+                               //offsetx=abs(Random()%80);
+                       }
+
+
+                       int startx=512;
+                       int starty=512;
+                       int endx=0;
+                       int endy=0;
+                       GLubyte color;
+                       if(creature==rabbittype)
+                               for(i=0;i<512;i++){
+                                       for(j=0;j<512;j++){
+                                               if(bloodText[i*512*3+j*3+0]<=which+4&&bloodText[i*512*3+j*3+0]>=which-4){
+                                                       if(i<startx)startx=i;
+                                                       if(j<starty)starty=j;
+                                                       if(i>endx)endx=i;
+                                                       if(j>endy)endy=j;
+                                               }
+                                       }       
+                               }
+                               if(creature==wolftype)
+                                       for(i=0;i<512;i++){
+                                               for(j=0;j<512;j++){
+                                                       if(wolfbloodText[i*512*3+j*3+0]<=which+4&&wolfbloodText[i*512*3+j*3+0]>=which-4){
+                                                               if(i<startx)startx=i;
+                                                               if(j<starty)starty=j;
+                                                               if(i>endx)endx=i;
+                                                               if(j>endy)endy=j;
+                                                       }
+                                               }       
+                                       }
+
+                                       startx+=offsetx;
+                                       endx+=offsetx;
+                                       starty+=offsety;
+                                       endy+=offsety;
+
+                                       if(startx<0)startx=0;
+                                       if(starty<0)starty=0;
+                                       if(endx>512-1)endx=512-1;
+                                       if(endy>512-1)endy=512-1;
+                                       if(endx<startx)endx=startx;
+                                       if(endy<starty)endy=starty;
+
+                                       startx/=realtexdetail;
+                                       starty/=realtexdetail;
+                                       endx/=realtexdetail;
+                                       endy/=realtexdetail;
+
+                                       int texdetailint=realtexdetail;
+                                       int where;
+                                       if(creature==rabbittype)
+                                               for(i=startx;i<endx;i++){
+                                                       for(j=starty;j<endy;j++){
+                                                               if(bloodText[(i*texdetailint-offsetx)*512*3+(j*texdetailint-offsety)*3+0]<=which+4&&bloodText[(i*texdetailint-offsetx)*512*3+(j*texdetailint-offsety)*3+0]>=which-4){
+                                                                       color=Random()%85+170;
+                                                                       where=i*skeleton.skinsize*3+j*3;
+                                                                       if(skeleton.skinText[where+0]>color/2)skeleton.skinText[where+0]=color/2;
+                                                                       skeleton.skinText[where+1]=0;
+                                                                       skeleton.skinText[where+2]=0;
+                                                               }
+                                                       }
+                                               }
+                                               if(creature==wolftype)
+                                                       for(i=startx;i<endx;i++){
+                                                               for(j=starty;j<endy;j++){
+                                                                       if(wolfbloodText[(i*texdetailint-offsetx)*512*3+(j*texdetailint-offsety)*3+0]<=which+4&&wolfbloodText[(i*texdetailint-offsetx)*512*3+(j*texdetailint-offsety)*3+0]>=which-4){
+                                                                               color=Random()%85+170;
+                                                                               where=i*skeleton.skinsize*3+j*3;
+                                                                               if(skeleton.skinText[where+0]>color/2)skeleton.skinText[where+0]=color/2;
+                                                                               skeleton.skinText[where+1]=0;
+                                                                               skeleton.skinText[where+2]=0;
+                                                                       }
+                                                               }
+                                                       }
+                                                       glBindTexture(GL_TEXTURE_2D,skeleton.drawmodel.textureptr);
+                                                       if(detail!=2||osx)DoMipmaps(5,0,0,skeleton.skinsize,skeleton.skinsize);
+                                                       else DoMipmaps(0,startx/realtexdetail,endx/realtexdetail,starty/realtexdetail,endy/realtexdetail);
+
+                                                       bleedxint=0;
+                                                       bleedyint=0;
+                                                       if(creature==rabbittype)
+                                                               while(bloodText[bleedxint*512*3+bleedyint*3+0]>which+4||bloodText[bleedxint*512*3+bleedyint*3+0]<which-4||bleedxint<10||bleedyint<10||bleedxint>500||bleedyint>500){
+                                                                       bleedxint=abs(Random()%512);
+                                                                       bleedyint=abs(Random()%512);
+                                                               }
+                                                               if(creature==wolftype)
+                                                                       while(wolfbloodText[bleedxint*512*3+bleedyint*3+0]>which+4||wolfbloodText[bleedxint*512*3+bleedyint*3+0]<which-4||bleedxint<10||bleedyint<10||bleedxint>500||bleedyint>500){
+                                                                               bleedxint=abs(Random()%512);
+                                                                               bleedyint=abs(Random()%512);
+                                                                       }
+                                                                       bleedy=bleedxint+offsetx;
+                                                                       bleedx=bleedyint+offsety;
+                                                                       bleedy/=realtexdetail;
+                                                                       bleedx/=realtexdetail;
+                                                                       if(bleedx<0)bleedx=0;
+                                                                       if(bleedy<0)bleedy=0;
+                                                                       if(bleedx>skeleton.skinsize-1)bleedx=skeleton.skinsize-1;
+                                                                       if(bleedy>skeleton.skinsize-1)bleedy=skeleton.skinsize-1;
+                                                                       direction=abs(Random()%2)*2-1;
+
+               }
+               bleeding=howmuch+(float)abs(Random()%100)/200-.25;
+               deathbleeding+=bleeding;
+               bloodloss+=bleeding*3;
+
+               if(tutoriallevel!=1&&aitype!=playercontrolled&&bloodloss>damagetolerance*2/3&&bloodloss<damagetolerance&&creature==rabbittype){
+                       if(abs(Random()%2)==0){aitype=gethelptype; 
+                       lastseentime=12;
+                       }
+                       else aitype=attacktypecutoff;
+                       ally=0;
+               }
+               if(bleeding>2)bleeding=2;
+}
+
+bool Person::DoBloodBigWhere(float howmuch,int which, XYZ where){
+       static int bleedxint,bleedyint,i,j;
+       static XYZ bloodvel;
+       static XYZ startpoint,endpoint,colpoint,movepoint;
+       static float rotationpoint;
+       static int whichtri;
+       static XYZ p1,p2,p3,p0;
+       static XYZ N,temp;
+       XYZ bary;
+       XYZ gxx,gyy;
+       float coordsx,coordsy;
+       float total;
+
+       if(bloodtoggle&&decals&&tutoriallevel!=1){
+               where-=coords;
+               if(!skeleton.free)where=DoRotation(where,0,-rotation,0);
+               //where=scale;
+               startpoint=where;
+               startpoint.y+=100;
+               endpoint=where;
+               endpoint.y-=100;
+               movepoint=0;
+               rotationpoint=0;
+               whichtri=skeleton.drawmodel.LineCheck(&startpoint,&endpoint, &colpoint, &movepoint, &rotationpoint);
+               if(whichtri!=-1){
+                       p0=colpoint;
+                       p1=skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[whichtri].vertex[0]];
+                       p2=skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[whichtri].vertex[1]];
+                       p3=skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[whichtri].vertex[2]];
+                       /*
+                       CrossProduct(p2-p1,p3-p1,&N);
+                       CrossProduct(p0-p1,p3-p1,&temp);
+                       s =  dotproduct(&temp,&N)/findLength(&N);
+                       CrossProduct(p2-p1,p1-p0,&temp);
+                       t = dotproduct(&temp,&N)/findLength(&N);
+                       r = 1 - (s + t);*/
+
+                       bary.x=findDistancefast(&p0,&p1);
+                       bary.y=findDistancefast(&p0,&p2);
+                       bary.z=findDistancefast(&p0,&p3);
+
+                       total=bary.x+bary.y+bary.z;
+                       bary.x/=total;
+                       bary.y/=total;
+                       bary.z/=total;
+
+                       bary.x=1-bary.x;
+                       bary.y=1-bary.y;
+                       bary.z=1-bary.z;
+
+                       total=bary.x+bary.y+bary.z;
+                       bary.x/=total;
+                       bary.y/=total;
+                       bary.z/=total;
+
+
+                       gxx.x=skeleton.drawmodel.Triangles[whichtri].gx[0];
+                       gxx.y=skeleton.drawmodel.Triangles[whichtri].gx[1];
+                       gxx.z=skeleton.drawmodel.Triangles[whichtri].gx[2];
+                       gyy.x=skeleton.drawmodel.Triangles[whichtri].gy[0];
+                       gyy.y=skeleton.drawmodel.Triangles[whichtri].gy[1];
+                       gyy.z=skeleton.drawmodel.Triangles[whichtri].gy[2];
+                       coordsx=skeleton.drawmodel.Triangles[whichtri].gx[0]*bary.x+skeleton.drawmodel.Triangles[whichtri].gx[1]*bary.y+skeleton.drawmodel.Triangles[whichtri].gx[2]*bary.z;
+                       coordsy=skeleton.drawmodel.Triangles[whichtri].gy[0]*bary.x+skeleton.drawmodel.Triangles[whichtri].gy[1]*bary.y+skeleton.drawmodel.Triangles[whichtri].gy[2]*bary.z;
+
+                       //coordsx=skeleton.drawmodel.Triangles[whichtri].gx[1];
+                       //coordsy=skeleton.drawmodel.Triangles[whichtri].gy[1];
+
+                       if(bleeding<=0&&spurt){
+                               spurt=0;
+                               for(int i=0;i<3;i++){
+                                       bloodvel=0;
+                                       if(!skeleton.free){
+                                               bloodvel.z=10;
+                                               bloodvel=DoRotation(bloodvel,((float)(Random()%100))/4,rotation+((float)(Random()%100))/4,0)*scale;
+                                       }
+                                       if(skeleton.free){
+                                               bloodvel-=DoRotation(skeleton.forward*10*scale,((float)(Random()%100))/4,((float)(Random()%100))/4,0);
+                                       }
+                                       if(skeleton.free)bloodvel+=DoRotation(skeleton.joints[skeleton.jointlabels[head]].velocity,((float)(Random()%100))/4,rotation+((float)(Random()%100))/4,0)*scale;
+                                       if(!skeleton.free)bloodvel+=DoRotation(velocity,((float)(Random()%100))/4,((float)(Random()%100))/4,0)*scale;
+                                       if(skeleton.free){
+                                               sprites.MakeSprite(bloodsprite, skeleton.joints[skeleton.jointlabels[head]].position*scale+coords,bloodvel, 1,1,1, .05, 1);
+                                               sprites.MakeSprite(bloodflamesprite, skeleton.joints[skeleton.jointlabels[head]].position*scale+coords,bloodvel, 1,1,1, .3, 1);
+                                       }
+                                       if(!skeleton.free){
+                                               sprites.MakeSprite(bloodsprite, DoRotation((skeleton.joints[skeleton.jointlabels[head]].position+skeleton.joints[skeleton.jointlabels[neck]].position)/2,0,rotation,0)*scale+coords,bloodvel, 1,1,1, .05, 1);
+                                               sprites.MakeSprite(bloodflamesprite, DoRotation((skeleton.joints[skeleton.jointlabels[head]].position+skeleton.joints[skeleton.jointlabels[neck]].position)/2,0,rotation,0)*scale+coords,bloodvel, 1,1,1, .3, 1);
+                                       }       
+                               }
+                       }
+                       int offsetx=0,offsety=0;
+                       /*if(which==225){
+                       offsety=Random()%40;
+                       offsetx=abs(Random()%120);
+                       }
+                       if(which==220||which==215){
+                       offsety=Random()%20;
+                       offsetx=abs(Random()%80);
+                       }*/
+                       //which=220;
+                       offsetx=(1+coordsy)*512-291;
+                       offsety=coordsx*512-437;
+
+                       int startx=512;
+                       int starty=512;
+                       int endx=0;
+                       int endy=0;
+                       GLubyte color;
+                       if(creature==rabbittype)
+                               for(i=0;i<512;i++){
+                                       for(j=0;j<512;j++){
+                                               if(bloodText[i*512*3+j*3+0]<=which+4&&bloodText[i*512*3+j*3+0]>=which-4){
+                                                       if(i<startx)startx=i;
+                                                       if(j<starty)starty=j;
+                                                       if(i>endx)endx=i;
+                                                       if(j>endy)endy=j;
+                                               }
+                                       }       
+                               }
+                               if(creature==wolftype)
+                                       for(i=0;i<512;i++){
+                                               for(j=0;j<512;j++){
+                                                       if(wolfbloodText[i*512*3+j*3+0]<=which+4&&wolfbloodText[i*512*3+j*3+0]>=which-4){
+                                                               if(i<startx)startx=i;
+                                                               if(j<starty)starty=j;
+                                                               if(i>endx)endx=i;
+                                                               if(j>endy)endy=j;
+                                                       }
+                                               }       
+                                       }
+                                       startx+=offsetx;
+                                       endx+=offsetx;
+                                       starty+=offsety;
+                                       endy+=offsety;
+
+                                       if(startx<0)startx=0;
+                                       if(starty<0)starty=0;
+                                       if(endx>512-1)endx=512-1;
+                                       if(endy>512-1)endy=512-1;
+                                       if(endx<startx)endx=startx;
+                                       if(endy<starty)endy=starty;
+
+                                       startx/=realtexdetail;
+                                       starty/=realtexdetail;
+                                       endx/=realtexdetail;
+                                       endy/=realtexdetail;
+
+                                       int texdetailint=realtexdetail;
+                                       int where;
+                                       if(creature==rabbittype)
+                                               for(i=startx;i<endx;i++){
+                                                       for(j=starty;j<endy;j++){
+                                                               if(bloodText[(i*texdetailint-offsetx)*512*3+(j*texdetailint-offsety)*3+0]<=which+4&&bloodText[(i*texdetailint-offsetx)*512*3+(j*texdetailint-offsety)*3+0]>=which-4){
+                                                                       color=Random()%85+170;
+                                                                       where=i*skeleton.skinsize*3+j*3;
+                                                                       if(skeleton.skinText[where+0]>color/2)skeleton.skinText[where+0]=color/2;
+                                                                       skeleton.skinText[where+1]=0;
+                                                                       skeleton.skinText[where+2]=0;
+                                                               }
+                                                               else if(bloodText[(i*texdetailint-offsetx)*512*3+(j*texdetailint-offsety)*3+0]<=160+4&&bloodText[(i*texdetailint-offsetx)*512*3+(j*texdetailint-offsety)*3+0]>=160-4){
+                                                                       color=Random()%85+170;
+                                                                       where=i*skeleton.skinsize*3+j*3;
+                                                                       if(skeleton.skinText[where+0]>color/2)skeleton.skinText[where+0]=color/2;
+                                                                       skeleton.skinText[where+1]=0;
+                                                                       skeleton.skinText[where+2]=0;
+                                                               }
+                                                       }
+                                               }
+                                               if(creature==wolftype)
+                                                       for(i=startx;i<endx;i++){
+                                                               for(j=starty;j<endy;j++){
+                                                                       if(wolfbloodText[(i*texdetailint-offsetx)*512*3+(j*texdetailint-offsety)*3+0]<=which+4&&wolfbloodText[(i*texdetailint-offsetx)*512*3+(j*texdetailint-offsety)*3+0]>=which-4){
+                                                                               color=Random()%85+170;
+                                                                               where=i*skeleton.skinsize*3+j*3;
+                                                                               if(skeleton.skinText[where+0]>color/2)skeleton.skinText[where+0]=color/2;
+                                                                               skeleton.skinText[where+1]=0;
+                                                                               skeleton.skinText[where+2]=0;
+                                                                       }
+                                                                       else if(wolfbloodText[(i*texdetailint-offsetx)*512*3+(j*texdetailint-offsety)*3+0]<=160+4&&wolfbloodText[(i*texdetailint-offsetx)*512*3+(j*texdetailint-offsety)*3+0]>=160-4){
+                                                                               color=Random()%85+170;
+                                                                               where=i*skeleton.skinsize*3+j*3;
+                                                                               if(skeleton.skinText[where+0]>color/2)skeleton.skinText[where+0]=color/2;
+                                                                               skeleton.skinText[where+1]=0;
+                                                                               skeleton.skinText[where+2]=0;
+                                                                       }
+                                                               }
+                                                       }
+                                                       glBindTexture(GL_TEXTURE_2D,skeleton.drawmodel.textureptr);
+                                                       if(detail!=2||osx)DoMipmaps(5,0,0,skeleton.skinsize,skeleton.skinsize);
+                                                       else DoMipmaps(0,startx/realtexdetail,endx/realtexdetail,starty/realtexdetail,endy/realtexdetail);
+
+                                                       bleedy=(1+coordsy)*512;
+                                                       bleedx=coordsx*512;
+                                                       bleedy/=realtexdetail;
+                                                       bleedx/=realtexdetail;
+                                                       if(bleedx<0)bleedx=0;
+                                                       if(bleedy<0)bleedy=0;
+                                                       if(bleedx>skeleton.skinsize-1)bleedx=skeleton.skinsize-1;
+                                                       if(bleedy>skeleton.skinsize-1)bleedy=skeleton.skinsize-1;
+                                                       direction=abs(Random()%2)*2-1;
+               }
+               if(whichtri==-1)return 0;
+       }
+       bleeding=howmuch+(float)abs(Random()%100)/200-.25;
+       deathbleeding+=bleeding;
+       bloodloss+=bleeding*3;
+
+       if(tutoriallevel!=1&&aitype!=playercontrolled&&bloodloss>damagetolerance*2/3&&bloodloss<damagetolerance&&creature==rabbittype){
+               if(abs(Random()%2)==0){aitype=gethelptype; 
+               lastseentime=12;
+               }
+               else aitype=attacktypecutoff;
+               ally=0;
+       }
+       if(bleeding>2)bleeding=2;
+       return 1;
+}
+
+
+void Person::DoMipmaps(int howmanylevels,float startx, float endx, float starty, float endy){
+       int i,j,k;
+       static float temp;
+       static int bytesPerPixel=3;
+       static int newsize,totalsize,rowsize,bigstep,smallstep,sum;
+       static int newstartx,newstarty,newendx,newendy;
+       static int newnewstartx,newnewstarty,newnewendx,newnewendy;
+       static int which;
+       static float sizemult;
+       /*
+       for(i=0;i<skeleton.skinsize*skeleton.skinsize*bytesPerPixel;i++){
+       texture[i]=skeleton.skinText[i];
+       }
+       */
+       if((!osx||howmanylevels)){
+
+               if(startx<0)startx=0;
+               if(starty<0)starty=0;
+               if(endx>skeleton.skinsize-1)endx=skeleton.skinsize-1;
+               if(endy>skeleton.skinsize-1)endy=skeleton.skinsize-1;
+               if((endx>startx&&endy>starty)||howmanylevels){
+
+                       newstartx=startx;
+                       newstarty=starty;
+                       newendx=endx;
+                       newendy=endy;
+
+                       for(i=startx;i<endx;i++){
+                               for(j=starty;j<endy;j++){
+                                       texturearray[(i-newstartx)*(newendy-newstarty)*3+(j-newstarty)*3+0]=skeleton.skinText[i*skeleton.skinsize*3+j*3+0];
+                                       texturearray[(i-newstartx)*(newendy-newstarty)*3+(j-newstarty)*3+1]=skeleton.skinText[i*skeleton.skinsize*3+j*3+1];
+                                       texturearray[(i-newstartx)*(newendy-newstarty)*3+(j-newstarty)*3+2]=skeleton.skinText[i*skeleton.skinsize*3+j*3+2];
+                               }
+                       }
+
+                       glBindTexture(GL_TEXTURE_2D,skeleton.drawmodel.textureptr);
+
+                       if(!howmanylevels){
+                               if(!osx)glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_TRUE);
+                               glTexSubImage2D(GL_TEXTURE_2D,0,starty,startx,endy-starty,endx-startx,GL_RGB,GL_UNSIGNED_BYTE,texturearray);
+                               if(!osx)glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS,GL_FALSE);
+                       }
+
+                       newsize=skeleton.skinsize;
+
+                       if(howmanylevels)
+                               gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGB, skeleton.skinsize, skeleton.skinsize, GL_RGB, GL_UNSIGNED_BYTE, &skeleton.skinText[0] );
+               }
+               /*for(j=1;j<=howmanylevels;j++){
+               if(j==1)texpointer=&skeleton.skinText[0];
+               else texpointer=&texture[0];
+
+               totalsize=int( newsize*newsize*bytesPerPixel);
+               rowsize=int( newsize*bytesPerPixel );
+               bigstep=bytesPerPixel*newsize*2;
+               smallstep=bytesPerPixel*2;
+
+               which=0;
+
+
+
+               glTexSubImage2D(GL_TEXTURE_2D,j,0,0,newsize/2,newsize/2,GL_RGB,GL_UNSIGNED_BYTE,texture);
+               newsize/=2;
+               }*/
+       }
+}
+
+
+void Person::Reverse(){
+       if(victim->aitype==playercontrolled||hostiletime>1)
+               if(victim->targetanimation!=jumpupanim&&victim->targetanimation!=jumpdownanim&&((tutoriallevel!=1||cananger)&&hostile)){
+                       if(normaldotproduct(victim->facing,victim->coords-coords)>0&&!(victim->id==0&&difficulty<2)&&(creature!=wolftype||victim->creature==wolftype))return;
+                       if(victim->aitype!=playercontrolled&&staggerdelay>0)return;
+                       if(targetanimation==sweepanim){
+                               targetanimation=sweepreversedanim;
+                               currentanimation=sweepreversedanim;
+                               victim->currentanimation=sweepreversalanim;
+                               victim->targetanimation=sweepreversalanim;
+                       }
+                       if(targetanimation==spinkickanim){
+                               targetanimation=spinkickreversedanim;
+                               currentanimation=spinkickreversedanim;
+                               victim->currentanimation=spinkickreversalanim;
+                               victim->targetanimation=spinkickreversalanim;
+                       }
+                       if(targetanimation==upunchanim||targetanimation==rabbittacklinganim){
+                               if(targetanimation==rabbittacklinganim){
+                                       currentframe=6;
+                                       targetframe=7;
+                                       victim->currentframe=6;
+                                       victim->targetframe=7;
+                               }
+                               targetanimation=upunchreversedanim;
+                               currentanimation=upunchreversedanim;
+                               victim->currentanimation=upunchreversalanim;
+                               victim->targetanimation=upunchreversalanim;
+                       }
+                       if(targetanimation==staffhitanim&&findDistancefast(&victim->coords,&coords)<2&&((victim->id==0&&victim->crouchkeydown)||Random()%4==0)){
+                               if(victim->weaponactive!=-1){
+                                       victim->throwtogglekeydown=1;
+                                       weapons.owner[victim->weaponids[0]]=-1;
+                                       weapons.velocity[victim->weaponids[0]]=victim->velocity*.2;
+                                       if(weapons.velocity[victim->weaponids[0]].x==0)weapons.velocity[victim->weaponids[0]].x=.1;
+                                       weapons.tipvelocity[victim->weaponids[0]]=weapons.velocity[victim->weaponids[0]];
+                                       weapons.missed[victim->weaponids[0]]=1;
+                                       weapons.freetime[victim->weaponids[0]]=0;
+                                       weapons.firstfree[victim->weaponids[0]]=1;
+                                       weapons.physics[victim->weaponids[0]]=1;
+                                       victim->num_weapons--;
+                                       if(victim->num_weapons){
+                                               victim->weaponids[0]=victim->weaponids[victim->num_weapons];
+                                               if(victim->weaponstuck==victim->num_weapons)victim->weaponstuck=0;
+                                }
+
+                                       victim->weaponactive=-1;
+                                       for(int j=0;j<numplayers;j++){
+                                               player[j].wentforweapon=0;
+                                }
+                               }
+
+                               targetanimation=staffhitreversedanim;
+                               currentanimation=staffhitreversedanim;
+                               victim->currentanimation=staffhitreversalanim;
+                               victim->targetanimation=staffhitreversalanim;
+                       }
+                       if(targetanimation==staffspinhitanim&&findDistancefast(&victim->coords,&coords)<2&&((victim->id==0&&victim->crouchkeydown)||Random()%2==0)){
+                               if(victim->weaponactive!=-1){
+                                       victim->throwtogglekeydown=1;
+                                       weapons.owner[victim->weaponids[0]]=-1;
+                                       weapons.velocity[victim->weaponids[0]]=victim->velocity*.2;
+                                       if(weapons.velocity[victim->weaponids[0]].x==0)weapons.velocity[victim->weaponids[0]].x=.1;
+                                       weapons.tipvelocity[victim->weaponids[0]]=weapons.velocity[victim->weaponids[0]];
+                                       weapons.missed[victim->weaponids[0]]=1;
+                                       weapons.freetime[victim->weaponids[0]]=0;
+                                       weapons.firstfree[victim->weaponids[0]]=1;
+                                       weapons.physics[victim->weaponids[0]]=1;
+                                       victim->num_weapons--;
+                                       if(victim->num_weapons){
+                                               victim->weaponids[0]=victim->weaponids[victim->num_weapons];
+                                               if(victim->weaponstuck==victim->num_weapons)victim->weaponstuck=0;
+                                }
+
+                                       victim->weaponactive=-1;
+                                       for(int j=0;j<numplayers;j++){
+                                               player[j].wentforweapon=0;
+                                }
+                               }
+                               targetanimation=staffspinhitreversedanim;
+                               currentanimation=staffspinhitreversedanim;
+                               victim->currentanimation=staffspinhitreversalanim;
+                               victim->targetanimation=staffspinhitreversalanim;
+                       }
+                       if(targetanimation==swordslashanim&&findDistancefast(&victim->coords,&coords)<2&&((victim->id==0&&victim->crouchkeydown)||Random()%4==0)){
+                               if(victim->weaponactive!=-1){
+                                       victim->throwtogglekeydown=1;
+                                       weapons.owner[victim->weaponids[0]]=-1;
+                                       weapons.velocity[victim->weaponids[0]]=victim->velocity*.2;
+                                       if(weapons.velocity[victim->weaponids[0]].x==0)weapons.velocity[victim->weaponids[0]].x=.1;
+                                       weapons.tipvelocity[victim->weaponids[0]]=weapons.velocity[victim->weaponids[0]];
+                                       weapons.missed[victim->weaponids[0]]=1;
+                                       weapons.freetime[victim->weaponids[0]]=0;
+                                       weapons.firstfree[victim->weaponids[0]]=1;
+                                       weapons.physics[victim->weaponids[0]]=1;
+                                       victim->num_weapons--;
+                                       if(victim->num_weapons){
+                                               victim->weaponids[0]=victim->weaponids[victim->num_weapons];
+                                               if(victim->weaponstuck==victim->num_weapons)victim->weaponstuck=0;
+                                }
+
+                                       victim->weaponactive=-1;
+                                       for(int j=0;j<numplayers;j++){
+                                               player[j].wentforweapon=0;
+                                }
+                               }
+                               targetanimation=swordslashreversedanim;
+                               currentanimation=swordslashreversedanim;
+                               victim->currentanimation=swordslashreversalanim;
+                               victim->targetanimation=swordslashreversalanim;
+                       }
+                       if(targetanimation==knifeslashstartanim&&findDistancefast(&victim->coords,&coords)<2&&(victim->id==0||Random()%4==0)){
+                               if(victim->weaponactive!=-1){
+                                       victim->throwtogglekeydown=1;
+                                       weapons.owner[victim->weaponids[0]]=-1;
+                                       weapons.velocity[victim->weaponids[0]]=victim->velocity*.2;
+                                       if(weapons.velocity[victim->weaponids[0]].x==0)weapons.velocity[victim->weaponids[0]].x=.1;
+                                       weapons.tipvelocity[victim->weaponids[0]]=weapons.velocity[victim->weaponids[0]];
+                                       weapons.missed[victim->weaponids[0]]=1;
+                                       weapons.freetime[victim->weaponids[0]]=0;
+                                       weapons.firstfree[victim->weaponids[0]]=1;
+                                       weapons.physics[victim->weaponids[0]]=1;
+                                       victim->num_weapons--;
+                                       if(victim->num_weapons){
+                                               victim->weaponids[0]=victim->weaponids[victim->num_weapons];
+                                               if(victim->weaponstuck==victim->num_weapons)victim->weaponstuck=0;
+                                }
+
+                                       victim->weaponactive=-1;
+                                       for(int j=0;j<numplayers;j++){
+                                               player[j].wentforweapon=0;
+                                }
+                               }
+                               targetanimation=knifeslashreversedanim;
+                               currentanimation=knifeslashreversedanim;
+                               victim->currentanimation=knifeslashreversalanim;
+                               victim->targetanimation=knifeslashreversalanim;
+                       }
+                       if(targetanimation!=knifeslashstartanim&&targetanimation!=staffhitanim&&targetanimation!=staffspinhitanim&&targetanimation!=winduppunchanim&&targetanimation!=wolfslapanim&&targetanimation!=swordslashanim&&targetanimation!=swordslashanim){
+                               victim->targettilt2=targettilt2;
+                               victim->currentframe=currentframe;
+                               victim->targetframe=targetframe;
+                               victim->target=target;
+                               victim->velocity=0;
+                               victim->oldcoords=victim->coords;
+                               victim->coords=coords;
+                               victim->targetrotation=targetrotation;
+                               victim->rotation=targetrotation;
+                               victim->victim=this;
+                       }
+                       if(targetanimation==winduppunchanim){
+                               targetanimation=winduppunchblockedanim;
+                               victim->targetanimation=blockhighleftanim;
+                               victim->targetframe=1;
+                               victim->target=.5;
+                               victim->victim=this;
+                               victim->targetrotation=targetrotation+180;
+                       }
+                       if(targetanimation==wolfslapanim){
+                               targetanimation=winduppunchblockedanim;
+                               victim->targetanimation=blockhighleftanim;
+                               victim->targetframe=1;
+                               victim->target=.5;
+                               victim->victim=this;
+                               victim->targetrotation=targetrotation+180;
+                       }
+                       if((targetanimation==swordslashanim||targetanimation==staffhitanim||targetanimation==staffspinhitanim)&&victim->weaponactive!=-1){
+                               targetanimation=swordslashparriedanim;
+                               parriedrecently=.4;
+                               victim->parriedrecently=0;
+                               victim->targetanimation=swordslashparryanim;
+                               victim->targetframe=1;
+                               victim->target=.5;
+                               victim->victim=this;
+                               victim->targetrotation=targetrotation+180;
+
+                               if(abs(Random()%20)==0||weapons.type[victim->weaponids[victim->weaponactive]]==knife){
+                                       float gLoc[3];
+                                       float vel[3];
+                                       gLoc[0]=victim->coords.x;
+                                       gLoc[1]=victim->coords.y;
+                                       gLoc[2]=victim->coords.z;
+                                       vel[0]=velocity.x;
+                                       vel[1]=velocity.y;
+                                       vel[2]=velocity.z;
+                                       if(victim->weaponactive!=-1){
+                                               if(weapons.type[victim->weaponids[0]]==staff||weapons.type[weaponids[0]]==staff){
+                                                       if(weapons.type[victim->weaponids[0]]==staff)weapons.damage[victim->weaponids[0]]+=.2+float(abs(Random()%100)-50)/250;
+                                                       if(weapons.type[weaponids[0]]==staff)weapons.damage[weaponids[0]]+=.2+float(abs(Random()%100)-50)/250;
+
+                                                       PlaySoundEx( swordstaffsound, samp[swordstaffsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[swordstaffsound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[swordstaffsound], 512);
+                                                       FSOUND_SetPaused(channels[swordstaffsound], FALSE);
+                                               }
+                                               else{
+                                                       PlaySoundEx( metalhitsound, samp[metalhitsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[metalhitsound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[metalhitsound], 512);
+                                                       FSOUND_SetPaused(channels[metalhitsound], FALSE);
+                                               }
+                                       }
+                                       XYZ aim;
+                                       victim->Puff(righthand);
+                                       victim->target=0;
+                                       victim->targetframe=0;
+                                       victim->targetanimation=staggerbackhighanim;
+                                       victim->targetrotation=targetrotation+180;
+                                       victim->target=0;
+                                       weapons.owner[victim->weaponids[0]]=-1;
+                                       aim=DoRotation(facing,0,90,0)*21;
+                                       aim.y+=7;
+                                       weapons.velocity[victim->weaponids[0]]=aim*-.2;
+                                       weapons.tipvelocity[victim->weaponids[0]]=aim;
+                                       weapons.missed[victim->weaponids[0]]=1;
+                                       weapons.hitsomething[victim->weaponids[0]]=0;
+                                       weapons.freetime[victim->weaponids[0]]=0;
+                                       weapons.firstfree[victim->weaponids[0]]=1;
+                                       weapons.physics[victim->weaponids[0]]=1;
+                                       victim->num_weapons--;
+                                       if(victim->num_weapons){
+                                               victim->weaponids[0]=victim->weaponids[num_weapons];
+                                               if(victim->weaponstuck==victim->num_weapons)victim->weaponstuck=0;
+                                }
+                                       victim->weaponactive=-1;
+                                       for(int i=0;i<numplayers;i++){
+                                               player[i].wentforweapon=0;
+                                }
+
+
+
+
+
+                                       /*PlaySoundEx( metalhitsound, samp[metalhitsound], NULL, TRUE);
+                                       FSOUND_3D_SetAttributes(channels[metalhitsound], gLoc, vel);
+                                       FSOUND_SetVolume(channels[metalhitsound], 512);
+                                       FSOUND_SetPaused(channels[metalhitsound], FALSE);*/
+                               }
+
+                               if(abs(Random()%20)==0){
+                                       float gLoc[3];
+                                       float vel[3];
+                                       gLoc[0]=coords.x;
+                                       gLoc[1]=coords.y;
+                                       gLoc[2]=coords.z;
+                                       vel[0]=velocity.x;
+                                       vel[1]=velocity.y;
+                                       vel[2]=velocity.z;
+                                       if(weaponactive!=-1){
+                                               if(weapons.type[victim->weaponids[0]]==staff||weapons.type[weaponids[0]]==staff){
+                                                       if(weapons.type[victim->weaponids[0]]==staff)weapons.damage[victim->weaponids[0]]+=.2+float(abs(Random()%100)-50)/250;
+                                                       if(weapons.type[weaponids[0]]==staff)weapons.damage[weaponids[0]]+=.2+float(abs(Random()%100)-50)/250;
+
+                                                       PlaySoundEx( swordstaffsound, samp[swordstaffsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[swordstaffsound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[swordstaffsound], 512);
+                                                       FSOUND_SetPaused(channels[swordstaffsound], FALSE);
+                                               }
+                                               else{
+                                                       PlaySoundEx( metalhitsound, samp[metalhitsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[metalhitsound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[metalhitsound], 512);
+                                                       FSOUND_SetPaused(channels[metalhitsound], FALSE);
+                                               }
+                                       }
+
+                                       XYZ aim;
+                                       Puff(righthand);
+                                       target=0;
+                                       targetframe=0;
+                                       targetanimation=staggerbackhighanim;
+                                       targetrotation=targetrotation+180;
+                                       target=0;
+                                       weapons.owner[weaponids[0]]=-1;
+                                       aim=DoRotation(facing,0,90,0)*21;
+                                       aim.y+=7;
+                                       weapons.velocity[weaponids[0]]=aim*-.2;
+                                       weapons.tipvelocity[weaponids[0]]=aim;
+                                       weapons.hitsomething[weaponids[0]]=0;
+                                       weapons.missed[weaponids[0]]=1;
+                                       weapons.freetime[weaponids[0]]=0;
+                                       weapons.firstfree[weaponids[0]]=1;
+                                       weapons.physics[weaponids[0]]=1;
+                                       num_weapons--;
+                                       if(num_weapons){
+                                               weaponids[0]=weaponids[num_weapons];
+                                               if(weaponstuck==num_weapons)weaponstuck=0;
+                                }
+                                       weaponactive=-1;
+                                       for(int i=0;i<numplayers;i++){
+                                               player[i].wentforweapon=0;
+                                }
+
+
+                                       /*PlaySoundEx( metalhitsound, samp[metalhitsound], NULL, TRUE);
+                                       FSOUND_3D_SetAttributes(channels[metalhitsound], gLoc, vel);
+                                       FSOUND_SetVolume(channels[metalhitsound], 512);
+                                       FSOUND_SetPaused(channels[metalhitsound], FALSE);*/
+                               }
+                       }
+                       if(hasvictim)
+                               if(targetanimation==knifeslashstartanim||targetanimation==swordslashanim||targetanimation==staffhitanim||targetanimation==staffspinhitanim){
+                                       if((targetanimation!=staffhitanim&&targetanimation!=staffspinhitanim)||findDistancefast(&coords,&victim->coords)>.2){
+                                               //victim->targetanimation=sweepanim;
+                                               victim->targetanimation=dodgebackanim;
+                                               victim->targetframe=0;
+                                               victim->target=0;
+                                               //victim->velocity=0;
+
+                                               XYZ rotatetarget;
+                                               rotatetarget=coords-victim->coords;
+                                               Normalise(&rotatetarget);
+                                               victim->targetrotation=-asin(0-rotatetarget.x);
+                                               victim->targetrotation*=360/6.28;
+                                               if(rotatetarget.z<0)victim->targetrotation=180-victim->targetrotation;
+
+                                               victim->targettilt2=-asin(rotatetarget.y)*360/6.28;//*-70;
+
+                                               victim->lastattack3=victim->lastattack2;
+                                               victim->lastattack2=victim->lastattack;
+                                               victim->lastattack=victim->targetanimation;
+                                       }
+                                       else
+                                       {
+                                               victim->targetanimation=sweepanim;
+                                               victim->targetframe=0;
+                                               victim->target=0;
+
+                                               XYZ rotatetarget;
+                                               rotatetarget=coords-victim->coords;
+                                               Normalise(&rotatetarget);
+                                               victim->targetrotation=-asin(0-rotatetarget.x);
+                                               victim->targetrotation*=360/6.28;
+                                               if(rotatetarget.z<0)victim->targetrotation=180-victim->targetrotation;
+
+                                               victim->targettilt2=-asin(rotatetarget.y)*360/6.28;//*-70;
+
+                                               victim->lastattack3=victim->lastattack2;
+                                               victim->lastattack2=victim->lastattack;
+                                               victim->lastattack=victim->targetanimation;
+                                       }
+                               }
+
+                               velocity=0;
+                               victim->velocity=0;
+
+                               if(aitype!=playercontrolled)feint=0;
+                               if(aitype!=playercontrolled&&Random()%3==0&&escapednum<2&&difficulty==2)feint=1;
+                               if(aitype!=playercontrolled&&Random()%5==0&&escapednum<2&&difficulty==1)feint=1;
+                               if(aitype!=playercontrolled&&Random()%10==0&&escapednum<2&&difficulty==0)feint=1;
+
+                               if(victim->id==0&&animation[victim->targetanimation].attack==reversal)numreversals++;
+               }
+}
+
+void Person::DoDamage(float howmuch){
+       if(tutoriallevel!=1)damage+=howmuch/power;
+       if(id!=0)damagedealt+=howmuch/power;
+       if(id==0)damagetaken+=howmuch/power;
+
+       if(id==0&&(bonus==solidhit||bonus==twoxcombo||bonus==threexcombo||bonus==fourxcombo||bonus==megacombo))bonus=0;
+       if(tutoriallevel!=1)permanentdamage+=howmuch/2/power;
+       if(tutoriallevel!=1)superpermanentdamage+=howmuch/4/power;
+       if(permanentdamage>damagetolerance/2&&permanentdamage-howmuch<damagetolerance/2&&Random()%2)DoBlood(1,255);
+       if((permanentdamage>damagetolerance*.8&&Random()%2&&!deathbleeding)||spurt)DoBlood(1,255);
+       spurt=0;
+       if(id==0)camerashake+=howmuch/100;
+       if(id==0&&((howmuch>50&&damage>damagetolerance/2)))blackout=damage/damagetolerance;
+       if(blackout>1)blackout=1;
+
+       if(aitype==passivetype&&damage<damagetolerance&&((tutoriallevel!=1||cananger)&&hostile))aitype=attacktypecutoff;
+       if(tutoriallevel!=1&&aitype!=playercontrolled&&damage<damagetolerance&&damage>damagetolerance*2/3&&creature==rabbittype){
+               if(abs(Random()%2)==0){aitype=gethelptype; 
+               lastseentime=12;
+               }
+               else aitype=attacktypecutoff;
+               ally=0;
+       }
+
+       if(howmuch>damagetolerance*50&&skeleton.free!=2){
+               XYZ flatvelocity2;
+               XYZ flatfacing2;
+               for(int i=0;i<skeleton.num_joints; i++){
+                       if(!skeleton.free)flatvelocity2=velocity;
+                       if(skeleton.free)flatvelocity2=skeleton.joints[i].velocity;
+                       if(!skeleton.free)flatfacing2=DoRotation(DoRotation(DoRotation(skeleton.joints[i].position,0,0,tilt),tilt2,0,0),0,rotation,0)*scale+coords;
+                       if(skeleton.free)flatfacing2=skeleton.joints[i].position*scale+coords;
+                       flatvelocity2.x+=(float)(abs(Random()%100)-50)/10;
+                       flatvelocity2.y+=(float)(abs(Random()%100)-50)/10;
+                       flatvelocity2.z+=(float)(abs(Random()%100)-50)/10;
+                       sprites.MakeSprite(bloodflamesprite, flatfacing2,flatvelocity2, 1,1,1, 3, 1);
+                       sprites.MakeSprite(bloodsprite, flatfacing2,flatvelocity2, 1,1,1, .4, 1);
+                       sprites.MakeSprite(cloudsprite, flatfacing2,flatvelocity2*0, .6,0,0, 1, .5);
+               }
+
+               float gLoc[3];
+               float vel[3];
+               gLoc[0]=coords.x;
+               gLoc[1]=coords.y;
+               gLoc[2]=coords.z;
+               vel[0]=0;
+               vel[1]=0;
+               vel[2]=0;
+               PlaySoundEx( splattersound, samp[splattersound], NULL, TRUE);
+               FSOUND_3D_SetAttributes(channels[splattersound], gLoc, vel);
+               FSOUND_SetVolume(channels[splattersound], 256);
+               FSOUND_SetPaused(channels[splattersound], FALSE);
+
+               skeleton.free=2;
+               DoDamage(10000);
+               RagDoll(0);
+               /*if(autoslomo){
+               slomo=1;
+               slomodelay=.2;
+               }*/
+               if(!dead&&creature==wolftype){
+                       bonus=Wolfbonus;
+                       bonustime=0;
+                       bonusvalue=300; 
+               }
+               dead=2;
+               coords=20;
+       }
+
+       if(tutoriallevel!=1||id==0)
+               if(speechdelay<=0&&!dead&&aitype!=playercontrolled){
+                       int whichsound=-1;
+                       float gLoc[3];
+                       float vel[3];
+                       gLoc[0]=coords.x;
+                       gLoc[1]=coords.y;
+                       gLoc[2]=coords.z;
+                       vel[0]=velocity.x;
+                       vel[1]=velocity.y;
+                       vel[2]=velocity.z;
+
+                       if(creature==wolftype){
+                               int i=abs(Random()%2);
+                               if(i==0)whichsound=snarlsound;
+                               if(i==1)whichsound=snarl2sound;
+                               envsound[numenvsounds]=coords;
+                               envsoundvol[numenvsounds]=16;
+                               envsoundlife[numenvsounds]=.4;
+                               numenvsounds++;
+                       }
+                       if(creature==rabbittype){
+                               int i=abs(Random()%2);
+                               if(i==0)whichsound=rabbitpainsound;
+                               if(i==1&&damage>damagetolerance)whichsound=rabbitpain1sound;
+                               envsound[numenvsounds]=coords;
+                               envsoundvol[numenvsounds]=16;
+                               envsoundlife[numenvsounds]=.4;
+                               numenvsounds++;
+                               //if(i==2)whichsound=rabbitpain2sound;
+                       }
+
+                       if(whichsound!=-1){
+                               PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[whichsound], 512);
+                               FSOUND_SetPaused(channels[whichsound], FALSE);
+                       }
+               }
+               speechdelay=.3;
+
+               //if(permanentdamage>=damagetolerance&&howmuch<50)permanentdamage=damagetolerance-1;
+               //if(damage>=damagetolerance&&howmuch<30&&!dead)damage=damagetolerance-1;
+}
+
+void Person::DoHead(){
+       static XYZ rotatearound;
+       static XYZ facing;
+       static float lookspeed=500;
+
+       if(!freeze&&!winfreeze&&(!mainmenu||!gamestarted)){
+
+               //head facing
+               targetheadrotation=(float)((int)((0-rotation-targetheadrotation+180)*100)%36000)/100;
+               targetheadrotation2=(float)((int)(targetheadrotation2*100)%36000)/100;
+
+               while(targetheadrotation>180)targetheadrotation-=360;
+               while(targetheadrotation<-180)targetheadrotation+=360;
+
+               if(targetheadrotation>160)targetheadrotation2=targetheadrotation2*-1;
+               if(targetheadrotation<-160)targetheadrotation2=targetheadrotation2*-1;
+               if(targetheadrotation>160)targetheadrotation=targetheadrotation-180;
+               if(targetheadrotation<-160)targetheadrotation=targetheadrotation+180;
+
+               if(targetheadrotation2>120)targetheadrotation2=120;
+               if(targetheadrotation2<-120)targetheadrotation2=-120;
+               if(targetheadrotation>120)targetheadrotation=120;
+               if(targetheadrotation<-120)targetheadrotation=-120;
+
+               if(!isIdle())targetheadrotation2=0;
+               if(isIdle()){
+                       if(targetheadrotation>80)targetheadrotation=80;
+                       if(targetheadrotation<-80)targetheadrotation=-80;
+                       if(targetheadrotation2>50)targetheadrotation2=50;
+                       if(targetheadrotation2<-50)targetheadrotation2=-50;
+               }
+
+               if(abs(headrotation-targetheadrotation)<multiplier*lookspeed)headrotation=targetheadrotation;
+               else if(headrotation>targetheadrotation){
+                       headrotation-=multiplier*lookspeed;
+               }
+               else if(headrotation<targetheadrotation){
+                       headrotation+=multiplier*lookspeed;
+               }
+
+               if(abs(headrotation2-targetheadrotation2)<multiplier*lookspeed/2)headrotation2=targetheadrotation2;
+               else if(headrotation2>targetheadrotation2){
+                       headrotation2-=multiplier*lookspeed/2;
+               }
+               else if(headrotation2<targetheadrotation2){
+                       headrotation2+=multiplier*lookspeed/2;
+               }
+
+               rotatearound=skeleton.joints[skeleton.jointlabels[neck]].position;
+               skeleton.joints[skeleton.jointlabels[head]].position=rotatearound+DoRotation(skeleton.joints[skeleton.jointlabels[head]].position-rotatearound,headrotation2,0,0);
+
+               facing=0;
+               facing.z=-1;
+               if(targetanimation!=bounceidleanim&&targetanimation!=fightidleanim&&targetanimation!=wolfidle&&targetanimation!=knifefightidleanim&&targetanimation!=drawrightanim&&targetanimation!=drawleftanim&&targetanimation!=walkanim){
+                       facing=DoRotation(facing,headrotation2*.4,0,0);
+                       facing=DoRotation(facing,0,headrotation*.4,0);
+               }
+
+               if(targetanimation==bounceidleanim||targetanimation==fightidleanim||targetanimation==wolfidle||targetanimation==knifefightidleanim||targetanimation==drawrightanim||targetanimation==drawleftanim){
+                       facing=DoRotation(facing,headrotation2*.8,0,0);
+                       facing=DoRotation(facing,0,headrotation*.8,0);
+               }
+
+               if(targetanimation==walkanim){
+                       facing=DoRotation(facing,headrotation2*.6,0,0);
+                       facing=DoRotation(facing,0,headrotation*.6,0);
+               }
+
+               skeleton.specialforward[0]=facing;
+               //skeleton.specialforward[0]=DoRotation(facing,0,rotation,0);
+               static int i;
+               for(i=0;i<skeleton.num_muscles;i++){
+                       if(skeleton.muscles[i].visible&&(skeleton.muscles[i].parent1->label==head||skeleton.muscles[i].parent2->label==head))
+                       {
+                               skeleton.FindRotationMuscle(i,targetanimation);
+                       }
+               }
+       }
+}
+
+void Person::RagDoll(bool checkcollision){
+       static XYZ change;
+       static int l,i,j;
+       static float speed;
+       if(!skeleton.free){
+               if(id==0)numfalls++;
+               if(id==0&&isFlip())numflipfail++;
+
+               escapednum=0;
+
+               facing=0;
+               facing.z=1;
+               facing=DoRotation(facing,0,rotation,0);
+
+               skeleton.freetime=0;
+
+               skeleton.longdead=0;
+
+               skeleton.free=1;
+               skeleton.broken=0;
+               skeleton.spinny=1;
+               freefall=1;
+               skeleton.freefall=1;
+
+               if(!isnormal(velocity.x))velocity.x=0;
+               if(!isnormal(velocity.y))velocity.y=0;
+               if(!isnormal(velocity.z))velocity.z=0;
+               if(!isnormal(rotation))rotation=0;
+               if(!isnormal(coords.x))coords=0;
+               if(!isnormal(tilt))tilt=0;
+               if(!isnormal(tilt2))tilt2=0;
+
+               for(i=0;i<skeleton.num_joints;i++){
+                       skeleton.joints[i].delay=0;
+                       skeleton.joints[i].locked=0;
+                       skeleton.joints[i].position=DoRotation(DoRotation(DoRotation(skeleton.joints[i].position,0,0,tilt),tilt2,0,0),0,rotation,0);
+                       if(!isnormal(skeleton.joints[i].position.x))skeleton.joints[i].position=DoRotation(skeleton.joints[i].position,0,rotation,0);
+                       if(!isnormal(skeleton.joints[i].position.x))skeleton.joints[i].position=skeleton.joints[i].position;
+                       if(!isnormal(skeleton.joints[i].position.x))skeleton.joints[i].position=coords;
+                       skeleton.joints[i].position.y+=.1;
+                       skeleton.joints[i].oldposition=skeleton.joints[i].position;
+                       skeleton.joints[i].realoldposition=skeleton.joints[i].position*scale+coords;
+               }
+
+               for(i=0;i<skeleton.num_joints;i++){
+                       skeleton.joints[i].velocity=0;
+                       skeleton.joints[i].velchange=0;
+               }
+               skeleton.DoConstraints(&coords,&scale);
+               if(animation[currentanimation].height==lowheight||animation[targetanimation].height==lowheight)
+               {
+                       skeleton.DoConstraints(&coords,&scale);
+                       skeleton.DoConstraints(&coords,&scale);
+                       skeleton.DoConstraints(&coords,&scale);
+                       skeleton.DoConstraints(&coords,&scale);
+               }
+
+               speed=animation[targetanimation].speed[targetframe]*2;
+               if(animation[currentanimation].speed[currentframe]>animation[targetanimation].speed[targetframe]){
+                       speed=animation[currentanimation].speed[currentframe]*2;
+               }
+               if(transspeed)speed=transspeed*2;
+
+               speed*=speedmult;
+
+               for(i=0;i<skeleton.num_joints;i++){
+                       if((animation[currentanimation].attack!=reversed||currentanimation==swordslashreversedanim)&&currentanimation!=rabbitkickanim&&!isLanding()&&!wasLanding()&&animation[currentanimation].height==animation[targetanimation].height)skeleton.joints[i].velocity=velocity/scale+facing*5+DoRotation(DoRotation(DoRotation((animation[targetanimation].position[i][targetframe]-animation[currentanimation].position[i][currentframe])*speed,0,0,tilt),tilt2,0,0),0,rotation,0);
+                       else skeleton.joints[i].velocity=velocity/scale+facing*5;
+                       change.x=(float)(Random()%100)/100;
+                       change.y=(float)(Random()%100)/100;
+                       change.z=(float)(Random()%100)/100;
+                       skeleton.joints[i].velocity+=change;
+                       skeleton.joints[abs(Random()%skeleton.num_joints)].velocity-=change;
+
+                       change.x=(float)(Random()%100)/100;
+                       change.y=(float)(Random()%100)/100;
+                       change.z=(float)(Random()%100)/100;
+                       skeleton.joints[i].velchange+=change;
+                       skeleton.joints[abs(Random()%skeleton.num_joints)].velchange-=change;
+               }
+
+               if(checkcollision){
+                       XYZ average;
+                       XYZ lowpoint;
+                       XYZ colpoint;
+                       int howmany;
+                       average=0;
+                       howmany=0;
+                       for(j=0;j<skeleton.num_joints;j++){
+                               average+=skeleton.joints[j].position;
+                               howmany++;
+                       }
+                       average/=howmany;
+                       coords+=average*scale;
+                       for(j=0;j<skeleton.num_joints;j++){
+                               skeleton.joints[j].position-=average;
+                       }
+
+                       whichpatchx=coords.x/(terrain.size/subdivision*terrain.scale*terraindetail);
+                       whichpatchz=coords.z/(terrain.size/subdivision*terrain.scale*terraindetail);
+                       if(terrain.patchobjectnum[whichpatchx][whichpatchz])
+                               for(l=0;l<terrain.patchobjectnum[whichpatchx][whichpatchz];l++){
+                                       i=terrain.patchobjects[whichpatchx][whichpatchz][l];
+                                       lowpoint=coords;
+                                       lowpoint.y+=1;
+                                       if(SphereCheck(&lowpoint, 3, &colpoint, &objects.position[i], &objects.rotation[i], &objects.model[i])!=-1){
+                                               coords.x=lowpoint.x;
+                                               coords.z=lowpoint.z;
+                                       }
+                               }
+               }
+
+               rotation=0;
+               updatedelay=0;
+
+               velocity=0;
+               for(i=0;i<skeleton.num_joints;i++){
+                       velocity+=skeleton.joints[i].velocity*scale;
+               }
+               velocity/=skeleton.num_joints;
+
+               if(Random()%2==0){
+                       if(weaponactive!=-1&&targetanimation!=rabbitkickanim&&num_weapons>0){
+                               weapons.owner[weaponids[0]]=-1;
+                               weapons.hitsomething[weaponids[0]]=0;
+                               weapons.velocity[weaponids[0]]=skeleton.joints[skeleton.jointlabels[righthand]].velocity*scale*-.3;
+                               weapons.velocity[weaponids[0]].x+=.01;
+                               weapons.tipvelocity[weaponids[0]]=skeleton.joints[skeleton.jointlabels[righthand]].velocity*scale;
+                               weapons.missed[weaponids[0]]=1;
+                               weapons.freetime[weaponids[0]]=0;
+                               weapons.firstfree[weaponids[0]]=1;
+                               weapons.physics[weaponids[0]]=1;
+                               num_weapons--;
+                               if(num_weapons){
+                                       weaponids[0]=weaponids[num_weapons];
+                                       if(weaponstuck==num_weapons)weaponstuck=0;
+                               }
+                               weaponactive=-1;
+                               for(i=0;i<numplayers;i++){
+                                       player[i].wentforweapon=0;
+                               }
+                       }
+               }
+
+               targetanimation=bounceidleanim;
+               currentanimation=bounceidleanim;
+               targetframe=0;
+               currentframe=0;
+       }
+}
+
+
+
+void Person::FootLand(int which, float opacity){
+       static XYZ terrainlight;
+       static XYZ footvel,footpoint;
+       if(opacity>=1||skiddelay<=0)
+               if(opacity>1)
+               {
+                       footvel=0;
+                       if(which==0)footpoint=DoRotation(skeleton.joints[skeleton.jointlabels[leftfoot]].position,0,rotation,0)*scale+coords;
+                       if(which==1)footpoint=DoRotation(skeleton.joints[skeleton.jointlabels[rightfoot]].position,0,rotation,0)*scale+coords;
+                       //footpoint.y=coords.y;
+                       if(findDistancefast(&footpoint,&viewer))sprites.MakeSprite(cloudsprite, footpoint,footvel, 1,1,1, .5, .2*opacity);
+               }
+               else if(environment==snowyenvironment&&onterrain&&terrain.getOpacity(coords.x,coords.z)<.2){
+                       footvel=velocity/5;
+                       if(footvel.y<.8)footvel.y=.8;
+                       if(which==0)footpoint=DoRotation(skeleton.joints[skeleton.jointlabels[leftfoot]].position,0,rotation,0)*scale+coords;
+                       if(which==1)footpoint=DoRotation(skeleton.joints[skeleton.jointlabels[rightfoot]].position,0,rotation,0)*scale+coords;
+                       footpoint.y=terrain.getHeight(footpoint.x,footpoint.z);
+                       terrainlight=terrain.getLighting(footpoint.x,footpoint.z);
+                       if(findDistancefast(&footpoint,&viewer)<viewdistance*viewdistance/4)sprites.MakeSprite(cloudsprite, footpoint,footvel*.6, terrainlight.x,terrainlight.y,terrainlight.z, .5, .7*opacity);
+                       if(opacity>=1||detail==2)if(detail==2)if(findDistancefast(&footpoint,&viewer)<viewdistance*viewdistance/4)terrain.MakeDecal(footprintdecal,footpoint,.2,1*opacity,rotation);
+               }
+               else if(environment==grassyenvironment&&onterrain&&terrain.getOpacity(coords.x,coords.z)<.2){
+                       footvel=velocity/5;
+                       if(footvel.y<.8)footvel.y=.8;
+                       if(which==0)footpoint=DoRotation(skeleton.joints[skeleton.jointlabels[leftfoot]].position,0,rotation,0)*scale+coords;
+                       if(which==1)footpoint=DoRotation(skeleton.joints[skeleton.jointlabels[rightfoot]].position,0,rotation,0)*scale+coords;
+                       footpoint.y=terrain.getHeight(footpoint.x,footpoint.z);
+                       terrainlight=terrain.getLighting(footpoint.x,footpoint.z);
+                       if(findDistancefast(&footpoint,&viewer)<viewdistance*viewdistance/4)sprites.MakeSprite(cloudsprite, footpoint,footvel*.6, terrainlight.x*90/255,terrainlight.y*70/255,terrainlight.z*8/255, .5, .5*opacity);
+               }
+               else if(environment==desertenvironment&&onterrain&&terrain.getOpacity(coords.x,coords.z)<.2){
+                       footvel=velocity/5;
+                       if(footvel.y<.8)footvel.y=.8;
+                       if(which==0)footpoint=DoRotation(skeleton.joints[skeleton.jointlabels[leftfoot]].position,0,rotation,0)*scale+coords;
+                       if(which==1)footpoint=DoRotation(skeleton.joints[skeleton.jointlabels[rightfoot]].position,0,rotation,0)*scale+coords;
+                       footpoint.y=terrain.getHeight(footpoint.x,footpoint.z);
+                       terrainlight=terrain.getLighting(footpoint.x,footpoint.z);
+                       if(findDistancefast(&footpoint,&viewer)<viewdistance*viewdistance/4)sprites.MakeSprite(cloudsprite, footpoint,footvel*.6, terrainlight.x*190/255,terrainlight.y*170/255,terrainlight.z*108/255, .5, .7*opacity);
+                       if(opacity>=1||detail==2)if(detail==2)if(findDistancefast(&footpoint,&viewer)<viewdistance*viewdistance/4)terrain.MakeDecal(footprintdecal,footpoint,.2,.25*opacity,rotation);
+               }
+               else if(isLanding()||targetanimation==jumpupanim||isLandhard())
+               {
+                       footvel=velocity/5;
+                       if(footvel.y<.8)footvel.y=.8;
+                       if(which==0)footpoint=DoRotation(skeleton.joints[skeleton.jointlabels[leftfoot]].position,0,rotation,0)*scale+coords;
+                       if(which==1)footpoint=DoRotation(skeleton.joints[skeleton.jointlabels[rightfoot]].position,0,rotation,0)*scale+coords;
+                       //footpoint.y=coords.y;
+                       if(findDistancefast(&footpoint,&viewer)<viewdistance*viewdistance/4)sprites.MakeSprite(cloudsprite, footpoint,footvel*.6, 1,1,1, .5, .2*opacity);
+               }
+}
+
+void Person::Puff(int whichlabel){
+       static XYZ footvel,footpoint;
+
+       footvel=0;
+       footpoint=DoRotation(skeleton.joints[skeleton.jointlabels[whichlabel]].position,0,rotation,0)*scale+coords;
+       sprites.MakeSprite(cloudimpactsprite, footpoint,footvel, 1,1,1, .9, .3);
+}
+
+
+/*
+HitStruct      Person::BulletCollideWithPlayer(XYZ start, XYZ end){
+float damage=20;
+XYZ tempbulletloc[2];
+XYZ collisionpoint;
+XYZ sparkpos;
+GLfloat M[16];
+int collide;
+float howfar;
+XYZ average;
+XYZ facing;
+int howmany;
+float distancemax;
+HitStruct hitstruct;
+hitstruct.collision=0;
+//Make bounding sphere
+average=0;
+howmany=0;
+for(int j=0;j<skeleton.num_joints;j++){
+average.x=average.x+skeleton.joints[j].position.x;
+average.y=average.y+skeleton.joints[j].position.y;
+average.z=average.z+skeleton.joints[j].position.z;
+howmany++;
+}
+average=average/howmany;
+distancemax=0;
+for(int j=0;j<skeleton.num_joints;j++){
+if(findDistancefast(average,skeleton.joints[j].position)>distancemax){
+distancemax=findDistancefast(average,skeleton.joints[j].position);
+}
+}
+distancemax=fast_sqrt(distancemax);
+//Collide with player
+if(skeleton.free<1){
+start=start-coords;
+end=end-coords;
+if(rotation)start=DoRotation(start,0,-rotation,0);
+if(rotation)end=DoRotation(end,0,-rotation,0);
+}
+tempbulletloc[0]=start;
+tempbulletloc[1]=end;
+if(sphere_line_intersection(tempbulletloc[0].x,tempbulletloc[0].y,tempbulletloc[0].z,
+tempbulletloc[1].x,tempbulletloc[1].y,tempbulletloc[1].z,
+average.x, average.y, average.z, distancemax)){
+for(int j=0;j<skeleton.num_joints;j++){
+if(skeleton.joints[j].hasparent&&skeleton.joints[j].visible){
+tempbulletloc[0]=start;
+tempbulletloc[1]=end;
+glPushMatrix();
+glLoadIdentity();
+glScalef(1,1/skeleton.joints[j].length,1);
+glRotatef(skeleton.joints[j].rotate2-90,0,0,1);
+glRotatef(skeleton.joints[j].rotate1-90,0,1,0);
+glTranslatef(  (-(skeleton.joints[j].position.x+skeleton.joints[j].parent->position.x)/2),
+(-(skeleton.joints[j].position.y+skeleton.joints[j].parent->position.y)/2),
+(-(skeleton.joints[j].position.z+skeleton.joints[j].parent->position.z)/2));
+glTranslatef(tempbulletloc[0].x,tempbulletloc[0].y,tempbulletloc[0].z);
+glGetFloatv(GL_MODELVIEW_MATRIX,M);
+tempbulletloc[0].x=M[12];
+tempbulletloc[0].y=M[13];
+tempbulletloc[0].z=M[14];
+glPopMatrix();
+glPushMatrix();
+glLoadIdentity();
+glScalef(1,1/skeleton.joints[j].length,1);
+glRotatef(skeleton.joints[j].rotate2-90,0,0,1);
+glRotatef(skeleton.joints[j].rotate1-90,0,1,0);
+glTranslatef(  (-(skeleton.joints[j].position.x+skeleton.joints[j].parent->position.x)/2),
+(-(skeleton.joints[j].position.y+skeleton.joints[j].parent->position.y)/2),
+(-(skeleton.joints[j].position.z+skeleton.joints[j].parent->position.z)/2));
+glTranslatef(tempbulletloc[1].x,tempbulletloc[1].y,tempbulletloc[1].z);
+glGetFloatv(GL_MODELVIEW_MATRIX,M);
+tempbulletloc[1].x=M[12];
+tempbulletloc[1].y=M[13];
+tempbulletloc[1].z=M[14];
+glPopMatrix();
+collide=skeletonmodels[skeleton.joints[j].modelnum].LineCheck(tempbulletloc[0],tempbulletloc[1],&collisionpoint);
+if(collide!=-1)
+{
+glPushMatrix();
+glLoadIdentity();
+glTranslatef(  (skeleton.joints[j].position.x+skeleton.joints[j].parent->position.x)/2,
+(skeleton.joints[j].position.y+skeleton.joints[j].parent->position.y)/2,
+(skeleton.joints[j].position.z+skeleton.joints[j].parent->position.z)/2);
+glRotatef(-skeleton.joints[j].rotate1+90,0,1,0);
+glRotatef(-skeleton.joints[j].rotate2+90,0,0,1);
+glScalef(1,skeleton.joints[j].length,1);
+glTranslatef(collisionpoint.x,collisionpoint.y,collisionpoint.z);
+glGetFloatv(GL_MODELVIEW_MATRIX,M);
+collisionpoint.x=M[12];
+collisionpoint.y=M[13];
+collisionpoint.z=M[14];
+glPopMatrix();
+hitstruct.collision=1;
+hitstruct.hitlocation=collisionpoint;
+hitstruct.joint1=&skeleton.joints[j];
+hitstruct.joint2=skeleton.joints[j].parent;
+}
+}
+}
+for(int j=0;j<skeleton.num_muscles;j++){
+if(skeleton.muscles[j].visible){
+tempbulletloc[0]=start;
+tempbulletloc[1]=end;
+glPushMatrix();
+glLoadIdentity();
+glScalef(1,1/skeleton.muscles[j].length,1);
+glRotatef(skeleton.muscles[j].rotate3,0,1,0);
+glRotatef(skeleton.muscles[j].rotate2-90,0,0,1);
+glRotatef(skeleton.muscles[j].rotate1-90,0,1,0);
+glTranslatef(  (-(skeleton.muscles[j].parent1->position.x+skeleton.muscles[j].parent2->position.x)/2),
+(-(skeleton.muscles[j].parent1->position.y+skeleton.muscles[j].parent2->position.y)/2),
+(-(skeleton.muscles[j].parent1->position.z+skeleton.muscles[j].parent2->position.z)/2));
+
+glTranslatef(tempbulletloc[0].x,tempbulletloc[0].y,tempbulletloc[0].z);
+glGetFloatv(GL_MODELVIEW_MATRIX,M);
+tempbulletloc[0].x=M[12];
+tempbulletloc[0].y=M[13];
+tempbulletloc[0].z=M[14];
+glPopMatrix();
+glPushMatrix();
+glLoadIdentity();
+glScalef(1,1/skeleton.muscles[j].length,1);
+glRotatef(skeleton.muscles[j].rotate3,0,1,0);
+glRotatef(skeleton.muscles[j].rotate2-90,0,0,1);
+glRotatef(skeleton.muscles[j].rotate1-90,0,1,0);
+
+glTranslatef(  (-(skeleton.muscles[j].parent1->position.x+skeleton.muscles[j].parent2->position.x)/2),
+(-(skeleton.muscles[j].parent1->position.y+skeleton.muscles[j].parent2->position.y)/2),
+(-(skeleton.muscles[j].parent1->position.z+skeleton.muscles[j].parent2->position.z)/2));
+glTranslatef(tempbulletloc[1].x,tempbulletloc[1].y,tempbulletloc[1].z);
+glGetFloatv(GL_MODELVIEW_MATRIX,M);
+tempbulletloc[1].x=M[12];
+tempbulletloc[1].y=M[13];
+tempbulletloc[1].z=M[14];
+glPopMatrix();
+collide=skeletonmodels[skeleton.muscles[j].parent1->modelnum].LineCheck(tempbulletloc[0],tempbulletloc[1],&collisionpoint);
+if(collide!=-1)
+{
+glPushMatrix();
+glLoadIdentity();
+glTranslatef(  (skeleton.muscles[j].parent1->position.x+skeleton.muscles[j].parent2->position.x)/2,
+(skeleton.muscles[j].parent1->position.y+skeleton.muscles[j].parent2->position.y)/2,
+(skeleton.muscles[j].parent1->position.z+skeleton.muscles[j].parent2->position.z)/2);
+glRotatef(-skeleton.muscles[j].rotate1+90,0,1,0);
+glRotatef(-skeleton.muscles[j].rotate2+90,0,0,1);
+glRotatef(-skeleton.muscles[j].rotate3,0,1,0);
+glScalef(1,findDistance(skeleton.muscles[j].parent1->position,skeleton.muscles[j].parent2->position),1);
+glTranslatef(collisionpoint.x,collisionpoint.y,collisionpoint.z);
+glGetFloatv(GL_MODELVIEW_MATRIX,M);
+collisionpoint.x=M[12];
+collisionpoint.y=M[13];
+collisionpoint.z=M[14];
+glPopMatrix();
+hitstruct.collision=1;
+hitstruct.hitlocation=collisionpoint;
+hitstruct.joint1=skeleton.muscles[j].parent1;
+hitstruct.joint2=skeleton.muscles[j].parent2;
+}
+}
+}
+}
+if(skeleton.free<1){
+if(rotation)hitstruct.hitlocation=DoRotation(hitstruct.hitlocation,0,rotation,0);
+hitstruct.hitlocation=hitstruct.hitlocation+coords;
+}
+return hitstruct;
+}
+*/
+void   Person::DoAnimations(){ 
+       if(!skeleton.free){
+               int i = 0;
+               static float oldtarget;
+
+               if(isIdle()&&currentanimation!=getIdle())normalsupdatedelay=0;
+
+               if(targetanimation==tempanim||currentanimation==tempanim){
+                       animation[tempanim]=tempanimation;                      
+               }
+               if(targetanimation==jumpupanim||targetanimation==jumpdownanim||isFlip()){
+                       float gLoc[3];
+                       float vel[3];
+                       gLoc[0]=coords.x;
+                       gLoc[1]=coords.y;
+                       gLoc[2]=coords.z;
+                       vel[0]=velocity.x;
+                       vel[1]=velocity.y;
+                       vel[2]=velocity.z;
+
+                       if(id==0){
+                               FSOUND_3D_SetAttributes(channels[whooshsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[whooshsound], 64*findLength(&velocity)/5);
+                       }
+                       if(((velocity.y<-15)||(crouchkeydown&&velocity.y<-8))&&abs(velocity.y)*4>fast_sqrt(velocity.x*velocity.x*velocity.z*velocity.z))landhard=1;                     
+                       if(!crouchkeydown&&velocity.y>=-15)landhard=0;
+               }
+               if((currentanimation==jumpupanim||targetanimation==jumpdownanim)/*&&velocity.y<40*/&&!isFlip()&&(!isLanding()&&!isLandhard())&&((crouchkeydown&&!crouchtogglekeydown))){
+                       XYZ targfacing;
+                       targfacing=0;
+                       targfacing.z=1;
+
+                       targfacing=DoRotation(targfacing,0,targetrotation,0);
+
+                       if(normaldotproduct(targfacing,velocity)>=-.3)targetanimation=flipanim;
+                       else targetanimation=backflipanim;
+                       crouchtogglekeydown=1;
+                       targetframe=0;
+                       target=0;
+
+                       if(id==0)numflipped++;
+               }
+
+               if(animation[targetanimation].attack!=reversed)feint=0;
+               if(!crouchkeydown||(isLanding()||isLandhard())||(wasLanding()||wasLandhard())){
+                       crouchtogglekeydown=0;
+                       if(aitype==playercontrolled)feint=0;
+               }
+               else 
+               {
+                       if(!crouchtogglekeydown&&animation[targetanimation].attack==reversed&&aitype==playercontrolled&&(escapednum<2||reversaltrain))feint=1;
+                       if(!isFlip())crouchtogglekeydown=1;
+               }
+
+
+               if(animation[targetanimation].attack||currentanimation==getupfrombackanim||currentanimation==getupfromfrontanim){
+                       if(detail)normalsupdatedelay=0;
+               }
+
+               if(target>=1){
+                       if(targetanimation==rollanim&&targetframe==3&&onfire){
+                               onfire=0;
+                               float gLoc[3];
+                               float vel[3];
+                               gLoc[0]=coords.x;
+                               gLoc[1]=coords.y;
+                               gLoc[2]=coords.z;
+                               vel[0]=0;
+                               vel[1]=0;
+                               vel[2]=0;
+                               PlaySoundEx( fireendsound, samp[fireendsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[fireendsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[fireendsound], 256);
+                               FSOUND_SetPaused(channels[fireendsound], FALSE);
+                               FSOUND_SetPaused(channels[stream_firesound], TRUE);
+                               deathbleeding=0;
+                       }
+
+                       if(targetanimation==rabbittacklinganim&&targetframe==1){
+                               //if(victim->aitype==attacktypecutoff&&Random()%2==0&&victim->stunned<=0&&animation[victim->targetanimation].attack==neutral&&victim->id!=0)Reverse();
+                               if(victim->aitype==attacktypecutoff&&victim->stunned<=0&&victim->surprised<=0&&victim->id!=0)Reverse();
+                               if(targetanimation==rabbittacklinganim&&targetframe==1&&!victim->isCrouch()&&victim->targetanimation!=backhandspringanim){
+                                       if(normaldotproduct(victim->facing,facing)>0)victim->targetanimation=rabbittackledbackanim;
+                                       else victim->targetanimation=rabbittackledfrontanim;
+                                       victim->targetframe=2;
+                                       victim->target=0;
+                                       victim->rotation=rotation;
+                                       victim->targetrotation=rotation;
+                                       if(victim->aitype==gethelptype)victim->DoDamage(victim->damagetolerance-victim->damage);
+                                       //victim->DoDamage(30);
+                                       if(creature==wolftype){
+                                               DoBloodBig(0,255);
+                                               float gLoc[3];
+                                               float vel[3];
+                                               gLoc[0]=victim->coords.x;
+                                               gLoc[1]=victim->coords.y;
+                                               gLoc[2]=victim->coords.z;
+                                               vel[0]=velocity.x;
+                                               vel[1]=velocity.y;
+                                               vel[2]=velocity.z;
+                                               PlaySoundEx( clawslicesound, samp[clawslicesound], NULL, TRUE);
+                                               FSOUND_3D_SetAttributes(channels[clawslicesound], gLoc, vel);
+                                               FSOUND_SetVolume(channels[clawslicesound], 128);
+                                               FSOUND_SetPaused(channels[clawslicesound], FALSE);
+                                               victim->spurt=1;
+                                               victim->DoBloodBig(1/victim->armorhead,210);
+                                       }
+                                       if(id==0){
+                                               bonus=TackleBonus;
+                                               bonustime=0;
+                                               bonusvalue=5;
+                                               if(victim->aitype==gethelptype)bonusvalue=50;
+                                       }
+                               }
+                       }
+
+                       if(!drawtogglekeydown&&drawkeydown&&(weaponactive==-1||num_weapons==1)&&(animation[targetanimation].label[targetframe]||(targetanimation!=currentanimation&&currentanimation==rollanim))&&num_weapons>0&&creature!=wolftype){
+                               if(weapons.type[weaponids[0]]==knife){
+                                       if(weaponactive==-1)weaponactive=0;
+                                       else if(weaponactive==0)weaponactive=-1;
+
+                                       if(weaponactive==-1){
+                                               float gLoc[3];
+                                               float vel[3];
+                                               gLoc[0]=coords.x;
+                                               gLoc[1]=coords.y;
+                                               gLoc[2]=coords.z;
+                                               vel[0]=velocity.x;
+                                               vel[1]=velocity.y;
+                                               vel[2]=velocity.z;
+
+                                               PlaySoundEx( knifesheathesound, samp[knifesheathesound], NULL, TRUE);
+                                               FSOUND_3D_SetAttributes(channels[knifesheathesound], gLoc, vel);
+                                               FSOUND_SetVolume(channels[knifesheathesound], 128);
+                                               FSOUND_SetPaused(channels[knifesheathesound], FALSE);   
+                                       }
+                                       if(weaponactive!=-1){
+                                               float gLoc[3];
+                                               float vel[3];
+                                               gLoc[0]=coords.x;
+                                               gLoc[1]=coords.y;
+                                               gLoc[2]=coords.z;
+                                               vel[0]=velocity.x;
+                                               vel[1]=velocity.y;
+                                               vel[2]=velocity.z;
+
+                                               PlaySoundEx( knifedrawsound, samp[knifedrawsound], NULL, TRUE);
+                                               FSOUND_3D_SetAttributes(channels[knifedrawsound], gLoc, vel);
+                                               FSOUND_SetVolume(channels[knifedrawsound], 128);
+                                               FSOUND_SetPaused(channels[knifedrawsound], FALSE);      
+                                       }
+                               }
+                               drawtogglekeydown=1;
+                       }
+                       //Footstep sounds
+                       if(tutoriallevel!=1||id==0)
+                               if((animation[targetanimation].label[targetframe]&&(animation[targetanimation].label[targetframe]<5||animation[targetanimation].label[targetframe]==8))/*||(targetanimation==rollanim&&targetframe==animation[rollanim].numframes-1)*/){
+                                       int whichsound;
+                                       float gLoc[3];
+                                       float vel[3];
+                                       gLoc[0]=coords.x;
+                                       gLoc[1]=coords.y;
+                                       gLoc[2]=coords.z;
+                                       vel[0]=velocity.x;
+                                       vel[1]=velocity.y;
+                                       vel[2]=velocity.z;
+                                       if(onterrain){
+                                               if(terrain.getOpacity(coords.x,coords.z)<.2){
+                                                       if(animation[targetanimation].label[targetframe]==1)whichsound=footstepsound;
+                                                       else whichsound=footstepsound2;
+                                                       if(animation[targetanimation].label[targetframe]==1)FootLand(0,1);
+                                                       if(animation[targetanimation].label[targetframe]==2)FootLand(1,1);
+                                                       if(animation[targetanimation].label[targetframe]==3&&isRun()){
+                                                               FootLand(1,1);
+                                                               FootLand(0,1);
+                                                       }
+
+                                               }       
+                                               if(terrain.getOpacity(coords.x,coords.z)>=.2){
+                                                       if(animation[targetanimation].label[targetframe]==1)whichsound=footstepsound3;
+                                                       else whichsound=footstepsound4;
+                                               }                       
+                                       }
+                                       if(!onterrain){
+                                               if(animation[targetanimation].label[targetframe]==1)whichsound=footstepsound3;
+                                               else whichsound=footstepsound4;
+                                       }
+                                       if(animation[targetanimation].label[targetframe]==4&&(weaponactive==-1||(targetanimation!=knifeslashstartanim&&targetanimation!=knifethrowanim&&targetanimation!=crouchstabanim&&targetanimation!=swordgroundstabanim&&targetanimation!=knifefollowanim))){
+                                               if(animation[targetanimation].attack!=neutral){
+                                                       i=abs(Random()%3);
+                                                       if(i==0)whichsound=lowwhooshsound;
+                                                       if(i==1)whichsound=midwhooshsound;
+                                                       if(i==2)whichsound=highwhooshsound;
+                                               }
+                                               if(animation[targetanimation].attack==neutral)whichsound=movewhooshsound;
+                                       }
+                                       else if(animation[targetanimation].label[targetframe]==4)whichsound=knifeswishsound;
+                                       if(animation[targetanimation].label[targetframe]==8&&tutoriallevel!=1)whichsound=landsound2;
+
+                                       PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                                       FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                                       if(whichsound!=knifeswishsound)FSOUND_SetVolume(channels[whichsound], 128);
+                                       if(whichsound!=knifeswishsound&&(targetanimation==staffhitanim||targetanimation==staffgroundsmashanim||targetanimation==staffspinhitanim))FSOUND_SetVolume(channels[whichsound], 256);
+                                       if(whichsound==knifeswishsound)FSOUND_SetVolume(channels[whichsound], 512);
+                                       FSOUND_SetPaused(channels[whichsound], FALSE);
+
+                                       if(id==0)
+                                               if(whichsound==footstepsound||whichsound==footstepsound2||whichsound==footstepsound3||whichsound==footstepsound4){
+                                                       envsound[numenvsounds]=coords;
+                                                       if(targetanimation==wolfrunninganim||targetanimation==rabbitrunninganim)envsoundvol[numenvsounds]=15;
+                                                       else envsoundvol[numenvsounds]=6;
+                                                       envsoundlife[numenvsounds]=.4;
+                                                       numenvsounds++;
+                                               }
+
+                                               if(animation[targetanimation].label[targetframe]==3){
+                                                       whichsound--;
+                                                       PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[whichsound], 128);
+                                                       FSOUND_SetPaused(channels[whichsound], FALSE);
+                                               }
+                               }
+
+                               //Combat sounds
+                               if(tutoriallevel!=1||id==0)
+                                       if(speechdelay<=0)
+                                               if(targetanimation!=crouchstabanim&&targetanimation!=swordgroundstabanim&&targetanimation!=staffgroundsmashanim)
+                                                       if((animation[targetanimation].label[targetframe]&&(animation[targetanimation].label[targetframe]<5||animation[targetanimation].label[targetframe]==8))/*||(targetanimation==rollanim&&targetframe==animation[rollanim].numframes-1)*/){
+                                                               int whichsound=-1;
+                                                               float gLoc[3];
+                                                               float vel[3];
+                                                               gLoc[0]=coords.x;
+                                                               gLoc[1]=coords.y;
+                                                               gLoc[2]=coords.z;
+                                                               vel[0]=velocity.x;
+                                                               vel[1]=velocity.y;
+                                                               vel[2]=velocity.z;
+                                                               if(animation[targetanimation].label[targetframe]==4&&aitype!=playercontrolled){
+                                                                       if(animation[targetanimation].attack!=neutral){
+                                                                               i=abs(Random()%4);
+                                                                               if(creature==rabbittype){
+                                                                                       if(i==0)whichsound=rabbitattacksound;
+                                                                                       if(i==1)whichsound=rabbitattack2sound;
+                                                                                       if(i==2)whichsound=rabbitattack3sound;
+                                                                                       if(i==3)whichsound=rabbitattack4sound;
+                                                                               }
+                                                                               if(creature==wolftype){
+                                                                                       if(i==0)whichsound=barksound;
+                                                                                       if(i==1)whichsound=bark2sound;
+                                                                                       if(i==2)whichsound=bark3sound;
+                                                                                       if(i==3)whichsound=barkgrowlsound;
+                                                                               }
+                                                                               speechdelay=.3;
+                                                                       }
+                                                                       //if(animation[targetanimation].attack==neutral)whichsound=movewhooshsound;
+                                                               }
+                                                               //else if(animation[targetanimation].label[targetframe]==4)whichsound=knifeswishsound;
+                                                               //if(animation[targetanimation].label[targetframe]==8)whichsound=landsound2;
+
+                                                               if(whichsound!=-1){
+                                                                       PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[whichsound], 512);
+                                                                       FSOUND_SetPaused(channels[whichsound], FALSE);
+                                                               }
+                                                       }
+
+
+
+                                                       if((!wasLanding()&&!wasLandhard())&&currentanimation!=getIdle()&&(isLanding()||isLandhard())){                          
+                                                               FootLand(0,1);
+                                                               FootLand(1,1);
+                                                       }
+
+                                                       transspeed=0;
+                                                       currentoffset=targetoffset;
+                                                       targetframe=currentframe;
+                                                       currentanimation=targetanimation;
+                                                       targetframe++;
+
+                                                       if(targetanimation==removeknifeanim&&animation[targetanimation].label[currentframe]==5){
+                                                               for(i=0;i<weapons.numweapons;i++){
+                                                                       if(/*weapons.velocity[i].x==0&&weapons.velocity[i].y==0&&weapons.velocity[i].z==0&&*/weapons.owner[i]==-1)
+                                                                               if(findDistancefastflat(&coords,&weapons.position[i])<4&&weaponactive==-1){
+                                                                                       if(findDistancefast(&coords,&weapons.position[i])>=1){
+                                                                                               if(weapons.type[i]!=staff){
+                                                                                                       float gLoc[3];
+                                                                                                       float vel[3];
+                                                                                                       gLoc[0]=coords.x;
+                                                                                                       gLoc[1]=coords.y;
+                                                                                                       gLoc[2]=coords.z;
+                                                                                                       vel[0]=velocity.x;
+                                                                                                       vel[1]=velocity.y;
+                                                                                                       vel[2]=velocity.z;
+                                                                                                       PlaySoundEx( knifedrawsound, samp[knifedrawsound], NULL, TRUE);
+                                                                                                       FSOUND_3D_SetAttributes(channels[knifedrawsound], gLoc, vel);
+                                                                                                       FSOUND_SetVolume(channels[knifedrawsound], 128);
+                                                                                                       FSOUND_SetPaused(channels[knifedrawsound], FALSE);
+                                                                                               }
+
+                                                                                               weaponactive=0;
+                                                                                               weapons.owner[i]=id;
+                                                                                               if(num_weapons>0){
+                                                                                                       weaponids[num_weapons]=weaponids[0];
+                                                                                               }
+                                                                                               num_weapons++;
+                                                                                               weaponids[0]=i;
+                                                                                       }
+                                                                               }
+                                                               }
+                                                       }
+
+                                                       static bool willwork;
+                                                       if(targetanimation==crouchremoveknifeanim&&animation[targetanimation].label[currentframe]==5){
+                                                               for(i=0;i<weapons.numweapons;i++){
+                                                                       bool willwork=1;
+                                                                       if(weapons.owner[i]!=-1)
+                                                                               if(player[weapons.owner[i]].weaponstuck!=-1)
+                                                                                       if(player[weapons.owner[i]].weaponids[player[weapons.owner[i]].weaponstuck]==i)
+                                                                                               if(player[weapons.owner[i]].num_weapons>1)willwork=0;
+                                                                       if((/*weapons.velocity[i].x==0&&weapons.velocity[i].y==0&&weapons.velocity[i].z==0&&*/weapons.owner[i]==-1)||(hasvictim&&weapons.owner[i]==victim->id&&victim->skeleton.free))
+                                                                               if(willwork&&findDistancefastflat(&coords,&weapons.position[i])<3&&weaponactive==-1){
+                                                                                       if(findDistancefast(&coords,&weapons.position[i])<1||hasvictim){
+                                                                                               float gLoc[3];
+                                                                                               float vel[3];
+                                                                                               gLoc[0]=coords.x;
+                                                                                               gLoc[1]=coords.y;
+                                                                                               gLoc[2]=coords.z;
+                                                                                               vel[0]=velocity.x;
+                                                                                               vel[1]=velocity.y;
+                                                                                               vel[2]=velocity.z;
+                                                                                               bool fleshstuck=0;
+                                                                                               if(weapons.owner[i]!=-1)
+                                                                                                       if(victim->weaponstuck!=-1){
+                                                                                                               if(victim->weaponids[victim->weaponstuck]==i){
+                                                                                                                       fleshstuck=1;
+                                                                                                               }
+                                                                                                       }
+                                                                                                       if(!fleshstuck){
+                                                                                                               if(weapons.type[i]!=staff){
+                                                                                                                       PlaySoundEx( knifedrawsound, samp[knifedrawsound], NULL, TRUE);
+                                                                                                                       FSOUND_3D_SetAttributes(channels[knifedrawsound], gLoc, vel);
+                                                                                                                       FSOUND_SetVolume(channels[knifedrawsound], 128);
+                                                                                                                       FSOUND_SetPaused(channels[knifedrawsound], FALSE);
+                                                                                                               }
+                                                                                                       }
+                                                                                                       if(fleshstuck){
+                                                                                                               PlaySoundEx( fleshstabremovesound, samp[fleshstabremovesound], NULL, TRUE);
+                                                                                                               FSOUND_3D_SetAttributes(channels[fleshstabremovesound], gLoc, vel);
+                                                                                                               FSOUND_SetVolume(channels[fleshstabremovesound], 128);
+                                                                                                               FSOUND_SetPaused(channels[fleshstabremovesound], FALSE);
+                                                                                                       }
+                                                                                                       weaponactive=0;
+                                                                                                       if(weapons.owner[i]!=-1){
+
+                                                                                                               victim=&player[weapons.owner[i]];
+                                                                                                               if(victim->num_weapons==1)victim->num_weapons=0;
+                                                                                                               else victim->num_weapons=1;
+
+                                                                                                               //victim->weaponactive=-1;
+                                                                                                               victim->skeleton.longdead=0;
+                                                                                                               victim->skeleton.free=1;
+                                                                                                               victim->skeleton.broken=0;
+
+                                                                                                               for(int j=0;j<victim->skeleton.num_joints;j++){
+                                                                                                                       victim->skeleton.joints[j].velchange=0;
+                                                                                                                       victim->skeleton.joints[j].locked=0;
+                                                                                                               }
+
+                                                                                                               XYZ relative;
+                                                                                                               relative=0;
+                                                                                                               relative.y=10;
+                                                                                                               Normalise(&relative);
+                                                                                                               XYZ footvel,footpoint;
+                                                                                                               footvel=0;
+                                                                                                               footpoint=weapons.position[i];
+                                                                                                               if(victim->weaponstuck!=-1){
+                                                                                                                       if(victim->weaponids[victim->weaponstuck]==i){
+                                                                                                                               if(bloodtoggle)sprites.MakeSprite(cloudimpactsprite, footpoint,footvel, 1,0,0, .8, .3);
+                                                                                                                               weapons.bloody[i]=2;
+                                                                                                                               weapons.blooddrip[i]=5;
+                                                                                                                               victim->weaponstuck=-1;
+                                                                                                                       }
+                                                                                                               }
+                                                                                                               if(victim->num_weapons>0){
+                                                                                                                       if(victim->weaponstuck!=0&&victim->weaponstuck!=-1)victim->weaponstuck=0;
+                                                                                                                       if(victim->weaponids[0]==i)
+                                                                                                                               victim->weaponids[0]=victim->weaponids[victim->num_weapons];
+                                                                                                               }
+
+                                                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*6;
+                                                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[neck]].velocity+=relative*6;
+                                                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[rightshoulder]].velocity+=relative*6;
+                                                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[leftshoulder]].velocity+=relative*6;
+                                                                                                       }
+                                                                                                       weapons.owner[i]=id;
+                                                                                                       if(num_weapons>0){
+                                                                                                               weaponids[num_weapons]=weaponids[0];
+                                                                                                       }
+                                                                                                       num_weapons++;
+                                                                                                       weaponids[0]=i;
+                                                                                       }
+                                                                               }
+                                                               }
+                                                       }
+
+                                                       if(currentanimation==drawleftanim&&animation[targetanimation].label[currentframe]==5){
+                                                               if(weaponactive==-1)weaponactive=0;
+                                                               else if(weaponactive==0){
+                                                                       weaponactive=-1;
+                                                                       if(num_weapons==2){
+                                                                               int buffer;
+                                                                               buffer=weaponids[0];
+                                                                               weaponids[0]=weaponids[1];
+                                                                               weaponids[1]=buffer;
+                                                                       }
+                                                               }
+                                                               if(weaponactive==-1){
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=coords.x;
+                                                                       gLoc[1]=coords.y;
+                                                                       gLoc[2]=coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+
+                                                                       PlaySoundEx( knifesheathesound, samp[knifesheathesound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[knifesheathesound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[knifesheathesound], 128);
+                                                                       FSOUND_SetPaused(channels[knifesheathesound], FALSE);   
+                                                               }
+                                                               if(weaponactive!=-1){
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=coords.x;
+                                                                       gLoc[1]=coords.y;
+                                                                       gLoc[2]=coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+
+                                                                       PlaySoundEx( knifedrawsound, samp[knifedrawsound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[knifedrawsound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[knifedrawsound], 128);
+                                                                       FSOUND_SetPaused(channels[knifedrawsound], FALSE);      
+                                                               }
+                                                       }
+
+
+                                                       if((currentanimation==walljumprightkickanim&&targetanimation==walljumprightkickanim)||(currentanimation==walljumpleftkickanim&&targetanimation==walljumpleftkickanim)){
+                                                               XYZ rotatetarget=DoRotation(skeleton.forward,0,rotation,0);
+                                                               Normalise(&rotatetarget);
+                                                               targetrotation=-asin(0-rotatetarget.x);
+                                                               targetrotation*=360/6.28;
+                                                               if(rotatetarget.z<0)targetrotation=180-targetrotation;
+
+                                                               if(targetanimation==walljumprightkickanim)targetrotation+=40;
+                                                               if(targetanimation==walljumpleftkickanim)targetrotation-=40;
+                                                       }
+
+                                                       bool dojumpattack;
+                                                       dojumpattack=0;
+                                                       if((targetanimation==rabbitrunninganim||targetanimation==wolfrunninganim)&&targetframe==3&&(jumpkeydown||attackkeydown||id!=0))dojumpattack=1;
+                                                       if(hasvictim)
+                       if(findDistancefast(&victim->coords,&/*player[i].*/coords)<5&&victim->aitype==gethelptype&&(attackkeydown)&&!victim->skeleton.free&&victim->isRun()&&victim->runninghowlong>=1)dojumpattack=1;                                                  if(!hostile)dojumpattack=0;
+                                                       if(dojumpattack){
+                                                               if((targetanimation==rabbitrunninganim||targetanimation==wolfrunninganim)&&id==0){
+                                                                       targetanimation=rabbittackleanim;
+                                                                       targetframe=0;
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=coords.x;
+                                                                       gLoc[1]=coords.y;
+                                                                       gLoc[2]=coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+
+                                                                       PlaySoundEx( jumpsound, samp[jumpsound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[jumpsound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[jumpsound], 128);
+                                                                       FSOUND_SetPaused(channels[jumpsound], FALSE);
+                                                               }
+
+                                                               float closestdist;
+                                                               closestdist=0;
+                                                               int closestid;
+                                                               closestid=-1;
+                                                               XYZ targetloc;
+                                                               targetloc=velocity;
+                                                               Normalise(&targetloc);
+                                                               targetloc+=coords;
+                                                               for(i=0;i<numplayers;i++){
+                                                                       if(i!=id)
+                                                                               if(findDistancefast(&targetloc,&player[i].coords)<closestdist||closestdist==0){
+                                                                                       closestdist=findDistancefast(&targetloc,&player[i].coords);
+                                                                                       closestid=i;
+                                                                               }
+                                                               }
+                                                               if(closestid!=-1)
+                                                                       if(closestdist<5&&!player[closestid].dead&&animation[player[closestid].targetanimation].height!=lowheight&&player[closestid].targetanimation!=backhandspringanim){
+                                                                               hasvictim=1;
+                                                                               victim=&player[closestid];
+                                                                               coords=victim->coords;
+                                                                               currentanimation=rabbittacklinganim;
+                                                                               targetanimation=rabbittacklinganim;
+                                                                               currentframe=0;
+                                                                               targetframe=1;
+                                                                               XYZ rotatetarget;
+                                                                               if(coords.z!=victim->coords.z||coords.x!=victim->coords.x){
+                                                                                       rotatetarget=coords-victim->coords;
+                                                                                       Normalise(&rotatetarget);
+                                                                                       targetrotation=-asin(0-rotatetarget.x);
+                                                                                       targetrotation*=360/6.28;
+                                                                                       if(rotatetarget.z<0)targetrotation=180-targetrotation;
+                                                                               }
+                                                                               if(targetanimation!=rabbitrunninganim){
+                                                                                       float gLoc[3];
+                                                                                       float vel[3];
+                                                                                       gLoc[0]=coords.x;
+                                                                                       gLoc[1]=coords.y;
+                                                                                       gLoc[2]=coords.z;
+                                                                                       vel[0]=velocity.x;
+                                                                                       vel[1]=velocity.y;
+                                                                                       vel[2]=velocity.z;
+
+                                                                                       PlaySoundEx( jumpsound, samp[jumpsound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[jumpsound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[jumpsound], 128);
+                                                                                       FSOUND_SetPaused(channels[jumpsound], FALSE);
+                                                                               }
+                                                                       }
+                                                       }
+
+                                                       //Move impacts
+                                                       float damagemult=1*power;
+                                                       if(creature==wolftype)damagemult=2.5*power;
+                                                       if(hasvictim){damagemult/=victim->damagetolerance/200;}
+                                                       //if(onfire)damagemult=3;
+                                                       if((animation[targetanimation].attack==normalattack||targetanimation==walljumprightkickanim||targetanimation==walljumpleftkickanim)&&(!feint)&&(victim->skeleton.free!=2||targetanimation==killanim||targetanimation==dropkickanim||targetanimation==crouchstabanim||targetanimation==swordgroundstabanim||targetanimation==staffgroundsmashanim)){
+                                                               if(targetanimation==spinkickanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*3&&3&&animation[victim->targetanimation].height!=lowheight){
+                                                                               escapednum=0;
+                                                                               if(id==0)camerashake+=.4;
+                                                                               if(Random()%2||creature==wolftype){
+                                                                                       victim->spurt=1;
+                                                                                       DoBlood(.2,250);
+                                                                                       if(creature==wolftype)DoBloodBig(0,250);
+                                                                               }
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               if(tutoriallevel!=1){
+                                                                                       PlaySoundEx( heavyimpactsound, samp[heavyimpactsound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[heavyimpactsound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[heavyimpactsound], 128);
+                                                                                       FSOUND_SetPaused(channels[heavyimpactsound], FALSE);
+                                                                               }
+                                                                               if(creature==wolftype){
+                                                                                       PlaySoundEx( clawslicesound, samp[clawslicesound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[clawslicesound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[clawslicesound], 128);
+                                                                                       FSOUND_SetPaused(channels[clawslicesound], FALSE);
+                                                                                       victim->spurt=1;
+                                                                                       victim->DoBloodBig(2/victim->armorhead,175);
+                                                                               }
+                                                                               victim->RagDoll(0);
+                                                                               XYZ relative;
+                                                                               relative=victim->coords-coords;
+                                                                               relative.y=0;
+                                                                               Normalise(&relative);
+                                                                               relative=DoRotation(relative,0,-90,0);
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velocity+=relative*damagemult*40;
+                                                                               }
+                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[head]].velocity+=relative*damagemult*200;
+                                                                               //FootLand(1,2);
+                                                                               victim->Puff(head);
+                                                                               victim->DoDamage(damagemult*100/victim->protectionhead);
+
+                                                                               if(id==0){
+                                                                                       SolidHitBonus();
+                                                                               }
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==wolfslapanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*3&&3&&animation[victim->targetanimation].height!=lowheight){
+                                                                               escapednum=0;
+                                                                               if(id==0)camerashake+=.4;
+                                                                               if(Random()%2||creature==wolftype){
+                                                                                       victim->spurt=1;
+                                                                                       if(creature==wolftype)DoBloodBig(0,235);
+                                                                               }
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               PlaySoundEx( whooshhitsound, samp[whooshhitsound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[whooshhitsound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[whooshhitsound], 512);
+                                                                               FSOUND_SetPaused(channels[whooshhitsound], FALSE);
+                                                                               if(creature==wolftype){
+                                                                                       PlaySoundEx( clawslicesound, samp[clawslicesound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[clawslicesound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[clawslicesound], 128);
+                                                                                       FSOUND_SetPaused(channels[clawslicesound], FALSE);
+                                                                                       victim->spurt=1;
+                                                                                       victim->DoBloodBig(2,175);
+                                                                               }
+                                                                               victim->RagDoll(0);
+                                                                               XYZ relative;
+                                                                               relative=victim->coords-coords;
+                                                                               relative.y=0;
+                                                                               Normalise(&relative);
+                                                                               relative.y-=1;
+                                                                               Normalise(&relative);
+                                                                               relative=DoRotation(relative,0,90,0);
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velocity+=relative*damagemult*20;
+                                                                               }
+                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[head]].velocity+=relative*damagemult*100;
+                                                                               //FootLand(1,2);
+                                                                               victim->Puff(head);
+                                                                               victim->DoDamage(damagemult*50/victim->protectionhead);
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==walljumprightkickanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*3&&animation[victim->targetanimation].height!=lowheight){
+                                                                               escapednum=0;
+                                                                               if(id==0)camerashake+=.4;
+                                                                               victim->spurt=1;
+                                                                               DoBlood(.2,250);
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               if(tutoriallevel!=1){
+                                                                                       PlaySoundEx( heavyimpactsound, samp[heavyimpactsound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[heavyimpactsound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[heavyimpactsound], 160);
+                                                                                       FSOUND_SetPaused(channels[heavyimpactsound], FALSE);
+                                                                               }
+                                                                               if(creature==wolftype){
+                                                                                       PlaySoundEx( clawslicesound, samp[clawslicesound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[clawslicesound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[clawslicesound], 128);
+                                                                                       FSOUND_SetPaused(channels[clawslicesound], FALSE);
+                                                                                       victim->spurt=1;
+                                                                                       victim->DoBloodBig(2/victim->armorhead,175);
+                                                                               }
+                                                                               victim->RagDoll(0);
+                                                                               XYZ relative;
+                                                                               relative=facing;
+                                                                               relative.y=0;
+                                                                               Normalise(&relative);
+                                                                               relative=DoRotation(relative,0,-90,0);
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velocity+=relative*damagemult*40;
+                                                                               }
+                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[head]].velocity+=relative*damagemult*200;
+                                                                               //FootLand(1,2);
+                                                                               victim->Puff(head);
+                                                                               victim->DoDamage(damagemult*150/victim->protectionhead);
+
+                                                                               if(victim->damage>victim->damagetolerance){
+                                                                                       if(id==0){
+                                                                                               bonus=style;
+                                                                                               bonustime=0;
+                                                                                               bonusvalue=150;
+                                                                                       }
+                                                                               }
+                                                                               else if(id==0){
+                                                                                       SolidHitBonus();
+                                                                               }
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==walljumpleftkickanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*3&&animation[victim->targetanimation].height!=lowheight){
+                                                                               escapednum=0;
+                                                                               if(id==0)camerashake+=.4;
+                                                                               victim->spurt=1;
+                                                                               DoBlood(.2,250);
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               if(tutoriallevel!=1){
+                                                                                       PlaySoundEx( heavyimpactsound, samp[heavyimpactsound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[heavyimpactsound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[heavyimpactsound], 160);
+                                                                                       FSOUND_SetPaused(channels[heavyimpactsound], FALSE);
+                                                                               }
+                                                                               if(creature==wolftype){
+                                                                                       PlaySoundEx( clawslicesound, samp[clawslicesound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[clawslicesound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[clawslicesound], 128);
+                                                                                       FSOUND_SetPaused(channels[clawslicesound], FALSE);
+                                                                                       victim->spurt=1;
+                                                                                       victim->DoBloodBig(2/victim->armorhead,175);
+                                                                               }
+                                                                               victim->RagDoll(0);
+                                                                               XYZ relative;
+                                                                               relative=facing;
+                                                                               relative.y=0;
+                                                                               Normalise(&relative);
+                                                                               relative=DoRotation(relative,0,90,0);
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velocity+=relative*damagemult*40;
+                                                                               }
+                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[head]].velocity+=relative*damagemult*200;
+                                                                               //FootLand(1,2);
+                                                                               victim->Puff(head);
+                                                                               victim->DoDamage(damagemult*150/victim->protectionhead);
+
+                                                                               if(victim->damage>victim->damagetolerance){
+                                                                                       if(id==0){
+                                                                                               bonus=style;
+                                                                                               bonustime=0;
+                                                                                               bonusvalue=150;
+                                                                                       }
+                                                                               }
+                                                                               else if(id==0){
+                                                                                       SolidHitBonus();
+                                                                               }
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==blockhighleftstrikeanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*3&&animation[victim->targetanimation].height!=lowheight){
+                                                                               escapednum=0;
+                                                                               if(id==0)camerashake+=.4;
+                                                                               if(Random()%2){
+                                                                                       victim->spurt=1;
+                                                                                       DoBlood(.2,235);
+                                                                               }
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               PlaySoundEx( whooshhitsound, samp[whooshhitsound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[whooshhitsound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[whooshhitsound], 512);
+                                                                               FSOUND_SetPaused(channels[whooshhitsound], FALSE);
+                                                                               victim->RagDoll(0);
+                                                                               XYZ relative;
+                                                                               relative=victim->coords-coords;
+                                                                               relative.y=0;
+                                                                               Normalise(&relative);
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velocity+=relative*damagemult*30;
+                                                                               }
+                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[head]].velocity+=relative*damagemult*100;
+                                                                               //FootLand(1,2);
+                                                                               victim->Puff(head);
+                                                                               victim->DoDamage(damagemult*50/victim->protectionhead);
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==killanim&&animation[targetanimation].label[currentframe]==8){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*3&&victim->dead){
+                                                                               escapednum=0;
+                                                                               if(id==0)camerashake+=.2;
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               /*PlaySoundEx( landsound2, samp[landsound2], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[landsound2], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[landsound2], 128);
+                                                                               FSOUND_SetPaused(channels[landsound2], FALSE);
+                                                                               */
+                                                                               PlaySoundEx( movewhooshsound, samp[movewhooshsound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[movewhooshsound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[movewhooshsound], 128);
+                                                                               FSOUND_SetPaused(channels[movewhooshsound], FALSE);
+
+                                                                               victim->skeleton.longdead=0;
+                                                                               victim->skeleton.free=1;
+                                                                               victim->skeleton.broken=0;
+                                                                               victim->skeleton.spinny=1;
+
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velchange=0;
+                                                                                       victim->skeleton.joints[i].delay=0;
+                                                                                       victim->skeleton.joints[i].locked=0;
+                                                                                       //victim->skeleton.joints[i].velocity=0;
+                                                                               }
+
+                                                                               XYZ relative;
+                                                                               relative=0;
+                                                                               relative.y=1;
+                                                                               Normalise(&relative);
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velocity.y=relative.y*10;
+                                                                                       victim->skeleton.joints[i].position.y+=relative.y*.3;
+                                                                                       victim->skeleton.joints[i].oldposition.y+=relative.y*.3;
+                                                                                       victim->skeleton.joints[i].realoldposition.y+=relative.y*.3;
+                                                                               }
+                                                                               victim->Puff(abdomen);
+                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity.y=relative.y*400;
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==killanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*9&&victim->dead){
+                                                                               escapednum=0;
+                                                                               if(id==0)camerashake+=.4;
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=coords.x;
+                                                                               gLoc[1]=coords.y;
+                                                                               gLoc[2]=coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               if(tutoriallevel!=1){
+                                                                                       PlaySoundEx( heavyimpactsound, samp[heavyimpactsound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[heavyimpactsound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[heavyimpactsound], 128);
+                                                                                       FSOUND_SetPaused(channels[heavyimpactsound], FALSE);
+                                                                               }
+                                                                               XYZ relative;
+                                                                               relative=victim->coords-coords;
+                                                                               relative.y=0;
+                                                                               Normalise(&relative);
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velocity+=relative*damagemult*90;
+                                                                               }
+                                                                               victim->Puff(abdomen);
+                                                                               if(victim->dead!=2&&victim->permanentdamage>victim->damagetolerance-250&&autoslomo){
+                                                                                       slomo=1;
+                                                                                       slomodelay=.2;
+                                                                               }
+                                                                               victim->DoDamage(damagemult*500/victim->protectionhigh);
+                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*damagemult*300;
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==dropkickanim&&animation[targetanimation].label[currentframe]==7){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*9&&victim->skeleton.free){
+                                                                               escapednum=0;
+                                                                               if(id==0)camerashake+=.4;
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=coords.x;
+                                                                               gLoc[1]=coords.y;
+                                                                               gLoc[2]=coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               if(tutoriallevel!=1){
+                                                                                       PlaySoundEx( thudsound, samp[thudsound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[thudsound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[thudsound], 400);
+                                                                                       FSOUND_SetPaused(channels[thudsound], FALSE);
+                                                                               }
+
+                                                                               victim->skeleton.longdead=0;
+                                                                               victim->skeleton.free=1;
+                                                                               victim->skeleton.broken=0;
+                                                                               victim->skeleton.spinny=1;
+
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velchange=0;
+                                                                                       //victim->skeleton.joints[i].delay=0;
+                                                                                       victim->skeleton.joints[i].locked=0;
+                                                                               }
+                                                                               XYZ relative;
+                                                                               relative=victim->coords-coords;
+                                                                               Normalise(&relative);
+                                                                               relative.y+=.3;
+                                                                               Normalise(&relative);
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velocity+=relative*damagemult*20;
+                                                                               }
+                                                                               if(id==0&&!victim->dead){
+                                                                                       SolidHitBonus();
+                                                                               }
+
+                                                                               victim->Puff(abdomen);
+                                                                               victim->DoDamage(damagemult*20/victim->protectionhigh);
+                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*damagemult*200;
+                                                                               staggerdelay=.5;
+                                                                               if(!victim->dead)staggerdelay=1.2;
+
+
+                                                                       }
+                                                               }
+
+                                                               if((targetanimation==crouchstabanim||targetanimation==swordgroundstabanim)&&animation[targetanimation].label[currentframe]==5){
+                                                                       // if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*9){
+                                                                       //if(id==0)camerashake+=.4;
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=coords.x;
+                                                                       gLoc[1]=coords.y;
+                                                                       gLoc[2]=coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+
+                                                                       if(hasvictim)
+                                                                               if(!victim->skeleton.free)hasvictim=0;
+
+                                                                       if(!hasvictim){
+                                                                               terrain.MakeDecal(blooddecalfast,(weapons.tippoint[weaponids[weaponactive]]*.8+weapons.position[weaponids[weaponactive]]*.2),.08,.6,Random()%360);
+                                                                               PlaySoundEx( knifesheathesound, samp[knifesheathesound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[knifesheathesound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[knifesheathesound], 128);
+                                                                               FSOUND_SetPaused(channels[knifesheathesound], FALSE);
+                                                                       }
+
+                                                                       if(victim&&hasvictim){
+                                                                               if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*3){
+
+                                                                                       XYZ where,startpoint,endpoint,movepoint,colpoint;
+                                                                                       float rotationpoint;
+                                                                                       int whichtri;
+                                                                                       if(weapons.type[weaponids[weaponactive]]==knife){
+                                                                                               where=(weapons.tippoint[weaponids[weaponactive]]*.6+weapons.position[weaponids[weaponactive]]*.4);
+                                                                                               where-=victim->coords;
+                                                                                               if(!victim->skeleton.free)where=DoRotation(where,0,-victim->rotation,0);
+                                                                                               //where=scale;
+                                                                                               startpoint=where;
+                                                                                               startpoint.y+=100;
+                                                                                               endpoint=where;
+                                                                                               endpoint.y-=100;
+                                                                                       }
+                                                                                       if(weapons.type[weaponids[weaponactive]]==sword){
+                                                                                               where=weapons.position[weaponids[weaponactive]];
+                                                                                               where-=victim->coords;
+                                                                                               if(!victim->skeleton.free)where=DoRotation(where,0,-victim->rotation,0);
+                                                                                               startpoint=where;
+                                                                                               where=weapons.tippoint[weaponids[weaponactive]];
+                                                                                               where-=victim->coords;
+                                                                                               if(!victim->skeleton.free)where=DoRotation(where,0,-victim->rotation,0);
+                                                                                               endpoint=where;
+                                                                                       }
+                                                                                       if(weapons.type[weaponids[weaponactive]]==staff){
+                                                                                               where=weapons.position[weaponids[weaponactive]];
+                                                                                               where-=victim->coords;
+                                                                                               if(!victim->skeleton.free)where=DoRotation(where,0,-victim->rotation,0);
+                                                                                               startpoint=where;
+                                                                                               where=weapons.tippoint[weaponids[weaponactive]];
+                                                                                               where-=victim->coords;
+                                                                                               if(!victim->skeleton.free)where=DoRotation(where,0,-victim->rotation,0);
+                                                                                               endpoint=where;
+                                                                                       }
+                                                                                       movepoint=0;
+                                                                                       rotationpoint=0;
+                                                                                       whichtri=victim->skeleton.drawmodel.LineCheck(&startpoint,&endpoint, &colpoint, &movepoint, &rotationpoint);
+
+                                                                                       if(whichtri!=-1){
+                                                                                               if(victim->dead!=2){
+                                                                                                       victim->DoDamage(abs((victim->damagetolerance-victim->permanentdamage)*2));
+                                                                                                       if(id==0&&!victim->dead){
+                                                                                                               bonus=FinishedBonus;
+                                                                                                               bonustime=0;
+                                                                                                               bonusvalue=200;
+                                                                                                       }
+                                                                                               }
+                                                                                               if(bloodtoggle)weapons.bloody[weaponids[weaponactive]]=2;
+
+                                                                                               victim->skeleton.longdead=0;
+                                                                                               victim->skeleton.free=1;
+                                                                                               victim->skeleton.broken=0;
+
+                                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                                       victim->skeleton.joints[i].velchange=0;
+                                                                                                       victim->skeleton.joints[i].locked=0;
+                                                                                                       //victim->skeleton.joints[i].velocity=0;
+                                                                                               }
+                                                                                               PlaySoundEx( fleshstabsound, samp[fleshstabsound], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[fleshstabsound], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[fleshstabsound], 128);
+                                                                                               FSOUND_SetPaused(channels[fleshstabsound], FALSE);
+
+                                                                                       }
+                                                                                       if(whichtri!=-1||weapons.bloody[weaponids[weaponactive]]){
+                                                                                               weapons.blooddrip[weaponids[weaponactive]]+=5;
+                                                                                               weapons.blooddripdelay[weaponids[weaponactive]]=0;
+                                                                                       }
+                                                                                       if(whichtri==-1){
+                                                                                               hasvictim=0;
+                                                                                               PlaySoundEx( knifesheathesound, samp[knifesheathesound], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[knifesheathesound], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[knifesheathesound], 128);
+                                                                                               FSOUND_SetPaused(channels[knifesheathesound], FALSE);                                                           
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                               }
+
+                                                               if((targetanimation==crouchstabanim||targetanimation==swordgroundstabanim)&&animation[targetanimation].label[currentframe]==6){
+                                                                       // if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*9){
+                                                                       //if(id==0)camerashake+=.4;
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=coords.x;
+                                                                       gLoc[1]=coords.y;
+                                                                       gLoc[2]=coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+                                                                       if(!hasvictim){
+                                                                               PlaySoundEx( knifedrawsound, samp[knifedrawsound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[knifedrawsound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[knifedrawsound], 128);
+                                                                               FSOUND_SetPaused(channels[knifedrawsound], FALSE);                                                      
+                                                                       }
+
+                                                                       if(victim&&hasvictim){
+                                                                               XYZ footvel,footpoint;  
+
+                                                                               PlaySoundEx( fleshstabremovesound, samp[fleshstabremovesound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[fleshstabremovesound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[fleshstabremovesound], 128);
+                                                                               FSOUND_SetPaused(channels[fleshstabremovesound], FALSE);
+
+                                                                               footvel=0;
+                                                                               footpoint=(weapons.tippoint[weaponids[weaponactive]]*.8+weapons.position[weaponids[weaponactive]]*.2);
+
+                                                                               if(weapons.type[weaponids[weaponactive]]==sword){
+                                                                                       XYZ where,startpoint,endpoint,movepoint;
+                                                                                       float rotationpoint;
+                                                                                       int whichtri;
+
+                                                                                       where=weapons.position[weaponids[weaponactive]];
+                                                                                       where-=victim->coords;
+                                                                                       if(!victim->skeleton.free)where=DoRotation(where,0,-victim->rotation,0);
+                                                                                       startpoint=where;
+                                                                                       where=weapons.tippoint[weaponids[weaponactive]];
+                                                                                       where-=victim->coords;
+                                                                                       if(!victim->skeleton.free)where=DoRotation(where,0,-victim->rotation,0);
+                                                                                       endpoint=where;
+
+                                                                                       movepoint=0;
+                                                                                       rotationpoint=0;
+                                                                                       whichtri=victim->skeleton.drawmodel.LineCheck(&startpoint,&endpoint, &footpoint, &movepoint, &rotationpoint);
+                                                                                       footpoint+=victim->coords;
+
+                                                                                       if(whichtri==-1){
+                                                                                               footpoint=(weapons.tippoint[weaponids[weaponactive]]*.8+weapons.position[weaponids[weaponactive]]*.2);
+                                                                                       }
+                                                                               }
+                                                                               if(weapons.type[weaponids[weaponactive]]==staff){
+                                                                                       XYZ where,startpoint,endpoint,movepoint;
+                                                                                       float rotationpoint;
+                                                                                       int whichtri;
+
+                                                                                       where=weapons.position[weaponids[weaponactive]];
+                                                                                       where-=victim->coords;
+                                                                                       if(!victim->skeleton.free)where=DoRotation(where,0,-victim->rotation,0);
+                                                                                       startpoint=where;
+                                                                                       where=weapons.tippoint[weaponids[weaponactive]];
+                                                                                       where-=victim->coords;
+                                                                                       if(!victim->skeleton.free)where=DoRotation(where,0,-victim->rotation,0);
+                                                                                       endpoint=where;
+
+                                                                                       movepoint=0;
+                                                                                       rotationpoint=0;
+                                                                                       whichtri=victim->skeleton.drawmodel.LineCheck(&startpoint,&endpoint, &footpoint, &movepoint, &rotationpoint);
+                                                                                       footpoint+=victim->coords;
+
+                                                                                       if(whichtri==-1){
+                                                                                               footpoint=(weapons.tippoint[weaponids[weaponactive]]*.8+weapons.position[weaponids[weaponactive]]*.2);
+                                                                                       }
+                                                                               }
+                                                                               hasvictim=victim->DoBloodBigWhere(2,220,footpoint);
+                                                                               if(hasvictim){
+                                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*3){
+                                                                                               victim->skeleton.longdead=0;
+                                                                                               victim->skeleton.free=1;
+                                                                                               victim->skeleton.broken=0;
+
+                                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                                       victim->skeleton.joints[i].velchange=0;
+                                                                                                       victim->skeleton.joints[i].locked=0;                                                            
+                                                                                                       //victim->skeleton.joints[i].velocity=0;
+                                                                                               }
+
+                                                                                               XYZ relative;
+                                                                                               relative=0;
+                                                                                               relative.y=10;
+                                                                                               Normalise(&relative);
+                                                                                               //victim->Puff(abdomen);
+                                                                                               if(bloodtoggle)sprites.MakeSprite(cloudimpactsprite, footpoint,footvel, 1,0,0, .8, .3);
+
+                                                                                               if(victim->bloodloss<victim->damagetolerance){
+                                                                                                       victim->bloodloss+=1000;
+                                                                                                       victim->bled=0;
+                                                                                               }
+
+                                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*damagemult*20;
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                                       if(!hasvictim&&onterrain){
+                                                                               weapons.bloody[weaponids[weaponactive]]=0;
+                                                                               weapons.blooddrip[weaponids[weaponactive]]=0;
+                                                                       }                                       
+                                                               }
+
+                                                               if(targetanimation==upunchanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*3){
+                                                                               escapednum=0;
+                                                                               if(id==0)camerashake+=.4;
+                                                                               if(Random()%2){
+                                                                                       victim->spurt=1;
+                                                                                       DoBlood(.2,235);
+                                                                               }
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               //if(!victim->isIdle()||victim->damage>victim->damagetolerance-60){
+                                                                               if(1==1){
+                                                                                       if(tutoriallevel!=1){
+                                                                                               PlaySoundEx( heavyimpactsound, samp[heavyimpactsound], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[heavyimpactsound], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[heavyimpactsound], 128);
+                                                                                               FSOUND_SetPaused(channels[heavyimpactsound], FALSE);
+                                                                                       }
+                                                                               }
+                                                                               else {
+                                                                                       if(tutoriallevel!=1){
+                                                                                               PlaySoundEx( landsound2, samp[landsound2], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[landsound2], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[landsound2], 256);
+                                                                                               FSOUND_SetPaused(channels[landsound2], FALSE);                                                  
+                                                                                       }
+                                                                               }
+
+                                                                               //if(!victim->isIdle()||victim->damage>victim->damagetolerance-60)
+                                                                               victim->RagDoll(0);
+                                                                               XYZ relative;
+                                                                               relative=victim->coords-coords;
+                                                                               relative.y=0;
+                                                                               Normalise(&relative);
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velocity=relative*30;
+                                                                               }
+                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[head]].velocity+=relative*damagemult*150;
+
+                                                                               victim->targetframe=0;
+                                                                               victim->targetanimation=staggerbackhardanim;
+                                                                               victim->targetrotation=targetrotation+180;
+                                                                               victim->target=0;
+                                                                               victim->stunned=1;
+
+                                                                               victim->Puff(head);
+                                                                               victim->Puff(abdomen);
+                                                                               victim->DoDamage(damagemult*60/victim->protectionhigh);
+
+                                                                               if(id==0){
+                                                                                       SolidHitBonus();
+                                                                               }
+                                                                       }
+                                                               }
+
+
+                                                               if(targetanimation==winduppunchanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*2){
+                                                                               escapednum=0;
+                                                                               if(id==0)camerashake+=.4;
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               //if(!victim->isIdle()||victim->damage>victim->damagetolerance-60){
+                                                                               if(victim->damage<=victim->damagetolerance-60&&normaldotproduct(victim->facing,victim->coords-coords)<(scale*5)*(scale*5)*0&&animation[victim->targetanimation].height!=lowheight){
+                                                                                       if(tutoriallevel!=1){
+                                                                                               PlaySoundEx( thudsound, samp[thudsound], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[thudsound], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[thudsound], 512);
+                                                                                               FSOUND_SetPaused(channels[thudsound], FALSE);
+                                                                                       }
+                                                                               }
+                                                                               else if(victim->damage<=victim->damagetolerance-60&&normaldotproduct(victim->facing,victim->coords-coords)<(scale*5)*(scale*5)*0&&animation[victim->targetanimation].height==lowheight){
+                                                                                       if(tutoriallevel!=1){
+                                                                                               PlaySoundEx( whooshhitsound, samp[whooshhitsound], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[whooshhitsound], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[whooshhitsound], 512);
+                                                                                               FSOUND_SetPaused(channels[whooshhitsound], FALSE);
+                                                                                       }
+                                                                               }
+                                                                               else {
+                                                                                       if(tutoriallevel!=1){
+                                                                                               PlaySoundEx( heavyimpactsound, samp[heavyimpactsound], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[heavyimpactsound], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[heavyimpactsound], 256);
+                                                                                               FSOUND_SetPaused(channels[heavyimpactsound], FALSE);
+                                                                                       }                                                       
+                                                                               }
+
+                                                                               if(victim->damage>victim->damagetolerance-60||normaldotproduct(victim->facing,victim->coords-coords)>0||animation[victim->targetanimation].height==lowheight)
+                                                                                       victim->RagDoll(0);
+                                                                               XYZ relative;
+                                                                               relative=victim->coords-coords;
+                                                                               relative.y=0;
+                                                                               Normalise(&relative);
+                                                                               relative.y=.3;
+                                                                               Normalise(&relative);
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velocity=relative*5;
+                                                                               }
+                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*damagemult*400;
+
+                                                                               victim->targetframe=0;
+                                                                               victim->targetanimation=staggerbackhardanim;
+                                                                               victim->targetrotation=targetrotation+180;
+                                                                               victim->target=0;
+                                                                               victim->stunned=1;
+
+                                                                               victim->Puff(abdomen);
+                                                                               victim->DoDamage(damagemult*60/victim->protectionhigh);
+
+                                                                               if(id==0){
+                                                                                       SolidHitBonus();
+                                                                               }
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==blockhighleftanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*4){
+                                                                               if(victim->id==0)camerashake+=.4;
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+
+                                                                               PlaySoundEx( landsound2, samp[landsound2], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[landsound2], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[landsound2], 256);
+                                                                               FSOUND_SetPaused(channels[landsound2], FALSE);
+
+                                                                               Puff(righthand);
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==swordslashparryanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*4){
+                                                                               if(victim->id==0)camerashake+=.4;
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+
+                                                                               if(weaponactive!=-1){
+                                                                                       if(weapons.type[victim->weaponids[0]]==staff||weapons.type[weaponids[0]]==staff){
+                                                                                               if(weapons.type[victim->weaponids[0]]==staff)weapons.damage[victim->weaponids[0]]+=.2+float(abs(Random()%100)-50)/250;
+                                                                                               if(weapons.type[weaponids[0]]==staff)weapons.damage[weaponids[0]]+=.2+float(abs(Random()%100)-50)/250;
+
+                                                                                               PlaySoundEx( swordstaffsound, samp[swordstaffsound], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[swordstaffsound], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[swordstaffsound], 512);
+                                                                                               FSOUND_SetPaused(channels[swordstaffsound], FALSE);
+                                                                                       }
+                                                                                       else{
+                                                                                               PlaySoundEx( metalhitsound, samp[metalhitsound], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[metalhitsound], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[metalhitsound], 512);
+                                                                                               FSOUND_SetPaused(channels[metalhitsound], FALSE);
+                                                                                       }
+                                                                               }
+
+                                                                               //Puff(righthand);
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==knifethrowanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(weaponactive!=-1){
+                                                                               escapednum=0;
+                                                                               XYZ aim;
+                                                                               weapons.owner[weaponids[0]]=-1;
+                                                                               aim=victim->coords+DoRotation(victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].position,0,victim->rotation,0)*victim->scale+victim->velocity*findDistance(&victim->coords,&coords)/50-(coords+DoRotation(skeleton.joints[skeleton.jointlabels[righthand]].position,0,rotation,0)*scale);                                          
+                                                                               Normalise(&aim);
+                                                                               /*if(victim->targetanimation==jumpupanim||victim->targetanimation==jumpdownanim){
+                                                                               aim=DoRotation(aim,(float)abs(Random()%15)-7,(float)abs(Random()%15)-7,0);
+                                                                               }*/
+                                                                               weapons.velocity[weaponids[0]]=aim*50;
+                                                                               weapons.tipvelocity[weaponids[0]]=aim*50;
+                                                                               weapons.missed[weaponids[0]]=0;
+                                                                               weapons.hitsomething[weaponids[0]]=0;
+                                                                               weapons.freetime[weaponids[0]]=0;
+                                                                               weapons.firstfree[weaponids[0]]=1;
+                                                                               weapons.physics[weaponids[0]]=0;
+                                                                               num_weapons--;
+                                                                               if(num_weapons){
+                                                                                       weaponids[0]=weaponids[num_weapons];
+                                                                               }
+                                                                               weaponactive=-1;
+                                                                       }               
+                                                               }
+
+                                                               if(targetanimation==knifeslashstartanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(hasvictim)
+                                                                               if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*4.5&&/*animation[victim->targetanimation].height!=lowheight&&*/victim->targetanimation!=dodgebackanim&&victim->targetanimation!=rollanim){
+                                                                                       escapednum=0;
+                                                                                       //if(Random()%2){
+                                                                                       if(tutoriallevel!=1)victim->DoBloodBig(1.5/victim->armorhigh,225);
+                                                                                       //}
+
+                                                                                       if(id==0){
+                                                                                               bonus=Slicebonus;
+                                                                                               bonustime=0;
+                                                                                               bonusvalue=10;
+                                                                                       }
+                                                                                       if(tutoriallevel!=1){
+                                                                                               float gLoc[3];
+                                                                                               float vel[3];
+                                                                                               gLoc[0]=victim->coords.x;
+                                                                                               gLoc[1]=victim->coords.y;
+                                                                                               gLoc[2]=victim->coords.z;
+                                                                                               vel[0]=velocity.x;
+                                                                                               vel[1]=velocity.y;
+                                                                                               vel[2]=velocity.z;
+                                                                                               PlaySoundEx( knifeslicesound, samp[knifeslicesound], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[knifeslicesound], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[knifeslicesound], 512);
+                                                                                               FSOUND_SetPaused(channels[knifeslicesound], FALSE);
+                                                                                       }
+                                                                                       //victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*damagemult*200;
+                                                                                       if(animation[victim->targetanimation].attack&&(victim->aitype!=playercontrolled||victim->targetanimation==knifeslashstartanim)&&(victim->creature==rabbittype||victim->deathbleeding<=0)){
+                                                                                               if(victim->id != 0 || difficulty==2){
+                                                                                                       victim->targetframe=0;
+                                                                                                       victim->targetanimation=staggerbackhardanim;
+                                                                                                       victim->targetrotation=targetrotation+180;
+                                                                                                       victim->target=0;
+                                                                                               }
+                                                                                       }
+                                                                                       victim->lowreversaldelay=0;
+                                                                                       victim->highreversaldelay=0;
+                                                                                       if(aitype!=playercontrolled)weaponmissdelay=.6;
+
+                                                                                       if(tutoriallevel!=1)if(bloodtoggle&&!weapons.bloody[weaponids[weaponactive]])weapons.bloody[weaponids[weaponactive]]=1;
+                                                                                       if(tutoriallevel!=1)weapons.blooddrip[weaponids[weaponactive]]+=3;
+
+                                                                                       XYZ footvel,footpoint;  
+                                                                                       footvel=0;
+                                                                                       if(skeleton.free){
+                                                                                               footpoint=(victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].position+victim->skeleton.joints[victim->skeleton.jointlabels[neck]].position)/2*victim->scale+victim->coords;
+                                                                                       }
+                                                                                       if(!skeleton.free){
+                                                                                               footpoint=DoRotation((victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].position+victim->skeleton.joints[victim->skeleton.jointlabels[neck]].position)/2,0,victim->rotation,0)*victim->scale+victim->coords;
+                                                                                       }               
+                                                                                       if(tutoriallevel!=1){
+                                                                                               if(bloodtoggle)sprites.MakeSprite(cloudimpactsprite, footpoint,footvel, 1,0,0, .6, .3);
+                                                                                               footvel=DoRotation(facing,0,90,0)*.8;
+                                                                                               //footvel.y-=.3;
+                                                                                               sprites.MakeSprite(bloodsprite,footpoint,DoRotation(footvel*7,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .05, .9);
+                                                                                               sprites.MakeSprite(bloodsprite,footpoint,DoRotation(footvel*3,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .05, .9);
+                                                                                               sprites.MakeSprite(bloodflamesprite, footpoint,footvel*5, 1,1,1, .2, 1);
+                                                                                               sprites.MakeSprite(bloodflamesprite, footpoint,footvel*2, 1,1,1, .2, 1);
+                                                                                       }
+                                                                                       if(tutoriallevel==1){
+                                                                                               sprites.MakeSprite(cloudimpactsprite, footpoint,footvel, 1,1,1, .6, .3);
+                                                                                       }
+                                                                                       victim->DoDamage(damagemult*0);
+                                                                               }
+                                                               }
+                                                               if(targetanimation==swordslashanim&&animation[targetanimation].label[currentframe]==5&&victim->targetanimation!=rollanim){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*6.5&&victim->targetanimation!=dodgebackanim){
+                                                                               if(victim->weaponactive==-1||normaldotproduct(victim->facing,victim->coords-coords)>0||(Random()%2==0)){
+                                                                                       if(id==0){
+                                                                                               bonus=Slashbonus;
+                                                                                               bonustime=0;
+                                                                                               bonusvalue=40;
+                                                                                       }
+                                                                                       escapednum=0; 
+                                                                                       if(tutoriallevel!=1){
+                                                                                               if(normaldotproduct(victim->facing,victim->coords-coords)<0)victim->DoBloodBig(2/victim->armorhigh,190);
+                                                                                               else victim->DoBloodBig(2/victim->armorhigh,185);
+                                                                                               victim->deathbleeding=1;
+                                                                                               float gLoc[3];
+                                                                                               float vel[3];
+                                                                                               gLoc[0]=victim->coords.x;
+                                                                                               gLoc[1]=victim->coords.y;
+                                                                                               gLoc[2]=victim->coords.z;
+                                                                                               vel[0]=velocity.x;
+                                                                                               vel[1]=velocity.y;
+                                                                                               vel[2]=velocity.z;
+                                                                                               PlaySoundEx( swordslicesound, samp[swordslicesound], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[swordslicesound], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[swordslicesound], 512);
+                                                                                               FSOUND_SetPaused(channels[swordslicesound], FALSE);
+                                                                                       }
+                                                                                       //victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*damagemult*200;
+                                                                                       //if(animation[victim->targetanimation].attack){
+                                                                                       //if(victim->creature==rabbittype){
+                                                                                       if(tutoriallevel!=1){
+                                                                                               victim->targetframe=0;
+                                                                                               victim->targetanimation=staggerbackhardanim;
+                                                                                               victim->targetrotation=targetrotation+180;
+                                                                                               victim->target=0;
+                                                                                       }
+                                                                                       //}
+                                                                                       //}
+
+                                                                                       if(tutoriallevel!=1){
+                                                                                               if(bloodtoggle&&!weapons.bloody[weaponids[weaponactive]])weapons.bloody[weaponids[weaponactive]]=1;
+                                                                                               weapons.blooddrip[weaponids[weaponactive]]+=3;
+
+                                                                                               float bloodlossamount;
+                                                                                               bloodlossamount=200+abs((float)(Random()%40))-20;
+                                                                                               victim->bloodloss+=bloodlossamount/victim->armorhigh;
+                                                                                               //victim->bloodloss+=100*(6.5-findDistancefast(&coords,&victim->coords));
+                                                                                               victim->DoDamage(damagemult*0);
+
+                                                                                               XYZ footvel,footpoint;  
+                                                                                               footvel=0;
+                                                                                               if(skeleton.free){
+                                                                                                       footpoint=(victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].position+victim->skeleton.joints[victim->skeleton.jointlabels[neck]].position)/2*victim->scale+victim->coords;
+                                                                                               }
+                                                                                               if(!skeleton.free){
+                                                                                                       footpoint=DoRotation((victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].position+victim->skeleton.joints[victim->skeleton.jointlabels[neck]].position)/2,0,victim->rotation,0)*victim->scale+victim->coords;
+                                                                                               }               
+                                                                                               if(bloodtoggle)sprites.MakeSprite(cloudimpactsprite, footpoint,footvel, 1,0,0, .9, .3);
+                                                                                               footvel=DoRotation(facing,0,90,0)*.8;
+                                                                                               footvel.y-=.3;
+                                                                                               sprites.MakeSprite(bloodsprite,footpoint,DoRotation(footvel*7,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .05, .9);
+                                                                                               sprites.MakeSprite(bloodsprite,footpoint,DoRotation(footvel*3,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .05, .9);
+                                                                                               sprites.MakeSprite(bloodflamesprite, footpoint,footvel*5, 1,1,1, .3, 1);
+                                                                                               sprites.MakeSprite(bloodflamesprite, footpoint,footvel*2, 1,1,1, .3, 1);
+                                                                                       }
+                                                                               }
+                                                                               else {
+
+
+                                                                                       float gLoc[3];
+                                                                                       float vel[3];
+                                                                                       gLoc[0]=victim->coords.x;
+                                                                                       gLoc[1]=victim->coords.y;
+                                                                                       gLoc[2]=victim->coords.z;
+                                                                                       vel[0]=velocity.x;
+                                                                                       vel[1]=velocity.y;
+                                                                                       vel[2]=velocity.z;
+                                                                                       if(victim->weaponactive!=-1){
+                                                                                               if(weapons.type[victim->weaponids[0]]==staff||weapons.type[weaponids[0]]==staff){
+                                                                                                       if(weapons.type[victim->weaponids[0]]==staff)weapons.damage[victim->weaponids[0]]+=.2+float(abs(Random()%100)-50)/250;
+                                                                                                       if(weapons.type[weaponids[0]]==staff)weapons.damage[weaponids[0]]+=.2+float(abs(Random()%100)-50)/250;
+
+                                                                                                       PlaySoundEx( swordstaffsound, samp[swordstaffsound], NULL, TRUE);
+                                                                                                       FSOUND_3D_SetAttributes(channels[swordstaffsound], gLoc, vel);
+                                                                                                       FSOUND_SetVolume(channels[swordstaffsound], 512);
+                                                                                                       FSOUND_SetPaused(channels[swordstaffsound], FALSE);
+                                                                                               }
+                                                                                               else{
+                                                                                                       PlaySoundEx( metalhitsound, samp[metalhitsound], NULL, TRUE);
+                                                                                                       FSOUND_3D_SetAttributes(channels[metalhitsound], gLoc, vel);
+                                                                                                       FSOUND_SetVolume(channels[metalhitsound], 512);
+                                                                                                       FSOUND_SetPaused(channels[metalhitsound], FALSE);
+                                                                                               }
+                                                                                       }
+
+
+                                                                                       XYZ aim;
+                                                                                       victim->Puff(righthand);
+                                                                                       victim->target=0;
+                                                                                       victim->targetframe=0;
+                                                                                       victim->targetanimation=staggerbackhighanim;
+                                                                                       victim->targetrotation=targetrotation+180;
+                                                                                       victim->target=0;
+                                                                                       weapons.owner[victim->weaponids[0]]=-1;
+                                                                                       aim=DoRotation(facing,0,90,0)*21;
+                                                                                       aim.y+=7;
+                                                                                       weapons.velocity[victim->weaponids[0]]=aim*-.2;
+                                                                                       weapons.tipvelocity[victim->weaponids[0]]=aim;
+                                                                                       weapons.missed[victim->weaponids[0]]=1;
+                                                                                       weapons.hitsomething[weaponids[0]]=0;
+                                                                                       weapons.freetime[victim->weaponids[0]]=0;
+                                                                                       weapons.firstfree[victim->weaponids[0]]=1;
+                                                                                       weapons.physics[victim->weaponids[0]]=1;
+                                                                                       victim->num_weapons--;
+                                                                                       if(victim->num_weapons){
+                                                                                               victim->weaponids[0]=victim->weaponids[num_weapons];
+                                                                                               if(victim->weaponstuck==victim->num_weapons)victim->weaponstuck=0;
+                                                                                       }
+                                                                                       victim->weaponactive=-1;
+                                                                                       for(i=0;i<numplayers;i++){
+                                                                                               player[i].wentforweapon=0;
+                                                                                       }
+
+                                                                                       /*PlaySoundEx( metalhitsound, samp[metalhitsound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[metalhitsound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[metalhitsound], 512);
+                                                                                       FSOUND_SetPaused(channels[metalhitsound], FALSE);*/
+
+                                                                               }
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==staffhitanim&&animation[targetanimation].label[currentframe]==5&&victim->targetanimation!=rollanim){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*6.5&&victim->targetanimation!=dodgebackanim&&victim->targetanimation!=sweepanim){
+                                                                               if(tutoriallevel!=1){
+                                                                                       weapons.damage[weaponids[0]]+=.4+float(abs(Random()%100)-50)/250;
+                                                                                       escapednum=0;
+                                                                                       if(id==0)camerashake+=.4;
+                                                                                       if(Random()%2||creature==wolftype){
+                                                                                               victim->spurt=1;
+                                                                                       }
+                                                                                       float gLoc[3];
+                                                                                       float vel[3];
+                                                                                       gLoc[0]=victim->coords.x;
+                                                                                       gLoc[1]=victim->coords.y;
+                                                                                       gLoc[2]=victim->coords.z;
+                                                                                       vel[0]=velocity.x;
+                                                                                       vel[1]=velocity.y;
+                                                                                       vel[2]=velocity.z;
+                                                                                       PlaySoundEx( staffheadsound, samp[staffheadsound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[staffheadsound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[staffheadsound], 256);
+                                                                                       FSOUND_SetPaused(channels[staffheadsound], FALSE);
+                                                                               }
+                                                                               victim->RagDoll(0);
+                                                                               XYZ relative;
+                                                                               relative=victim->coords-coords;
+                                                                               relative.y=0;
+                                                                               Normalise(&relative);
+                                                                               relative=DoRotation(relative,0,90,0);
+                                                                               relative.y-=1;
+                                                                               Normalise(&relative);
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velocity+=relative*damagemult*60;
+                                                                               }
+                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[head]].velocity+=relative*damagemult*230;
+                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[neck]].velocity+=relative*damagemult*230;
+                                                                               //FootLand(1,2);
+                                                                               victim->Puff(head);
+                                                                               if(tutoriallevel!=1){
+                                                                                       victim->DoDamage(damagemult*120/victim->protectionhigh);
+
+                                                                                       if(id==0){
+                                                                                               bonus=solidhit;
+                                                                                               bonustime=0;
+                                                                                               bonusvalue=30;
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==staffspinhitanim&&animation[targetanimation].label[currentframe]==5&&victim->targetanimation!=rollanim){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*6.5&&victim->targetanimation!=dodgebackanim&&victim->targetanimation!=sweepanim){
+                                                                               if(tutoriallevel!=1){
+                                                                                       weapons.damage[weaponids[0]]+=.6+float(abs(Random()%100)-50)/250;
+                                                                                       escapednum=0;
+                                                                                       if(id==0)camerashake+=.4;
+                                                                                       if(Random()%2||creature==wolftype){
+                                                                                               victim->spurt=1;
+                                                                                       }
+                                                                                       float gLoc[3];
+                                                                                       float vel[3];
+                                                                                       gLoc[0]=victim->coords.x;
+                                                                                       gLoc[1]=victim->coords.y;
+                                                                                       gLoc[2]=victim->coords.z;
+                                                                                       vel[0]=velocity.x;
+                                                                                       vel[1]=velocity.y;
+                                                                                       vel[2]=velocity.z;
+                                                                                       PlaySoundEx( staffheadsound, samp[staffheadsound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[staffheadsound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[staffheadsound], 256);
+                                                                                       FSOUND_SetPaused(channels[staffheadsound], FALSE);
+                                                                               }
+                                                                               victim->RagDoll(0);
+                                                                               XYZ relative;
+                                                                               relative=victim->coords-coords;
+                                                                               relative.y=0;
+                                                                               Normalise(&relative);
+                                                                               relative=DoRotation(relative,0,-90,0);
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velocity+=relative*damagemult*40;
+                                                                               }
+                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[head]].velocity+=relative*damagemult*220;
+                                                                               victim->skeleton.joints[victim->skeleton.jointlabels[neck]].velocity+=relative*damagemult*220;
+                                                                               //FootLand(1,2);
+                                                                               victim->Puff(head);
+                                                                               if(tutoriallevel!=1){victim->DoDamage(damagemult*350/victim->protectionhead);
+
+                                                                               if(id==0){
+                                                                                       bonus=solidhit;
+                                                                                       bonustime=0;
+                                                                                       bonusvalue=60;
+                                                                               }
+                                                                               }
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==staffgroundsmashanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*6.5){
+                                                                               escapednum=0;
+                                                                               if(tutoriallevel!=1){
+                                                                                       if(!victim->dead)weapons.damage[weaponids[0]]+=.4+float(abs(Random()%100)-50)/500;
+                                                                                       if(id==0)camerashake+=.4;
+                                                                                       if(Random()%2||creature==wolftype){
+                                                                                               victim->spurt=1;
+                                                                                       }
+                                                                                       float gLoc[3];
+                                                                                       float vel[3];
+                                                                                       gLoc[0]=victim->coords.x;
+                                                                                       gLoc[1]=victim->coords.y;
+                                                                                       gLoc[2]=victim->coords.z;
+                                                                                       vel[0]=velocity.x;
+                                                                                       vel[1]=velocity.y;
+                                                                                       vel[2]=velocity.z;
+                                                                                       PlaySoundEx( staffbodysound, samp[staffbodysound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[staffbodysound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[staffbodysound], 256);
+                                                                                       FSOUND_SetPaused(channels[staffbodysound], FALSE);
+                                                                               }
+                                                                               victim->skeleton.longdead=0;
+                                                                               victim->skeleton.free=1;
+                                                                               victim->skeleton.broken=0;
+
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velchange=0;
+                                                                                       victim->skeleton.joints[i].locked=0;                                                            
+                                                                                       //victim->skeleton.joints[i].velocity=0;
+                                                                               }
+
+                                                                               victim->RagDoll(0);
+                                                                               XYZ relative;
+                                                                               relative=0;
+                                                                               /*relative=victim->coords-coords;
+                                                                               relative.y=0;
+                                                                               Normalise(&relative);
+                                                                               relative=DoRotation(relative,0,90,0);*/
+                                                                               relative.y=-1;
+                                                                               Normalise(&relative);
+                                                                               if(!victim->dead){
+                                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                               victim->skeleton.joints[i].velocity=relative*damagemult*40;
+                                                                                       }
+                                                                                       //FootLand(1,2);
+                                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*damagemult*40;
+                                                                               }
+                                                                               if(victim->dead){
+                                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                               victim->skeleton.joints[i].velocity=relative*damagemult*abs(Random()%20);
+                                                                                       }
+                                                                                       //FootLand(1,2);
+                                                                                       //victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*damagemult*20;
+                                                                               }
+                                                                               victim->Puff(abdomen);
+                                                                               if(tutoriallevel!=1){victim->DoDamage(damagemult*100/victim->protectionhigh);
+
+                                                                               if(!victim->dead){
+                                                                                       if(id==0){
+                                                                                               bonus=solidhit;
+                                                                                               bonustime=0;
+                                                                                               bonusvalue=40;
+                                                                                       }
+                                                                               }
+                                                                               }
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==lowkickanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*3&&animation[victim->targetanimation].height!=highheight){
+                                                                               escapednum=0;
+                                                                               if(id==0)camerashake+=.4;
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               XYZ relative;
+                                                                               relative=victim->coords-coords;
+                                                                               relative.y=0;
+                                                                               Normalise(&relative);
+
+                                                                               if(id==0){
+                                                                                       SolidHitBonus();
+                                                                               }
+
+                                                                               if(animation[victim->targetanimation].height==lowheight){
+                                                                                       if(Random()%2){
+                                                                                               victim->spurt=1;
+                                                                                               DoBlood(.2,250);
+                                                                                       }
+                                                                                       victim->RagDoll(0);
+                                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                               victim->skeleton.joints[i].velocity+=relative*damagemult*40;
+                                                                                       }
+                                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[head]].velocity+=relative*damagemult*200;
+                                                                                       if(tutoriallevel!=1){
+                                                                                               PlaySoundEx( heavyimpactsound, samp[heavyimpactsound], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[heavyimpactsound], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[heavyimpactsound], 128);
+                                                                                               FSOUND_SetPaused(channels[heavyimpactsound], FALSE);
+                                                                                       }
+                                                                                       victim->Puff(head);
+                                                                                       victim->DoDamage(damagemult*100/victim->protectionhead);
+                                                                                       if(victim->howactive==typesleeping)victim->DoDamage(damagemult*150/victim->protectionhead);
+                                                                                       if(creature==wolftype){
+                                                                                               PlaySoundEx( clawslicesound, samp[clawslicesound], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[clawslicesound], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[clawslicesound], 128);
+                                                                                               FSOUND_SetPaused(channels[clawslicesound], FALSE);
+                                                                                               victim->spurt=1;
+                                                                                               victim->DoBloodBig(2/victim->armorhead,175);
+                                                                                       }
+                                                                               }
+                                                                               else{
+                                                                                       if(victim->damage>=victim->damagetolerance)victim->RagDoll(0);
+                                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                               victim->skeleton.joints[i].velocity+=relative*damagemult*10;
+                                                                                       }
+                                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*damagemult*200;
+                                                                                       victim->targetframe=0;
+                                                                                       victim->targetanimation=staggerbackhighanim;
+                                                                                       victim->targetrotation=targetrotation+180;
+                                                                                       victim->target=0;
+                                                                                       if(tutoriallevel!=1){
+                                                                                               PlaySoundEx( landsound2, samp[landsound2], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[landsound2], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[landsound2], 128);
+                                                                                               FSOUND_SetPaused(channels[landsound2], FALSE);
+                                                                                       }
+                                                                                       victim->Puff(abdomen);
+                                                                                       victim->DoDamage(damagemult*30/victim->protectionhigh);
+                                                                                       if(creature==wolftype){
+                                                                                               PlaySoundEx( clawslicesound, samp[clawslicesound], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[clawslicesound], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[clawslicesound], 128);
+                                                                                               FSOUND_SetPaused(channels[clawslicesound], FALSE);
+                                                                                               victim->spurt=1;
+                                                                                               victim->DoBloodBig(2/victim->armorhigh,170);
+                                                                                       }
+                                                                               }
+
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==sweepanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(victim->targetanimation!=jumpupanim&&findDistancefast(&coords,&victim->coords)<(scale*5)*(scale*5)*3&&victim!=this){
+                                                                               escapednum=0;
+                                                                               if(id==0)camerashake+=.2;
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               if(tutoriallevel!=1){
+                                                                                       PlaySoundEx( landsound2, samp[landsound2], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[landsound2], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[landsound2], 128);
+                                                                                       FSOUND_SetPaused(channels[landsound2], FALSE);
+                                                                               }
+                                                                               XYZ relative;
+                                                                               relative=victim->coords-coords;
+                                                                               relative.y=0;
+                                                                               Normalise(&relative);
+
+                                                                               if(animation[victim->targetanimation].height==middleheight||animation[victim->currentanimation].height==middleheight||victim->damage>=victim->damagetolerance-40){
+                                                                                       victim->RagDoll(0);
+
+                                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                               victim->skeleton.joints[i].velocity+=relative*damagemult*15;
+                                                                                       }
+                                                                                       relative=DoRotation(relative,0,-90,0);
+                                                                                       relative.y+=.1;
+                                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                               if(victim->skeleton.joints[i].label==leftfoot||victim->skeleton.joints[i].label==rightfoot||victim->skeleton.joints[i].label==leftankle||victim->skeleton.joints[i].label==rightankle)
+                                                                                                       victim->skeleton.joints[i].velocity=relative*80;
+                                                                                       }
+                                                                                       victim->Puff(rightankle);
+                                                                                       victim->Puff(leftankle);
+                                                                                       victim->DoDamage(damagemult*40/victim->protectionlow);
+                                                                               }
+                                                                               else{
+                                                                                       if(victim->damage>=victim->damagetolerance)victim->RagDoll(0);
+                                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                               victim->skeleton.joints[i].velocity+=relative*damagemult*10;
+                                                                                       }
+                                                                                       relative=DoRotation(relative,0,-90,0);
+                                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                               if(victim->skeleton.joints[i].label==leftfoot||victim->skeleton.joints[i].label==rightfoot||victim->skeleton.joints[i].label==leftankle||victim->skeleton.joints[i].label==rightankle)
+                                                                                                       victim->skeleton.joints[i].velocity+=relative*damagemult*80;
+                                                                                       }
+                                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*damagemult*200;
+                                                                                       victim->targetframe=0;
+                                                                                       victim->targetanimation=staggerbackhighanim;
+                                                                                       victim->targetrotation=targetrotation+180;
+                                                                                       victim->target=0;
+                                                                                       if(tutoriallevel!=1){
+                                                                                               PlaySoundEx( landsound2, samp[landsound2], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[landsound2], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[landsound2], 128);
+                                                                                               FSOUND_SetPaused(channels[landsound2], FALSE);
+                                                                                       }
+                                                                                       victim->Puff(abdomen);
+                                                                                       victim->DoDamage(damagemult*30/victim->protectionlow);
+                                                                               }
+
+                                                                               if(id==0){
+                                                                                       SolidHitBonus();
+                                                                               }
+
+                                                                       }
+                                                               }
+                                                       }                               
+                                                       if(animation[targetanimation].attack==reversal&&(!victim->feint||(victim->lastattack==victim->lastattack2&&victim->lastattack2==victim->lastattack3&&Random()%2)||targetanimation==knifefollowanim)){
+                                                               if(targetanimation==spinkickreversalanim&&animation[targetanimation].label[currentframe]==7){
+                                                                       escapednum=0;
+                                                                       if(id==0)camerashake+=.4;
+                                                                       if(Random()%2){
+                                                                               victim->spurt=1;
+                                                                               DoBlood(.2,230);
+                                                                       }
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=victim->coords.x;
+                                                                       gLoc[1]=victim->coords.y;
+                                                                       gLoc[2]=victim->coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+                                                                       if(tutoriallevel!=1){
+                                                                               PlaySoundEx( heavyimpactsound, samp[heavyimpactsound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[heavyimpactsound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[heavyimpactsound], 128);
+                                                                               FSOUND_SetPaused(channels[heavyimpactsound], FALSE);
+                                                                       }
+                                                                       if(creature==wolftype){
+                                                                               PlaySoundEx( clawslicesound, samp[clawslicesound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[clawslicesound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[clawslicesound], 128);
+                                                                               FSOUND_SetPaused(channels[clawslicesound], FALSE);
+                                                                               victim->spurt=1;
+                                                                               victim->DoBloodBig(2/victim->armorhigh,170);
+                                                                       }
+                                                                       victim->RagDoll(0);
+                                                                       XYZ relative;
+                                                                       relative=victim->coords-oldcoords;
+                                                                       relative.y=0;
+                                                                       Normalise(&relative);
+                                                                       //relative=DoRotation(relative,0,-90,0);
+                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                               victim->skeleton.joints[i].velocity+=relative*damagemult*40;
+                                                                       }
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*damagemult*200;
+                                                                       //FootLand(1,2);
+                                                                       victim->Puff(abdomen);
+                                                                       victim->DoDamage(damagemult*150/victim->protectionhigh);
+
+                                                                       if(id==0){
+                                                                               bonus=Reversal;
+                                                                               bonustime=0;
+                                                                               bonusvalue=60;
+                                                                       }
+                                                               }
+
+                                                               if((targetanimation==swordslashreversalanim||targetanimation==knifeslashreversalanim||targetanimation==staffhitreversalanim||targetanimation==staffspinhitreversalanim)&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(victim->weaponactive!=-1&&victim->num_weapons>0){
+                                                                               if(weapons.owner[victim->weaponids[victim->weaponactive]]==victim->id){
+                                                                                       weapons.owner[victim->weaponids[victim->weaponactive]]=id;
+                                                                                       weaponactive=0;
+                                                                                       if(num_weapons>0){
+                                                                                               weaponids[num_weapons]=weaponids[victim->weaponactive];
+                                                                                       }
+                                                                                       num_weapons++;
+                                                                                       weaponids[0]=victim->weaponids[victim->weaponactive];
+                                                                                       victim->num_weapons--;
+                                                                                       if(victim->num_weapons>0){
+                                                                                               victim->weaponids[victim->weaponactive]=victim->weaponids[victim->num_weapons];
+                                                                                               //if(victim->weaponstuck==victim->num_weapons)victim->weaponstuck=0;
+                                                                                       }
+                                                                                       victim->weaponactive=-1;
+                                                                               }
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==staffhitreversalanim&&animation[targetanimation].label[currentframe]==5){
+                                                                       escapednum=0;
+                                                                       if(id==0)camerashake+=.4;
+                                                                       if(Random()%2){
+                                                                               victim->spurt=1;
+                                                                               DoBlood(.2,230);
+                                                                       }
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=victim->coords.x;
+                                                                       gLoc[1]=victim->coords.y;
+                                                                       gLoc[2]=victim->coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+                                                                       PlaySoundEx( whooshhitsound, samp[whooshhitsound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[whooshhitsound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[whooshhitsound], 128);
+                                                                       FSOUND_SetPaused(channels[whooshhitsound], FALSE);
+                                                                       victim->RagDoll(0);
+                                                                       XYZ relative;
+                                                                       relative=victim->coords-oldcoords;
+                                                                       relative.y=0;
+                                                                       Normalise(&relative);
+                                                                       //relative=DoRotation(relative,0,-90,0);
+                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                               victim->skeleton.joints[i].velocity+=relative*damagemult*30;
+                                                                       }
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*damagemult*200;
+                                                                       //FootLand(1,2);
+                                                                       victim->Puff(head);
+                                                                       victim->DoDamage(damagemult*70/victim->protectionhigh);
+                                                               }
+
+                                                               if(targetanimation==staffspinhitreversalanim&&animation[targetanimation].label[currentframe]==7){
+                                                                       escapednum=0;
+                                                                       if(id==0)camerashake+=.4;
+                                                                       if(Random()%2){
+                                                                               victim->spurt=1;
+                                                                               DoBlood(.2,230);
+                                                                       }
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=victim->coords.x;
+                                                                       gLoc[1]=victim->coords.y;
+                                                                       gLoc[2]=victim->coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+
+                                                                       if(id==0){
+                                                                               bonus=staffreversebonus;
+                                                                               bonustime=0;
+                                                                               bonusvalue=100;
+                                                                       }
+
+                                                                       if(tutoriallevel!=1){
+                                                                               PlaySoundEx( heavyimpactsound, samp[heavyimpactsound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[heavyimpactsound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[heavyimpactsound], 128);
+                                                                               FSOUND_SetPaused(channels[heavyimpactsound], FALSE);
+                                                                       }
+                                                                       victim->RagDoll(0);
+                                                                       if(id==0){
+                                                                               bonus=staffreversebonus;
+                                                                               bonustime=0;
+                                                                               bonusvalue=100;
+                                                                       }
+
+                                                                       XYZ relative;
+                                                                       relative=victim->coords-oldcoords;
+                                                                       relative.y=0;
+                                                                       Normalise(&relative);
+                                                                       //relative=DoRotation(relative,0,-90,0);
+                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                               victim->skeleton.joints[i].velocity+=relative*damagemult*30;
+                                                                       }
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*damagemult*200;
+                                                                       //FootLand(1,2);
+                                                                       victim->Puff(head);
+                                                                       victim->DoDamage(damagemult*70/victim->protectionhigh);
+                                                               }
+
+                                                               if(targetanimation==upunchreversalanim&&animation[targetanimation].label[currentframe]==7){
+                                                                       escapednum=0;
+                                                                       victim->RagDoll(1);
+                                                                       XYZ relative;
+                                                                       relative=facing;
+                                                                       relative.y=0;
+                                                                       Normalise(&relative);
+                                                                       //relative*=-1;
+                                                                       relative.y-=.1;
+                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                               victim->skeleton.joints[i].velocity+=relative*damagemult*70;
+                                                                       }
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[lefthand]].velocity*=.1;
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[leftwrist]].velocity*=.2;
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[leftelbow]].velocity*=.5;
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[leftshoulder]].velocity*=.7;
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[righthand]].velocity*=.1;
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[rightwrist]].velocity*=.2;
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[rightelbow]].velocity*=.5;
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[rightshoulder]].velocity*=.7;
+
+                                                                       victim->Puff(abdomen);
+                                                                       victim->DoDamage(damagemult*90/victim->protectionhigh);
+
+                                                                       if(id==0){
+                                                                               bonus=Reversal;
+                                                                               bonustime=0;
+                                                                               bonusvalue=60;
+                                                                       }
+
+                                                                       bool doslice;
+                                                                       doslice=0;
+                                                                       if(weaponactive!=-1||creature==wolftype)doslice=1;
+                                                                       if(creature==rabbittype&&weaponactive!=-1)if(weapons.type[weaponids[0]]==staff)doslice=0;
+                                                                       if(doslice){
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               if(weaponactive!=-1){
+                                                                                       victim->DoBloodBig(2/victim->armorhigh,225);
+                                                                                       PlaySoundEx( knifeslicesound, samp[knifeslicesound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[knifeslicesound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[knifeslicesound], 512);
+                                                                                       FSOUND_SetPaused(channels[knifeslicesound], FALSE);
+                                                                                       if(bloodtoggle&&!weapons.bloody[weaponids[weaponactive]])weapons.bloody[weaponids[weaponactive]]=1;
+                                                                                       weapons.blooddrip[weaponids[weaponactive]]+=3;
+                                                                               }
+                                                                               if(weaponactive==-1&&creature==wolftype){
+                                                                                       PlaySoundEx( clawslicesound, samp[clawslicesound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[clawslicesound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[clawslicesound], 128);
+                                                                                       FSOUND_SetPaused(channels[clawslicesound], FALSE);
+                                                                                       victim->spurt=1;
+                                                                                       victim->DoBloodBig(2/victim->armorhigh,175);
+                                                                               }
+                                                                       }
+                                                               }
+
+
+
+                                                               if(targetanimation==swordslashreversalanim&&animation[targetanimation].label[currentframe]==7){
+                                                                       escapednum=0;
+                                                                       victim->RagDoll(1);
+                                                                       XYZ relative;
+                                                                       relative=facing;
+                                                                       relative.y=0;
+                                                                       Normalise(&relative);
+                                                                       //relative*=-1;
+                                                                       relative.y-=.1;
+                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                               victim->skeleton.joints[i].velocity+=relative*damagemult*70;
+                                                                       }
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[lefthand]].velocity*=.1-1;
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[leftwrist]].velocity*=.2-1;
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[leftelbow]].velocity*=.5-1;
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[leftshoulder]].velocity*=.7-1;
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[righthand]].velocity*=.1-1;
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[rightwrist]].velocity*=.2-1;
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[rightelbow]].velocity*=.5-1;
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[rightshoulder]].velocity*=.7-1;
+
+                                                                       if(id==0){
+                                                                               bonus=swordreversebonus;
+                                                                               bonustime=0;
+                                                                               bonusvalue=100;
+                                                                       }
+                                                                       //victim->DoDamage(90);
+
+                                                                       /*if(weaponactive!=-1){
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=victim->coords.x;
+                                                                       gLoc[1]=victim->coords.y;
+                                                                       gLoc[2]=victim->coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+                                                                       victim->DoBloodBig(2,225);
+                                                                       PlaySoundEx( knifeslicesound, samp[knifeslicesound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[knifeslicesound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[knifeslicesound], 512);
+                                                                       FSOUND_SetPaused(channels[knifeslicesound], FALSE);
+                                                                       if(bloodtoggle&&!weapons.bloody[weaponids[weaponactive]])weapons.bloody[weaponids[weaponactive]]=1;
+                                                                       weapons.blooddrip[weaponids[weaponactive]]+=3;
+                                                                       }*/
+                                                               }
+
+                                                               if(hasvictim&&targetanimation==knifeslashreversalanim&&animation[targetanimation].label[currentframe]==7){
+                                                                       escapednum=0;
+                                                                       if(id==0)camerashake+=.4;
+                                                                       if(Random()%2){
+                                                                               victim->spurt=1;
+                                                                               DoBlood(.2,230);
+                                                                       }
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=victim->coords.x;
+                                                                       gLoc[1]=victim->coords.y;
+                                                                       gLoc[2]=victim->coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+                                                                       if(tutoriallevel!=1){
+                                                                               PlaySoundEx( heavyimpactsound, samp[heavyimpactsound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[heavyimpactsound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[heavyimpactsound], 128);
+                                                                               FSOUND_SetPaused(channels[heavyimpactsound], FALSE);
+                                                                       }
+                                                                       victim->RagDoll(0);
+                                                                       XYZ relative;
+                                                                       relative=victim->coords-oldcoords;
+                                                                       relative.y=0;
+                                                                       Normalise(&relative);
+                                                                       relative=DoRotation(relative,0,-90,0);
+                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                               victim->skeleton.joints[i].velocity+=relative*damagemult*40;
+                                                                       }
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[abdomen]].velocity+=relative*damagemult*200;
+                                                                       //FootLand(1,2);
+                                                                       victim->Puff(abdomen);
+                                                                       victim->DoDamage(damagemult*30/victim->protectionhigh);
+
+                                                                       if(id==0){
+                                                                               bonus=Reversal;
+                                                                               bonustime=0;
+                                                                               bonusvalue=60;
+                                                                       }
+                                                               }
+
+                                                               if(hasvictim&&targetanimation==sneakattackanim&&animation[targetanimation].label[currentframe]==7){
+                                                                       escapednum=0;
+                                                                       victim->RagDoll(0);
+                                                                       victim->skeleton.spinny=0;
+                                                                       XYZ relative;
+                                                                       relative=facing*-1;
+                                                                       relative.y=-3;
+                                                                       Normalise(&relative);
+                                                                       if(victim->id==0)relative/=30;
+                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                               victim->skeleton.joints[i].velocity+=relative*damagemult*40;
+                                                                       }
+                                                                       //victim->DoDamage(1000);
+                                                                       victim->damage=victim->damagetolerance;
+                                                                       victim->permanentdamage=victim->damagetolerance-1;
+                                                                       bool doslice;
+                                                                       doslice=0;
+                                                                       if(weaponactive!=-1||creature==wolftype)doslice=1;
+                                                                       if(creature==rabbittype&&weaponactive!=-1)if(weapons.type[weaponids[0]]==staff)doslice=0;
+                                                                       if(doslice){
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               if(weaponactive!=-1){
+                                                                                       victim->DoBloodBig(200,225);
+                                                                                       PlaySoundEx( knifeslicesound, samp[knifeslicesound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[knifeslicesound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[knifeslicesound], 512);
+                                                                                       FSOUND_SetPaused(channels[knifeslicesound], FALSE);
+                                                                                       if(bloodtoggle)weapons.bloody[weaponids[weaponactive]]=2;
+                                                                                       weapons.blooddrip[weaponids[weaponactive]]+=5;
+                                                                               }
+
+                                                                               if(creature==wolftype&&weaponactive==-1){
+                                                                                       PlaySoundEx( clawslicesound, samp[clawslicesound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[clawslicesound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[clawslicesound], 128);
+                                                                                       FSOUND_SetPaused(channels[clawslicesound], FALSE);
+                                                                                       victim->spurt=1;
+                                                                                       victim->DoBloodBig(2,175);
+                                                                               }
+                                                                       }
+                                                                       if(id==0){
+                                                                               bonus=spinecrusher;
+                                                                               bonustime=0;
+                                                                               bonusvalue=100;
+                                                                       }
+                                                               }
+
+                                                               if(hasvictim&&(targetanimation==knifefollowanim||targetanimation==knifesneakattackanim)&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(weaponactive!=-1&&victim->bloodloss<victim->damagetolerance){
+                                                                               escapednum=0;
+                                                                               if(targetanimation==knifefollowanim)victim->DoBloodBig(200,210);
+                                                                               if(targetanimation==knifesneakattackanim){
+                                                                                       /*victim->DoBloodBig(200,195);
+                                                                                       XYZ bloodvel;
+                                                                                       bloodvel=0;
+                                                                                       bloodvel.z=20;
+                                                                                       bloodvel.y=5;
+                                                                                       bloodvel=DoRotation(bloodvel,((float)(Random()%100))/4,rotation+((float)(Random()%100))/4,0)*scale;
+                                                                                       sprites.MakeSprite(bloodsprite, DoRotation(skeleton.joints[skeleton.jointlabels[neck]].position,0,rotation,0)*scale+coords,bloodvel, 1,1,1, .05, 1);
+                                                                                       */
+                                                                                       XYZ footvel,footpoint;  
+                                                                                       footvel=0;
+                                                                                       footpoint=weapons.tippoint[weaponids[0]];
+                                                                                       if(bloodtoggle)sprites.MakeSprite(cloudimpactsprite, footpoint,footvel, 1,0,0, .9, .3);
+                                                                                       footvel=(weapons.tippoint[weaponids[0]]-weapons.position[weaponids[0]]);
+                                                                                       sprites.MakeSprite(bloodsprite,footpoint,DoRotation(footvel*7,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .05, .9);
+                                                                                       sprites.MakeSprite(bloodsprite,footpoint,DoRotation(footvel*3,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .05, .9);
+                                                                                       sprites.MakeSprite(bloodflamesprite, footpoint,footvel*5, 1,1,1, .3, 1);
+                                                                                       sprites.MakeSprite(bloodflamesprite, footpoint,footvel*2, 1,1,1, .3, 1);
+                                                                                       victim->DoBloodBig(200,195);
+                                                                                       if(id==0){
+                                                                                               bonus=tracheotomy;
+                                                                                               bonustime=0;
+                                                                                               bonusvalue=100;
+                                                                                       }
+
+                                                                                       //victim->neckspurtamount=5;
+                                                                               }
+                                                                               if(targetanimation==knifefollowanim){
+                                                                                       if(id==0){
+                                                                                               bonus=Stabbonus;
+                                                                                               bonustime=0;
+                                                                                               bonusvalue=40;
+                                                                                       }
+                                                                                       XYZ footvel,footpoint;  
+                                                                                       footvel=0;
+                                                                                       footpoint=weapons.tippoint[weaponids[0]];
+                                                                                       if(bloodtoggle)sprites.MakeSprite(cloudimpactsprite, footpoint,footvel, 1,0,0, .9, .3);
+                                                                                       footvel=(weapons.tippoint[weaponids[0]]-weapons.position[weaponids[0]])*-1;
+                                                                                       sprites.MakeSprite(bloodsprite,footpoint,DoRotation(footvel*7,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .05, .9);
+                                                                                       sprites.MakeSprite(bloodsprite,footpoint,DoRotation(footvel*3,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .05, .9);
+                                                                                       sprites.MakeSprite(bloodflamesprite, footpoint,footvel*5, 1,1,1, .2, 1);
+                                                                                       sprites.MakeSprite(bloodflamesprite, footpoint,footvel*2, 1,1,1, .2, 1);
+
+                                                                               }
+                                                                               victim->bloodloss+=10000;
+                                                                               victim->velocity=0;
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               PlaySoundEx( fleshstabsound, samp[fleshstabsound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[fleshstabsound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[fleshstabsound], 512);
+                                                                               FSOUND_SetPaused(channels[fleshstabsound], FALSE);
+                                                                               if(bloodtoggle)weapons.bloody[weaponids[weaponactive]]=2;
+                                                                               weapons.blooddrip[weaponids[weaponactive]]+=5;
+                                                                       }
+                                                               }
+
+                                                               if(hasvictim&&(targetanimation==knifefollowanim||targetanimation==knifesneakattackanim)&&animation[targetanimation].label[currentframe]==6){
+                                                                       escapednum=0;
+                                                                       victim->velocity=0;
+                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                               victim->skeleton.joints[i].velocity=0;
+                                                                       }
+                                                                       if(targetanimation==knifefollowanim){
+                                                                               victim->RagDoll(0);
+                                                                               for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                                       victim->skeleton.joints[i].velocity=0;
+                                                                               }
+                                                                       }
+                                                                       if(weaponactive!=-1&&animation[victim->targetanimation].attack!=reversal){
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               PlaySoundEx( fleshstabremovesound, samp[fleshstabremovesound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[fleshstabremovesound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[fleshstabremovesound], 512);
+                                                                               FSOUND_SetPaused(channels[fleshstabremovesound], FALSE);
+                                                                               if(bloodtoggle)weapons.bloody[weaponids[weaponactive]]=2;
+                                                                               weapons.blooddrip[weaponids[weaponactive]]+=5;
+
+                                                                               XYZ footvel,footpoint;  
+                                                                               footvel=0;
+                                                                               footpoint=weapons.tippoint[weaponids[0]];
+                                                                               if(bloodtoggle)sprites.MakeSprite(cloudimpactsprite, footpoint,footvel, 1,0,0, .9, .3);
+                                                                               footvel=(weapons.tippoint[weaponids[0]]-weapons.position[weaponids[0]])*-1;
+                                                                               sprites.MakeSprite(bloodsprite,footpoint,DoRotation(footvel*7,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .05, .9);
+                                                                               sprites.MakeSprite(bloodsprite,footpoint,DoRotation(footvel*3,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .05, .9);
+                                                                               sprites.MakeSprite(bloodflamesprite, footpoint,footvel*5, 1,1,1, .3, 1);
+                                                                               sprites.MakeSprite(bloodflamesprite, footpoint,footvel*2, 1,1,1, .3, 1);
+                                                                       }
+                                                               }
+
+                                                               if(hasvictim&&(targetanimation==swordsneakattackanim)&&animation[targetanimation].label[currentframe]==5){
+                                                                       if(weaponactive!=-1&&victim->bloodloss<victim->damagetolerance){
+                                                                               if(id==0){
+                                                                                       bonus=backstab;
+                                                                                       bonustime=0;
+                                                                                       bonusvalue=100;
+                                                                               }
+
+                                                                               escapednum=0;
+
+                                                                               XYZ footvel,footpoint;  
+                                                                               footvel=0;
+                                                                               footpoint=(weapons.tippoint[weaponids[0]]+weapons.position[weaponids[0]])/2;
+                                                                               if(bloodtoggle)sprites.MakeSprite(cloudimpactsprite, footpoint,footvel, 1,0,0, .9, .3);
+                                                                               footvel=(weapons.tippoint[weaponids[0]]-weapons.position[weaponids[0]]);
+                                                                               sprites.MakeSprite(bloodsprite,footpoint,DoRotation(footvel*7,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .05, .9);
+                                                                               sprites.MakeSprite(bloodsprite,footpoint,DoRotation(footvel*3,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .05, .9);
+                                                                               sprites.MakeSprite(bloodflamesprite, footpoint,DoRotation(footvel*5,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .3, 1);
+                                                                               sprites.MakeSprite(bloodflamesprite, footpoint,DoRotation(footvel*3,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .3, 1);
+                                                                               victim->DoBloodBig(200,180);
+                                                                               victim->DoBloodBig(200,215);
+                                                                               victim->bloodloss+=10000;
+                                                                               victim->velocity=0;
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               PlaySoundEx( fleshstabsound, samp[fleshstabsound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[fleshstabsound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[fleshstabsound], 512);
+                                                                               FSOUND_SetPaused(channels[fleshstabsound], FALSE);
+                                                                               if(bloodtoggle)weapons.bloody[weaponids[weaponactive]]=2;
+                                                                               weapons.blooddrip[weaponids[weaponactive]]+=5;
+                                                                       }
+                                                               }
+
+                                                               if(hasvictim&&targetanimation==swordsneakattackanim&&animation[targetanimation].label[currentframe]==6){
+                                                                       escapednum=0;
+                                                                       victim->velocity=0;
+                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                               victim->skeleton.joints[i].velocity=0;
+                                                                       }
+                                                                       if(weaponactive!=-1){
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=victim->coords.x;
+                                                                               gLoc[1]=victim->coords.y;
+                                                                               gLoc[2]=victim->coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+                                                                               PlaySoundEx( fleshstabremovesound, samp[fleshstabremovesound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[fleshstabremovesound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[fleshstabremovesound], 512);
+                                                                               FSOUND_SetPaused(channels[fleshstabremovesound], FALSE);
+                                                                               if(bloodtoggle)weapons.bloody[weaponids[weaponactive]]=2;
+                                                                               weapons.blooddrip[weaponids[weaponactive]]+=5;
+
+                                                                               XYZ footvel,footpoint;  
+                                                                               footvel=0;
+                                                                               footpoint=weapons.tippoint[weaponids[0]];
+                                                                               if(bloodtoggle)sprites.MakeSprite(cloudimpactsprite, footpoint,footvel, 1,0,0, .9, .3);
+                                                                               footvel=(weapons.tippoint[weaponids[0]]-weapons.position[weaponids[0]])*-1;
+                                                                               sprites.MakeSprite(bloodsprite,footpoint,DoRotation(footvel*7,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .05, .9);
+                                                                               sprites.MakeSprite(bloodsprite,footpoint,DoRotation(footvel*3,(float)(Random()%20),(float)(Random()%20),0), 1,1,1, .05, .9);
+                                                                               sprites.MakeSprite(bloodflamesprite, footpoint,footvel*5, 1,1,1, .3, 1);
+                                                                               sprites.MakeSprite(bloodflamesprite, footpoint,footvel*2, 1,1,1, .3, 1);
+                                                                       }
+                                                               }
+
+                                                               if(targetanimation==sweepreversalanim&&animation[targetanimation].label[currentframe]==7){
+                                                                       escapednum=0;
+                                                                       if(id==0)camerashake+=.4;
+                                                                       if(Random()%2){
+                                                                               victim->spurt=1;
+                                                                               DoBlood(.2,240);
+                                                                       }
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=victim->coords.x;
+                                                                       gLoc[1]=victim->coords.y;
+                                                                       gLoc[2]=victim->coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+                                                                       if(weaponactive==-1){
+                                                                               if(tutoriallevel!=1){
+                                                                                       PlaySoundEx( heavyimpactsound, samp[heavyimpactsound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[heavyimpactsound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[heavyimpactsound], 128);
+                                                                                       FSOUND_SetPaused(channels[heavyimpactsound], FALSE);
+                                                                               }
+                                                                       }
+                                                                       bool doslice;
+                                                                       doslice=0;
+                                                                       if(weaponactive!=-1||creature==wolftype)doslice=1;
+                                                                       if(creature==rabbittype&&weaponactive!=-1)if(weapons.type[weaponids[0]]==staff)doslice=0;
+                                                                       if(doslice){
+                                                                               if(weaponactive!=-1){
+                                                                                       victim->DoBloodBig(2/victim->armorhead,225);
+                                                                                       PlaySoundEx( knifeslicesound, samp[knifeslicesound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[knifeslicesound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[knifeslicesound], 512);
+                                                                                       FSOUND_SetPaused(channels[knifeslicesound], FALSE);
+                                                                                       if(bloodtoggle&&!weapons.bloody[weaponids[weaponactive]])weapons.bloody[weaponids[weaponactive]]=1;
+                                                                                       weapons.blooddrip[weaponids[weaponactive]]+=3;
+                                                                               }
+                                                                               if(weaponactive==-1&&creature==wolftype){       
+                                                                                       PlaySoundEx( clawslicesound, samp[clawslicesound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[clawslicesound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[clawslicesound], 128);
+                                                                                       FSOUND_SetPaused(channels[clawslicesound], FALSE);
+                                                                                       victim->spurt=1;
+                                                                                       victim->DoBloodBig(2/victim->armorhead,175);
+                                                                               }
+                                                                       }
+
+                                                                       if(id==0){
+                                                                               bonus=Reversal;
+                                                                               bonustime=0;
+                                                                               bonusvalue=60;
+                                                                       }
+
+                                                                       victim->Puff(neck);
+
+                                                                       XYZ relative;
+                                                                       //relative=victim->coords-oldcoords;
+                                                                       relative=facing*-1;
+                                                                       relative.y=0;
+                                                                       Normalise(&relative);
+                                                                       relative=DoRotation(relative,0,90,0);
+                                                                       relative.y=.5;
+                                                                       Normalise(&relative);
+                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                               victim->skeleton.joints[i].velocity+=relative*damagemult*20;
+                                                                       }
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[head]].velocity+=relative*damagemult*200;
+                                                                       if(victim->damage<victim->damagetolerance-100)victim->velocity=relative*200;
+                                                                       victim->DoDamage(damagemult*100/victim->protectionhead);
+                                                                       victim->velocity=0;
+                                                               }
+
+                                                               if(targetanimation==sweepreversalanim&&((animation[targetanimation].label[currentframe]==9&&victim->damage<victim->damagetolerance)||(animation[targetanimation].label[currentframe]==7&&victim->damage>victim->damagetolerance))){
+                                                                       escapednum=0;
+                                                                       victim->RagDoll(0);
+                                                                       XYZ relative;
+                                                                       //relative=victim->coords-oldcoords;
+                                                                       relative=facing*-1;
+                                                                       relative.y=0;
+                                                                       Normalise(&relative);
+                                                                       relative=DoRotation(relative,0,90,0);
+                                                                       relative.y=.5;
+                                                                       Normalise(&relative);
+                                                                       for(i=0;i<victim->skeleton.num_joints;i++){
+                                                                               victim->skeleton.joints[i].velocity+=relative*damagemult*20;
+                                                                       }
+                                                                       victim->skeleton.joints[victim->skeleton.jointlabels[head]].velocity+=relative*damagemult*200;
+                                                               }
+
+                                                               if(hasvictim&&(targetanimation==spinkickreversalanim||targetanimation==sweepreversalanim||targetanimation==rabbitkickreversalanim||targetanimation==upunchreversalanim||targetanimation==jumpreversalanim||targetanimation==swordslashreversalanim||targetanimation==knifeslashreversalanim||targetanimation==rabbittacklereversal||targetanimation==wolftacklereversal||targetanimation==staffhitreversalanim||targetanimation==staffspinhitreversalanim))
+                                                                       if(victim->damage>victim->damagetolerance&&bonus!=reverseko){
+                                                                               if(id==0){
+                                                                                       bonus=reverseko;
+                                                                                       bonustime=0;
+                                                                                       bonusvalue=100;
+                                                                               }
+                                                                       }
+                                                       }
+
+
+                                                       //Animation end
+                                                       if(targetframe>animation[currentanimation].numframes-1){
+                                                               targetframe=0;
+                                                               if(wasStop()){
+                                                                       targetanimation=getIdle();
+                                                                       FootLand(0,1);
+                                                                       FootLand(1,1);
+                                                               }
+                                                               if(currentanimation==rabbittackleanim||currentanimation==rabbittacklinganim){
+                                                                       targetanimation=rollanim;
+                                                                       targetframe=3;
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=coords.x;
+                                                                       gLoc[1]=coords.y;
+                                                                       gLoc[2]=coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+
+                                                                       PlaySoundEx( movewhooshsound, samp[movewhooshsound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[movewhooshsound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[movewhooshsound], 128);
+                                                                       FSOUND_SetPaused(channels[movewhooshsound], FALSE);
+                                                               }
+                                                               if(currentanimation==staggerbackhighanim){
+                                                                       targetanimation=getIdle();
+                                                               }
+                                                               if(currentanimation==staggerbackhardanim){
+                                                                       targetanimation=getIdle();
+                                                               }
+                                                               if(currentanimation==removeknifeanim){
+                                                                       targetanimation=getIdle();
+                                                               }
+                                                               if(currentanimation==crouchremoveknifeanim){
+                                                                       targetanimation=getCrouch();
+                                                               }
+                                                               if(currentanimation==backhandspringanim){
+                                                                       targetanimation=getIdle();
+                                                               }
+                                                               if(currentanimation==dodgebackanim){
+                                                                       targetanimation=getIdle();
+                                                               }
+                                                               if(currentanimation==drawleftanim){
+                                                                       targetanimation=getIdle();
+                                                               }
+                                                               if(currentanimation==drawrightanim||currentanimation==crouchdrawrightanim){
+                                                                       targetanimation=getIdle();
+                                                                       if(currentanimation==crouchdrawrightanim){
+                                                                               targetanimation=getCrouch();
+                                                                       }
+                                                                       if(weaponactive==-1)weaponactive=0;
+                                                                       else if(weaponactive==0){
+                                                                               weaponactive=-1;
+                                                                               if(num_weapons==2){
+                                                                                       int buffer;
+                                                                                       buffer=weaponids[0];
+                                                                                       weaponids[0]=weaponids[1];
+                                                                                       weaponids[1]=buffer;
+                                                                               }
+                                                                       }
+
+                                                                       if(weaponactive==-1){
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=coords.x;
+                                                                               gLoc[1]=coords.y;
+                                                                               gLoc[2]=coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+
+                                                                               PlaySoundEx( knifesheathesound, samp[knifesheathesound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[knifesheathesound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[knifesheathesound], 128);
+                                                                               FSOUND_SetPaused(channels[knifesheathesound], FALSE);   
+                                                                       }
+                                                                       if(weaponactive!=-1){
+                                                                               float gLoc[3];
+                                                                               float vel[3];
+                                                                               gLoc[0]=coords.x;
+                                                                               gLoc[1]=coords.y;
+                                                                               gLoc[2]=coords.z;
+                                                                               vel[0]=velocity.x;
+                                                                               vel[1]=velocity.y;
+                                                                               vel[2]=velocity.z;
+
+                                                                               PlaySoundEx( knifedrawsound, samp[knifedrawsound], NULL, TRUE);
+                                                                               FSOUND_3D_SetAttributes(channels[knifedrawsound], gLoc, vel);
+                                                                               FSOUND_SetVolume(channels[knifedrawsound], 128);
+                                                                               FSOUND_SetPaused(channels[knifedrawsound], FALSE);      
+                                                                       }
+                                                               }
+                                                               if(currentanimation==rollanim){
+                                                                       targetanimation=getCrouch();
+                                                                       FootLand(0,1);
+                                                                       FootLand(1,1);
+                                                               }
+                                                               if(isFlip()){
+                                                                       if(targetanimation==walljumprightkickanim){
+                                                                               targetrot=-190;
+                                                                       }
+                                                                       if(targetanimation==walljumpleftkickanim){
+                                                                               targetrot=190;
+                                                                       }
+                                                                       targetanimation=jumpdownanim;
+                                                               }
+                                                               if(currentanimation==climbanim){
+                                                                       targetanimation=getCrouch();
+                                                                       targetframe=1;
+                                                                       coords+=facing*.1;
+                                                                       if(!isnormal(coords.x))
+                                                                               coords=oldcoords;
+                                                                       oldcoords=coords;
+                                                                       collided=0;
+                                                                       targetoffset=0;
+                                                                       currentoffset=0;
+                                                                       grabdelay=1;
+                                                                       velocity=0;
+                                                                       collided=0;
+                                                                       avoidcollided=0;
+                                                               }
+                                                               if(targetanimation==rabbitkickreversalanim){
+                                                                       targetanimation=getCrouch();
+                                                                       lastfeint=0;
+                                                               }
+                                                               if(targetanimation==jumpreversalanim){
+                                                                       targetanimation=getCrouch();
+                                                                       lastfeint=0;
+                                                               }
+                                                               if(targetanimation==walljumprightanim||targetanimation==walljumpbackanim||targetanimation==walljumpfrontanim){
+                                                                       if(attackkeydown&&targetanimation!=walljumpfrontanim){
+                                                                               int closest=-1;
+                                                                               float closestdist=-1;
+                                                                               float distance;
+                                                                               if(numplayers>1)
+                                                                                       for(i=0;i<numplayers;i++){
+                                                                                               if(id!=i&&player[i].coords.y<coords.y&&!player[i].skeleton.free){
+                                                                                                       distance=findDistancefast(&player[i].coords,&coords);
+                                                                                                       if(closestdist==-1||distance<closestdist){
+                                                                                                               closestdist=distance;
+                                                                                                               closest=i;
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+                                                                                       if(closestdist>0&&closest>=0&&closestdist<16){
+                                                                                               victim=&player[closest];
+                                                                                               targetanimation=walljumprightkickanim;
+                                                                                               targetframe=0;
+                                                                                               XYZ rotatetarget=victim->coords-coords;
+                                                                                               Normalise(&rotatetarget);
+                                                                                               rotation=-asin(0-rotatetarget.x);
+                                                                                               rotation*=360/6.28;
+                                                                                               if(rotatetarget.z<0)rotation=180-rotation;
+                                                                                               targettilt2=-asin(rotatetarget.y)*360/6.28;
+                                                                                               velocity=(victim->coords-coords)*4;
+                                                                                               velocity.y+=2;
+                                                                                               transspeed=40;
+                                                                                       }
+                                                                       }
+                                                                       if(targetanimation==walljumpbackanim){
+                                                                               targetanimation=backflipanim;
+                                                                               targetframe=3;
+                                                                               velocity=facing*-8;
+                                                                               velocity.y=4;
+                                                                               if(id==0)FSOUND_SetPaused(channels[whooshsound], FALSE);
+                                                                       }
+                                                                       if(targetanimation==walljumprightanim){
+                                                                               targetanimation=rightflipanim;
+                                                                               targetframe=4;
+                                                                               targetrotation-=90;
+                                                                               rotation-=90;
+                                                                               velocity=DoRotation(facing,0,30,0)*-8;
+                                                                               velocity.y=4;
+                                                                       }
+                                                                       if(targetanimation==walljumpfrontanim){
+                                                                               targetanimation=frontflipanim;
+                                                                               targetframe=2;
+                                                                               //targetrotation-=180;
+                                                                               ////rotation-=180;
+                                                                               velocity=facing*8;
+                                                                               velocity.y=4;
+                                                                       }
+                                                                       if(id==0)FSOUND_SetPaused(channels[whooshsound], FALSE);
+                                                               }
+                                                               if(targetanimation==walljumpleftanim){
+                                                                       if(attackkeydown){
+                                                                               int closest=-1;
+                                                                               float closestdist=-1;
+                                                                               float distance;
+                                                                               if(numplayers>1)
+                                                                                       for(i=0;i<numplayers;i++){
+                                                                                               if(id!=i&&player[i].coords.y<coords.y&&!player[i].skeleton.free){
+                                                                                                       distance=findDistancefast(&player[i].coords,&coords);
+                                                                                                       if(closestdist==-1||distance<closestdist){
+                                                                                                               closestdist=distance;
+                                                                                                               closest=i;
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+                                                                                       if(closestdist>0&&closest>=0&&closestdist<16){
+                                                                                               victim=&player[closest];
+                                                                                               targetanimation=walljumpleftkickanim;
+                                                                                               targetframe=0;
+                                                                                               XYZ rotatetarget=victim->coords-coords;
+                                                                                               Normalise(&rotatetarget);
+                                                                                               rotation=-asin(0-rotatetarget.x);
+                                                                                               rotation*=360/6.28;
+                                                                                               if(rotatetarget.z<0)rotation=180-rotation;
+                                                                                               targettilt2=-asin(rotatetarget.y)*360/6.28;
+                                                                                               velocity=(victim->coords-coords)*4;
+                                                                                               velocity.y+=2;
+                                                                                               transspeed=40;
+                                                                                       }
+                                                                       }
+                                                                       if(targetanimation!=walljumpleftkickanim){
+                                                                               targetanimation=leftflipanim;
+                                                                               targetframe=4;
+                                                                               targetrotation+=90;
+                                                                               rotation+=90;
+                                                                               velocity=DoRotation(facing,0,-30,0)*-8;
+                                                                               velocity.y=4;
+                                                                       }
+                                                                       if(id==0)FSOUND_SetPaused(channels[whooshsound], FALSE);
+                                                               }
+                                                               if(targetanimation==sneakattackanim){
+                                                                       float ycoords=oldcoords.y;
+                                                                       currentanimation=getCrouch();
+                                                                       targetanimation=getCrouch();
+                                                                       targetframe=1;
+                                                                       currentframe=0;
+                                                                       targetrotation+=180;
+                                                                       rotation+=180;
+                                                                       targettilt2*=-1;
+                                                                       tilt2*=-1;
+                                                                       transspeed=1000000;
+                                                                       targetheadrotation+=180;
+                                                                       coords-=facing*.7;
+                                                                       if(onterrain)coords.y=terrain.getHeight(coords.x,coords.z);
+
+                                                                       lastfeint=0;
+                                                               }
+                                                               if(targetanimation==knifesneakattackanim||targetanimation==swordsneakattackanim){
+                                                                       float ycoords=oldcoords.y;
+                                                                       targetanimation=getIdle();
+                                                                       targetframe=0;
+                                                                       if(onterrain)coords.y=terrain.getHeight(coords.x,coords.z);
+
+                                                                       lastfeint=0;
+                                                               }
+                                                               if(currentanimation==knifefollowanim){
+                                                                       targetanimation=getIdle();
+                                                                       lastfeint=0;
+                                                               }
+                                                               if(animation[targetanimation].attack==reversal&&currentanimation!=sneakattackanim&&currentanimation!=knifesneakattackanim&&currentanimation!=swordsneakattackanim&&currentanimation!=knifefollowanim){
+                                                                       float ycoords=oldcoords.y;
+                                                                       targetanimation=getStop();
+                                                                       targetrotation+=180;
+                                                                       rotation+=180;
+                                                                       targettilt2*=-1;
+                                                                       tilt2*=-1;
+                                                                       transspeed=1000000;
+                                                                       targetheadrotation+=180;
+                                                                       if(!isnormal(coords.x))
+                                                                               coords=oldcoords;
+                                                                       if(currentanimation==spinkickreversalanim||currentanimation==swordslashreversalanim)
+                                                                               oldcoords=coords+facing*.5;
+                                                                       else if(currentanimation==sweepreversalanim)
+                                                                               oldcoords=coords+facing*1.1;
+                                                                       else if(currentanimation==upunchreversalanim){
+                                                                               oldcoords=coords+facing*1.5;
+                                                                               targetrotation+=180;
+                                                                               rotation+=180;
+                                                                               targetheadrotation+=180;
+                                                                               targettilt2*=-1;
+                                                                               tilt2*=-1;
+                                                                       }
+                                                                       else if(currentanimation==knifeslashreversalanim){
+                                                                               oldcoords=coords+facing*.5;
+                                                                               targetrotation+=90;
+                                                                               rotation+=90;
+                                                                               targetheadrotation+=90;
+                                                                               targettilt2=0;
+                                                                               tilt2=0;
+                                                                       }
+                                                                       else if(currentanimation==staffspinhitreversalanim){
+                                                                               targetrotation+=180;
+                                                                               rotation+=180;
+                                                                               targetheadrotation+=180;
+                                                                               targettilt2=0;
+                                                                               tilt2=0;
+                                                                       }
+                                                                       if(onterrain)oldcoords.y=terrain.getHeight(oldcoords.x,oldcoords.z);
+                                                                       else oldcoords.y=ycoords;
+                                                                       currentoffset=coords-oldcoords;
+                                                                       targetoffset=0;
+                                                                       coords=oldcoords;
+
+                                                                       lastfeint=0;
+                                                               }
+                                                               if(currentanimation==knifesneakattackedanim||currentanimation==swordsneakattackedanim){
+                                                                       velocity=0;
+                                                                       velocity.y=-5;
+                                                                       RagDoll(0);
+                                                               }
+                                                               if(animation[targetanimation].attack==reversed){
+                                                                       escapednum++;
+                                                                       if(targetanimation==sweepreversedanim)targetrotation+=90;
+                                                                       targetanimation=backhandspringanim;
+                                                                       targetframe=2;
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=coords.x;
+                                                                       gLoc[1]=coords.y;
+                                                                       gLoc[2]=coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+                                                                       PlaySoundEx( landsound, samp[landsound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[landsound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[landsound], 128);
+                                                                       FSOUND_SetPaused(channels[landsound], FALSE);
+
+                                                                       if(currentanimation==upunchreversedanim||currentanimation==swordslashreversedanim){
+                                                                               targetanimation=rollanim;
+                                                                               targetframe=5;
+                                                                               oldcoords=coords;
+                                                                               coords+=(DoRotation(skeleton.joints[skeleton.jointlabels[leftfoot]].position,0,rotation,0)+DoRotation(skeleton.joints[skeleton.jointlabels[rightfoot]].position,0,rotation,0))/2*scale;
+                                                                               coords.y=oldcoords.y;
+                                                                       }
+                                                                       if(currentanimation==knifeslashreversedanim){
+                                                                               targetanimation=rollanim;
+                                                                               targetframe=0;
+                                                                               targetrotation+=90;
+                                                                               rotation+=90;
+                                                                               oldcoords=coords;
+                                                                               coords+=(DoRotation(skeleton.joints[skeleton.jointlabels[leftfoot]].position,0,rotation,0)+DoRotation(skeleton.joints[skeleton.jointlabels[rightfoot]].position,0,rotation,0))/2*scale;
+                                                                               coords.y=oldcoords.y;
+                                                                       }
+                                                               }
+                                                               if(wasFlip()){
+                                                                       targetanimation=jumpdownanim;
+                                                               }
+                                                               if(wasLanding())targetanimation=getIdle();
+                                                               if(wasLandhard())targetanimation=getIdle();
+                                                               if(currentanimation==spinkickanim||currentanimation==getupfrombackanim||currentanimation==getupfromfrontanim||currentanimation==lowkickanim){
+                                                                       targetanimation=getIdle();
+                                                                       oldcoords=coords;
+                                                                       coords+=(DoRotation(skeleton.joints[skeleton.jointlabels[leftfoot]].position,0,rotation,0)+DoRotation(skeleton.joints[skeleton.jointlabels[rightfoot]].position,0,rotation,0))/2*scale;
+                                                                       coords.y=oldcoords.y;
+                                                                       //coords+=DoRotation(animation[currentanimation].offset,0,rotation,0)*scale;
+                                                                       targetoffset.y=coords.y;
+                                                                       if(onterrain)targetoffset.y=terrain.getHeight(coords.x,coords.z);
+                                                                       currentoffset=DoRotation(animation[currentanimation].offset*-1,0,rotation,0)*scale;
+                                                                       currentoffset.y-=(coords.y-targetoffset.y);
+                                                                       coords.y=targetoffset.y;
+                                                                       targetoffset=0;
+                                                                       normalsupdatedelay=0;
+                                                               }
+                                                               if(currentanimation==upunchanim){
+                                                                       targetanimation=getStop();
+                                                                       normalsupdatedelay=0;
+                                                                       lastfeint=0;
+                                                               }
+                                                               if(currentanimation==rabbitkickanim&&targetanimation!=backflipanim){
+                                                                       targetrotation=rotation;
+                                                                       bool hasstaff;
+                                                                       hasstaff=0;
+                                                                       if(num_weapons>0)if(weapons.type[0]==staff)hasstaff=1;
+                                                                       if(!hasstaff)DoDamage(35);
+                                                                       RagDoll(0);
+                                                                       lastfeint=0;
+                                                                       rabbitkickragdoll=1;
+                                                               }
+                                                               if(currentanimation==rabbitkickreversedanim){
+                                                                       if(!feint){
+                                                                               velocity=0;
+                                                                               velocity.y=-10;
+                                                                               //DoDamage(100);
+                                                                               RagDoll(0);
+                                                                               skeleton.spinny=0;
+                                                                               if(id!=0)SolidHitBonus();
+                                                                       }
+                                                                       if(feint){
+                                                                               escapednum++;
+                                                                               targetanimation=rollanim;
+                                                                               coords+=facing;
+                                                                               if(id==0)FSOUND_SetPaused(channels[whooshsound], TRUE);
+                                                                       }
+                                                                       lastfeint=0;
+                                                               }
+                                                               if(currentanimation==rabbittackledbackanim||currentanimation==rabbittackledfrontanim){
+                                                                       velocity=0;
+                                                                       velocity.y=-10;
+                                                                       RagDoll(0);
+                                                                       skeleton.spinny=0;
+                                                               }
+                                                               if(currentanimation==jumpreversedanim){
+                                                                       if(!feint){
+                                                                               velocity=0;
+                                                                               velocity.y=-10;
+                                                                               //DoDamage(100);
+                                                                               RagDoll(0);
+                                                                               skeleton.spinny=0;
+                                                                               if(id!=0)SolidHitBonus();
+                                                                       }
+                                                                       if(feint){
+                                                                               escapednum++;
+                                                                               targetanimation=rollanim;
+                                                                               coords+=facing*2;
+                                                                               if(id==0)FSOUND_SetPaused(channels[whooshsound], TRUE);
+                                                                       }
+                                                                       lastfeint=0;
+                                                               }
+
+                                                               if(animation[currentanimation].attack==normalattack&&!victim->skeleton.free&&victim->targetanimation!=staggerbackhighanim&&victim->targetanimation!=staggerbackhardanim&&targetanimation!=winduppunchblockedanim&&targetanimation!=blockhighleftanim&&targetanimation!=swordslashparryanim&&targetanimation!=swordslashparriedanim&&targetanimation!=crouchstabanim&&targetanimation!=swordgroundstabanim){
+                                                                       targetanimation=getupfromfrontanim;
+                                                                       lastfeint=0;
+                                                               }
+                                                               else if(animation[currentanimation].attack==normalattack){
+                                                                       targetanimation=getIdle();
+                                                                       lastfeint=0;
+                                                               }
+                                                               if(currentanimation==blockhighleftanim&&aitype!=playercontrolled){
+                                                                       targetanimation=blockhighleftstrikeanim;
+                                                               }
+                                                               if(currentanimation==knifeslashstartanim||currentanimation==knifethrowanim||currentanimation==swordslashanim||currentanimation==staffhitanim||currentanimation==staffgroundsmashanim||currentanimation==staffspinhitanim){
+                                                                       targetanimation=getIdle();
+                                                                       lastfeint=0;
+                                                               }
+                                                               if(currentanimation==spinkickanim&&victim->skeleton.free){
+                                                                       if(creature==rabbittype)targetanimation=fightidleanim;
+                                                               }
+                                                       }
+                                                       target=0;
+
+                                                       if(isIdle()&&!wasIdle())normalsupdatedelay=0;
+
+                                                       if(currentanimation==jumpupanim&&velocity.y<0&&!isFlip()){
+                                                               targetanimation=jumpdownanim;
+                                                       }
+               }
+               if(!skeleton.free){             
+                       oldtarget=target;
+                       if(!transspeed&&animation[targetanimation].attack!=2&&animation[targetanimation].attack!=3){
+                               if(!isRun()||!wasRun()){
+                                       if(animation[targetanimation].speed[targetframe]>animation[currentanimation].speed[currentframe])
+                                               target+=multiplier*animation[targetanimation].speed[targetframe]*speed*2;
+                                       if(animation[targetanimation].speed[targetframe]<=animation[currentanimation].speed[currentframe])
+                                               target+=multiplier*animation[currentanimation].speed[currentframe]*speed*2;
+                               }
+                               if(isRun()&&wasRun()){
+                                       float tempspeed;
+                                       tempspeed=velspeed;
+                                       if(tempspeed<10*speedmult)tempspeed=10*speedmult;
+                                       target+=multiplier*animation[targetanimation].speed[currentframe]*speed*1.7*tempspeed/(speed*45*scale);
+                               }
+                       }
+                       else if(transspeed)target+=multiplier*transspeed*speed*2;
+                       else{
+                               if(!isRun()||!wasRun()){
+                                       if(animation[targetanimation].speed[targetframe]>animation[currentanimation].speed[currentframe])
+                                               target+=multiplier*animation[targetanimation].speed[targetframe]*2;
+                                       if(animation[targetanimation].speed[targetframe]<=animation[currentanimation].speed[currentframe])
+                                               target+=multiplier*animation[currentanimation].speed[currentframe]*2;
+                               }
+                       }
+
+                       if(currentanimation!=targetanimation)target=(target+oldtarget)/2;
+
+                       if(target>1){currentframe=targetframe; target=1;}
+                       oldrot=rot;
+                       rot=targetrot*target;
+                       rotation+=rot-oldrot;
+                       if(target==1){
+                               rot=0;
+                               oldrot=0;
+                               targetrot=0;
+                       }
+                       if(currentanimation!=oldcurrentanimation||targetanimation!=oldtargetanimation||((currentframe!=oldcurrentframe||targetframe!=oldtargetframe)&&!calcrot)){
+                               //Old rotates
+                               for(i=0;i<skeleton.num_joints;i++){
+                                       skeleton.joints[i].position=animation[currentanimation].position[i][currentframe];      
+                               }
+
+                               skeleton.FindForwards();
+
+                               for(i=0;i<skeleton.num_muscles;i++){
+                                       if(skeleton.muscles[i].visible)
+                                       {
+                                               skeleton.FindRotationMuscle(i,targetanimation);
+                                       }
+                               }
+                               for(i=0;i<skeleton.num_muscles;i++){
+                                       if(skeleton.muscles[i].visible)
+                                       {
+                                               if(isnormal((float)((int)(skeleton.muscles[i].rotate1*100)%36000)/100))skeleton.muscles[i].oldrotate1=(float)((int)(skeleton.muscles[i].rotate1*100)%36000)/100;
+                                               if(isnormal((float)((int)(skeleton.muscles[i].rotate2*100)%36000)/100))skeleton.muscles[i].oldrotate2=(float)((int)(skeleton.muscles[i].rotate2*100)%36000)/100;
+                                               if(isnormal((float)((int)(skeleton.muscles[i].rotate3*100)%36000)/100))skeleton.muscles[i].oldrotate3=(float)((int)(skeleton.muscles[i].rotate3*100)%36000)/100;
+                                       }
+                               }
+
+                               //New rotates
+                               for(i=0;i<skeleton.num_joints;i++){
+                                       skeleton.joints[i].position=animation[targetanimation].position[i][targetframe];        
+                               }
+
+                               skeleton.FindForwards();
+
+                               for(i=0;i<skeleton.num_muscles;i++){
+                                       if(skeleton.muscles[i].visible)
+                                       {
+                                               skeleton.FindRotationMuscle(i,targetanimation);
+                                       }
+                               }
+                               for(i=0;i<skeleton.num_muscles;i++){
+                                       if(skeleton.muscles[i].visible)
+                                       {
+                                               if(isnormal((float)((int)(skeleton.muscles[i].rotate1*100)%36000)/100))skeleton.muscles[i].newrotate1=(float)((int)(skeleton.muscles[i].rotate1*100)%36000)/100;
+                                               if(isnormal((float)((int)(skeleton.muscles[i].rotate2*100)%36000)/100))skeleton.muscles[i].newrotate2=(float)((int)(skeleton.muscles[i].rotate2*100)%36000)/100;
+                                               if(isnormal((float)((int)(skeleton.muscles[i].rotate3*100)%36000)/100))skeleton.muscles[i].newrotate3=(float)((int)(skeleton.muscles[i].rotate3*100)%36000)/100;
+                                               if(skeleton.muscles[i].newrotate3>skeleton.muscles[i].oldrotate3+180)skeleton.muscles[i].newrotate3-=360;
+                                               if(skeleton.muscles[i].newrotate3<skeleton.muscles[i].oldrotate3-180)skeleton.muscles[i].newrotate3+=360;
+                                               if(skeleton.muscles[i].newrotate2>skeleton.muscles[i].oldrotate2+180)skeleton.muscles[i].newrotate2-=360;
+                                               if(skeleton.muscles[i].newrotate2<skeleton.muscles[i].oldrotate2-180)skeleton.muscles[i].newrotate2+=360;
+                                               if(skeleton.muscles[i].newrotate1>skeleton.muscles[i].oldrotate1+180)skeleton.muscles[i].newrotate1-=360;
+                                               if(skeleton.muscles[i].newrotate1<skeleton.muscles[i].oldrotate1-180)skeleton.muscles[i].newrotate1+=360;
+                                       }
+                               }
+                       }
+                       if(currentframe>=animation[currentanimation].numframes)currentframe=animation[currentanimation].numframes-1;
+
+                       oldcurrentanimation=currentanimation;
+                       oldtargetanimation=targetanimation;
+                       oldtargetframe=targetframe;
+                       oldcurrentframe=currentframe;
+
+                       for(i=0;i<skeleton.num_joints;i++){
+                               skeleton.joints[i].velocity=(animation[currentanimation].position[i][currentframe]*(1-target)+animation[targetanimation].position[i][targetframe]*(target)-skeleton.joints[i].position)/multiplier;
+                               skeleton.joints[i].position=animation[currentanimation].position[i][currentframe]*(1-target)+animation[targetanimation].position[i][targetframe]*(target);
+                       }
+                       offset=currentoffset*(1-target)+targetoffset*target;
+                       for(i=0;i<skeleton.num_muscles;i++){
+                               if(skeleton.muscles[i].visible)
+                               {
+                                       skeleton.muscles[i].rotate1=skeleton.muscles[i].oldrotate1*(1-target)+skeleton.muscles[i].newrotate1*(target);
+                                       skeleton.muscles[i].rotate2=skeleton.muscles[i].oldrotate2*(1-target)+skeleton.muscles[i].newrotate2*(target);
+                                       skeleton.muscles[i].rotate3=skeleton.muscles[i].oldrotate3*(1-target)+skeleton.muscles[i].newrotate3*(target);
+                               }
+                       }
+               }
+
+               if(isLanding()&&landhard){
+                       //if(abs(velocity.y)>fast_sqrt(velocity.x*velocity.x*velocity.z*velocity.z)){
+                       if(id==0)camerashake+=.4;
+                       targetanimation=getLandhard();
+                       targetframe=0;
+                       target=0;
+                       landhard=0;
+                       transspeed=15;
+                       //}
+               }
+       }
+       //skeleton.DoConstraints();
+}
+
+void   Person::DoStuff(){
+       static XYZ terrainnormal;
+       static XYZ flatfacing;
+       static XYZ flatvelocity;
+       static float flatvelspeed;
+       static int i,j,l;
+       static XYZ average;
+       static int howmany;
+       static int bloodsize;
+       static int startx,starty,endx,endy;
+       static int texdetailint;
+       static GLubyte color;
+       static XYZ bloodvel;
+
+       onfiredelay-=multiplier;
+       if(onfiredelay<0&&onfire)
+       {
+               if(Random()%2==0){
+                       crouchkeydown=1;
+               }
+               onfiredelay=0.3;
+       }
+
+       crouchkeydowntime+=multiplier;
+       if(!crouchkeydown)crouchkeydowntime=0;
+       jumpkeydowntime+=multiplier;
+       if(!jumpkeydown&&skeleton.free)jumpkeydowntime=0;
+
+       if(hostile||damage>0||bloodloss>0)immobile=0;
+
+       if(isIdle()||isRun())targetoffset=0;
+
+       if(num_weapons==1&&weaponactive!=-1)weaponstuck=-1;
+
+       if(id==0)blooddimamount-=multiplier*.3;
+       speechdelay-=multiplier;
+       texupdatedelay-=multiplier;
+       interestdelay-=multiplier;
+       flamedelay-=multiplier;
+       parriedrecently-=multiplier;
+       if(!victim){
+               victim=this;
+               hasvictim=0;
+       }
+
+       if(id==0)speed=1.1*speedmult;
+       else speed=1.0*speedmult;
+       if(!skeleton.free)rabbitkickragdoll=0;
+
+       speed*=speedmult;
+
+       if(id!=0&&(creature==rabbittype||difficulty!=2))superruntoggle=0;
+       if(id!=0&&creature==wolftype&&difficulty==2){
+               superruntoggle=0;
+               if(aitype!=passivetype){
+                       superruntoggle=1;
+                       if(aitype==attacktypecutoff&&(player[0].isIdle()||player[0].isCrouch()||player[0].skeleton.free||player[0].targetanimation==getupfrombackanim||player[0].targetanimation==getupfromfrontanim||player[0].targetanimation==sneakanim)&&findDistancefast(&coords,&player[0].coords)<16){
+                               superruntoggle=0;
+                       }
+               }
+               if(scale<0.2)superruntoggle=0;
+               if(targetanimation==wolfrunninganim&&!superruntoggle){
+                       targetanimation=getRun();
+                       targetframe=0;
+               }
+               /*static float toggledelay;
+               toggledelay-=multiplier;
+               if(toggledelay<0){
+               toggledelay=1;
+               if(Random()%3==0)superruntoggle=1-superruntoggle;
+               }*/
+       }
+       if(weaponactive==-1&&num_weapons>0){
+               if(weapons.type[weaponids[0]]==staff){
+                       weaponactive=0;
+               }
+       }
+
+       if(onfire){
+               burnt+=multiplier;
+               /*if(aitype!=playercontrolled)*///deathbleeding=5;
+               /*if(aitype!=playercontrolled)*/
+               deathbleeding=1;
+               if(burnt>.6)burnt=.6;
+               FSOUND_SetVolume(channels[stream_firesound], 256+256*findLength(&velocity)/3);
+
+               if(targetanimation==jumpupanim||targetanimation==jumpdownanim||isFlip()){
+                       float gLoc[3];
+                       float vel[3];
+                       gLoc[0]=coords.x;
+                       gLoc[1]=coords.y;
+                       gLoc[2]=coords.z;
+                       vel[0]=velocity.x;
+                       vel[1]=velocity.y;
+                       vel[2]=velocity.z;
+
+                       if(id==0){
+                               FSOUND_3D_SetAttributes(channels[whooshsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[whooshsound], 64*findLength(&velocity)/5);
+                       }
+               }
+       }
+       while(flamedelay<0&&onfire){
+               flamedelay+=.006;
+               howmany=abs(Random()%(skeleton.num_joints));
+               if(!skeleton.free)flatvelocity=(coords-oldcoords)/multiplier/2;//velocity/2;
+               if(skeleton.free)flatvelocity=skeleton.joints[howmany].velocity*scale/2;
+               if(!skeleton.free)flatfacing=DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position,0,0,tilt),tilt2,0,0),0,rotation,0)*scale+coords;
+               if(skeleton.free)flatfacing=skeleton.joints[howmany].position*scale+coords;
+               sprites.MakeSprite(flamesprite, flatfacing,flatvelocity, 1,1,1, .6+(float)abs(Random()%100)/200-.25, 1);
+       }
+
+       while(flamedelay<0&&!onfire&&tutoriallevel==1&&id!=0){
+               flamedelay+=.05;
+               howmany=abs(Random()%(skeleton.num_joints));
+               if(!skeleton.free)flatvelocity=(coords-oldcoords)/multiplier/2;//velocity/2;
+               if(skeleton.free)flatvelocity=skeleton.joints[howmany].velocity*scale/2;
+               if(!skeleton.free)flatfacing=DoRotation(DoRotation(DoRotation(skeleton.joints[howmany].position,0,0,tilt),tilt2,0,0),0,rotation,0)*scale+coords;
+               if(skeleton.free)flatfacing=skeleton.joints[howmany].position*scale+coords;
+               sprites.MakeSprite(breathsprite, flatfacing,flatvelocity, 1,1,1, .6+(float)abs(Random()%100)/200-.25, .3);      
+       }
+
+       if(bleeding>0){
+               bleeding-=multiplier*.3;
+               if(bloodtoggle==2){
+                       glBindTexture(GL_TEXTURE_2D,skeleton.drawmodel.textureptr);
+                       if(bleeding<=0&&(detail!=2||osx))DoMipmaps(5,0,0,skeleton.skinsize,skeleton.skinsize);
+               }
+       }
+
+       if(neckspurtamount>0){
+               neckspurtamount-=multiplier;
+               neckspurtdelay-=multiplier*3;
+               neckspurtparticledelay-=multiplier*3;
+               if(neckspurtparticledelay<0&&neckspurtdelay>2){
+                       spurt=0;
+                       bloodvel=0;
+                       if(!skeleton.free){
+                               bloodvel.z=5*neckspurtamount;
+                               bloodvel=DoRotation(bloodvel,((float)(Random()%100))/40,rotation+((float)(Random()%100))/40,0)*scale;
+                       }
+                       if(skeleton.free){
+                               bloodvel-=DoRotation(skeleton.forward*10*scale,((float)(Random()%100))/40,((float)(Random()%100))/40,0);
+                       }
+                       if(skeleton.free)bloodvel+=DoRotation(skeleton.joints[skeleton.jointlabels[head]].velocity,((float)(Random()%100))/40,rotation+((float)(Random()%100))/40,0)*scale;
+                       if(!skeleton.free)bloodvel+=DoRotation(velocity,((float)(Random()%100))/40,((float)(Random()%100))/40,0)*scale;
+                       if(skeleton.free)sprites.MakeSprite(bloodsprite, (skeleton.joints[skeleton.jointlabels[neck]].position+(skeleton.joints[skeleton.jointlabels[neck]].position-skeleton.joints[skeleton.jointlabels[head]].position)/5)*scale+coords,bloodvel, 1,1,1, .05, .9);
+                       if(!skeleton.free)sprites.MakeSprite(bloodsprite, DoRotation(skeleton.joints[skeleton.jointlabels[neck]].position+(skeleton.joints[skeleton.jointlabels[neck]].position-skeleton.joints[skeleton.jointlabels[head]].position)/5,0,rotation,0)*scale+coords,bloodvel, 1,1,1, .05, .9);
+                       neckspurtparticledelay=.05;
+               }
+               if(neckspurtdelay<0){
+                       neckspurtdelay=3;
+               }
+       }
+
+       if(deathbleeding>0&&dead!=2){
+               if(deathbleeding<5)bleeddelay-=deathbleeding*multiplier/4;
+               else bleeddelay-=5*multiplier/4;
+               if(bleeddelay<0&&bloodtoggle){
+                       bleeddelay=1;
+                       XYZ bloodvel;
+                       if(bloodtoggle){
+                               bloodvel=0;
+                               if(skeleton.free)bloodvel+=DoRotation(skeleton.joints[skeleton.jointlabels[abdomen]].velocity,((float)(Random()%100))/4,rotation+((float)(Random()%100))/4,0)*scale;
+                               if(!skeleton.free)bloodvel+=DoRotation(velocity,((float)(Random()%100))/4,((float)(Random()%100))/4,0)*scale;
+                               if(skeleton.free)sprites.MakeSprite(bloodsprite, skeleton.joints[skeleton.jointlabels[abdomen]].position*scale+coords,bloodvel, 1,1,1, .05, 1);
+                               if(!skeleton.free)sprites.MakeSprite(bloodsprite, DoRotation((skeleton.joints[skeleton.jointlabels[abdomen]].position+skeleton.joints[skeleton.jointlabels[abdomen]].position)/2,0,rotation,0)*scale+coords,bloodvel, 1,1,1, .05, 1);
+                       }                       
+               }
+               /*if(id==0){
+               bloodloss+=deathbleeding*40;
+               deathbleeding=0;
+               }*/
+               bloodloss+=deathbleeding*multiplier*80;
+               deathbleeding-=multiplier*1.6;
+               //if(id==0)deathbleeding-=multiplier*.2;
+               if(deathbleeding<0)deathbleeding=0;     
+               if(bloodloss>damagetolerance&&animation[targetanimation].attack==neutral){
+                       if(weaponactive!=-1){
+                               weapons.owner[weaponids[0]]=-1;
+                               weapons.velocity[weaponids[0]]=velocity*scale*-.3;
+                               weapons.velocity[weaponids[0]].x+=.01;
+                               weapons.tipvelocity[weaponids[0]]=velocity*scale;
+                               weapons.missed[weaponids[0]]=1;
+                               weapons.hitsomething[weaponids[0]]=0;
+                               weapons.freetime[weaponids[0]]=0;
+                               weapons.firstfree[weaponids[0]]=1;
+                               weapons.physics[weaponids[0]]=1;
+                               num_weapons--;
+                               if(num_weapons){
+                                       weaponids[0]=weaponids[num_weapons];
+                                       if(weaponstuck==num_weapons)weaponstuck=0;
+                               }
+                               weaponactive=-1;
+                               for(i=0;i<numplayers;i++){
+                                       player[i].wentforweapon=0;
+                               }
+
+                               if(id==0){
+                                       flashamount=.5;
+                                       flashr=1;
+                                       flashg=0;
+                                       flashb=0;
+                                       flashdelay=0;
+                               }
+                       }
+
+                       if(!dead&&creature==wolftype){
+                               bonus=Wolfbonus;
+                               bonustime=0;
+                               bonusvalue=300; 
+                       }
+                       dead=2;
+                       if(targetanimation==knifefollowedanim&&!skeleton.free){
+                               for(i=0;i<skeleton.num_joints;i++){
+                                       skeleton.joints[i].velocity=0;
+                                       skeleton.joints[i].velocity.y=-2;
+                               }
+                       }
+                       if(id!=0&&unconscioustime>.1){
+                               numafterkill++;
+                       }
+
+                       RagDoll(0);
+               }
+       }
+
+       if(texupdatedelay<0&&bleeding>0&&bloodtoggle==2&&findDistancefast(&viewer,&coords)<9){
+               texupdatedelay=.12;
+
+               bloodsize=5-realtexdetail;
+
+               startx=0;
+               starty=0;
+               texdetailint=realtexdetail;
+               startx=bleedy;//abs(Random()%(skeleton.skinsize-bloodsize-1));
+               starty=bleedx;//abs(Random()%(skeleton.skinsize-bloodsize-1));
+               endx=startx+bloodsize;
+               endy=starty+bloodsize;
+
+               if(startx<0){startx=0;bleeding=0;}
+               if(starty<0){starty=0;bleeding=0;}
+               if(endx>skeleton.skinsize-1){endx=skeleton.skinsize-1;bleeding=0;}
+               if(endy>skeleton.skinsize-1){endy=skeleton.skinsize-1;bleeding=0;}
+               if(endx<startx)endx=startx;
+               if(endy<starty)endy=starty;
+               /*int startx=0;
+               int starty=0;
+               int endx=256;
+               int endy=256;*/
+
+               for(i=startx;i<endx;i++){
+                       for(j=starty;j<endy;j++){
+                               if(Random()%2==0){
+                                       color=Random()%85+170;
+                                       if(skeleton.skinText[i*skeleton.skinsize*3+j*3+0]>color/2)skeleton.skinText[i*skeleton.skinsize*3+j*3+0]=color/2;
+                                       skeleton.skinText[i*skeleton.skinsize*3+j*3+1]=0;
+                                       skeleton.skinText[i*skeleton.skinsize*3+j*3+2]=0;
+                               }
+                       }
+               }
+               if(!osx&&detail>1){
+                       glBindTexture(GL_TEXTURE_2D,skeleton.drawmodel.textureptr);
+                       DoMipmaps(0,startx,endx,starty,endy);
+               }
+
+               if(!skeleton.free){
+                       bleedy-=4/realtexdetail;
+                       if(detail==2)bleedx+=(abs(Random()%3)-1)*2/realtexdetail;
+                       else bleedx+=(abs(Random()%3)-1)*4/realtexdetail;
+               }
+               if(skeleton.free){
+                       bleedx+=4*direction/realtexdetail;
+                       if(detail==2)bleedy+=(abs(Random()%3)-1)*2/realtexdetail;
+                       else bleedy+=(abs(Random()%3)-1)*4/realtexdetail;
+               }
+       }
+
+       if(abs(righthandmorphness-targetrighthandmorphness)<multiplier*4){
+               righthandmorphness=targetrighthandmorphness;
+               righthandmorphstart=righthandmorphend;
+       }
+       else if(righthandmorphness>targetrighthandmorphness){
+               righthandmorphness-=multiplier*4;
+       }
+       else if(righthandmorphness<targetrighthandmorphness){
+               righthandmorphness+=multiplier*4;
+       }
+
+       if(abs(lefthandmorphness-targetlefthandmorphness)<multiplier*4){
+               lefthandmorphness=targetlefthandmorphness;
+               lefthandmorphstart=lefthandmorphend;
+       }
+       else if(lefthandmorphness>targetlefthandmorphness){
+               lefthandmorphness-=multiplier*4;
+       }
+       else if(lefthandmorphness<targetlefthandmorphness){
+               lefthandmorphness+=multiplier*4;
+       }
+
+       if(creature==rabbittype||targettailmorphness==5||targettailmorphness==0){
+               if(abs(tailmorphness-targettailmorphness)<multiplier*10){
+                       tailmorphness=targettailmorphness;
+                       tailmorphstart=tailmorphend;
+               }
+               else if(tailmorphness>targettailmorphness){
+                       tailmorphness-=multiplier*10;
+               }
+               else if(tailmorphness<targettailmorphness){
+                       tailmorphness+=multiplier*10;
+               }
+       }
+
+       if(creature==wolftype){
+               if(abs(tailmorphness-targettailmorphness)<multiplier*4){
+                       tailmorphness=targettailmorphness;
+                       tailmorphstart=tailmorphend;
+               }
+               else if(tailmorphness>targettailmorphness){
+                       tailmorphness-=multiplier*2;
+               }
+               else if(tailmorphness<targettailmorphness){
+                       tailmorphness+=multiplier*2;
+               }
+       }
+
+       if(headmorphend==3||headmorphstart==3){
+               if(abs(headmorphness-targetheadmorphness)<multiplier*7){
+                       headmorphness=targetheadmorphness;
+                       headmorphstart=headmorphend;
+               }
+               else if(headmorphness>targetheadmorphness){
+                       headmorphness-=multiplier*7;
+               }
+               else if(headmorphness<targetheadmorphness){
+                       headmorphness+=multiplier*7;
+               }
+       }
+       else if(headmorphend==5||headmorphstart==5){
+               if(abs(headmorphness-targetheadmorphness)<multiplier*10){
+                       headmorphness=targetheadmorphness;
+                       headmorphstart=headmorphend;
+               }
+               else if(headmorphness>targetheadmorphness){
+                       headmorphness-=multiplier*10;
+               }
+               else if(headmorphness<targetheadmorphness){
+                       headmorphness+=multiplier*10;
+               }
+       }
+       else{
+               if(abs(headmorphness-targetheadmorphness)<multiplier*4){
+                       headmorphness=targetheadmorphness;
+                       headmorphstart=headmorphend;
+               }
+               else if(headmorphness>targetheadmorphness){
+                       headmorphness-=multiplier*4;
+               }
+               else if(headmorphness<targetheadmorphness){
+                       headmorphness+=multiplier*4;
+               }
+       }
+
+       if(abs(chestmorphness-targetchestmorphness)<multiplier){
+               chestmorphness=targetchestmorphness;
+               chestmorphstart=chestmorphend;
+       }
+       else if(chestmorphness>targetchestmorphness){
+               chestmorphness-=multiplier;
+       }
+       else if(chestmorphness<targetchestmorphness){
+               chestmorphness+=multiplier;
+       }
+
+       if(dead!=2&&howactive<=typesleeping){
+               if(chestmorphstart==0&&chestmorphend==0){
+                       chestmorphness=0;
+                       targetchestmorphness=1;
+                       chestmorphend=3;
+               }
+               if(chestmorphstart!=0&&chestmorphend!=0){
+                       chestmorphness=0;
+                       targetchestmorphness=1;
+                       chestmorphend=0;
+                       if(environment==snowyenvironment){
+                               XYZ footpoint;
+                               XYZ footvel;
+                               if(!skeleton.free)footvel=DoRotation(skeleton.specialforward[0],0,rotation,0)*-1;
+                               if(skeleton.free)footvel=skeleton.specialforward[0]*-1;
+                               if(!skeleton.free)footpoint=DoRotation((skeleton.joints[skeleton.jointlabels[head]].position+skeleton.joints[skeleton.jointlabels[neck]].position)/2,0,rotation,0)*scale+coords;
+                               if(skeleton.free)footpoint=((skeleton.joints[skeleton.jointlabels[head]].position+skeleton.joints[skeleton.jointlabels[neck]].position)/2)*scale+coords;
+                               if(targetanimation==sleepanim)footvel=DoRotation(footvel,0,90,0);
+                               sprites.MakeSprite(breathsprite, footpoint+footvel*.2,footvel*.4, 1,1,1, .4, .3);                                                       
+                       }
+               }
+
+               if(!dead&&howactive<typesleeping){
+                       blinkdelay-=multiplier*2;
+                       if(headmorphstart==0&&headmorphend==0&&blinkdelay<=0){
+                               headmorphness=0;
+                               targetheadmorphness=1;
+                               headmorphend=3;
+                               blinkdelay=(float)(abs(Random()%40))/5;
+                       }
+                       if(headmorphstart==3&&headmorphend==3){
+                               headmorphness=0;
+                               targetheadmorphness=1;
+                               headmorphend=0;
+                       }
+               }
+               if(!dead){
+                       twitchdelay-=multiplier*1.5;
+                       if(targetanimation!=hurtidleanim){
+                               if(headmorphstart==0&&headmorphend==0&&twitchdelay<=0){
+                                       headmorphness=0;
+                                       targetheadmorphness=1;
+                                       headmorphend=5;
+                                       twitchdelay=(float)(abs(Random()%40))/5;
+                               }
+                               if(headmorphstart==5&&headmorphend==5){
+                                       headmorphness=0;
+                                       targetheadmorphness=1;
+                                       headmorphend=0;
+                               }
+                       }
+                       if((isIdle()||isCrouch())&&targetanimation!=hurtidleanim){
+                               twitchdelay3-=multiplier*1;
+                               if(Random()%2==0){
+                                       if(righthandmorphstart==0&&righthandmorphend==0&&twitchdelay3<=0){
+                                               righthandmorphness=0;
+                                               targetrighthandmorphness=1;
+                                               righthandmorphend=1;
+                                               if(Random()%2==0)twitchdelay3=(float)(abs(Random()%40))/5;
+                                       }
+                                       if(righthandmorphstart==1&&righthandmorphend==1){
+                                               righthandmorphness=0;
+                                               targetrighthandmorphness=1;
+                                               righthandmorphend=0;
+                                       }
+                               }
+                               if(Random()%2==0){
+                                       if(lefthandmorphstart==0&&lefthandmorphend==0&&twitchdelay3<=0){
+                                               lefthandmorphness=0;
+                                               targetlefthandmorphness=1;
+                                               lefthandmorphend=1;
+                                               twitchdelay3=(float)(abs(Random()%40))/5;
+                                       }
+                                       if(lefthandmorphstart==1&&lefthandmorphend==1){
+                                               lefthandmorphness=0;
+                                               targetlefthandmorphness=1;
+                                               lefthandmorphend=0;
+                                       }
+                               }
+                       }
+               }
+               if(!dead){
+                       if(creature==rabbittype){
+                               if(howactive<typesleeping)twitchdelay2-=multiplier*1.5;
+                               else twitchdelay2-=multiplier*0.5;
+                               if(howactive<=typesleeping){
+                                       if(tailmorphstart==0&&tailmorphend==0&&twitchdelay2<=0){
+                                               tailmorphness=0;
+                                               targettailmorphness=1;
+                                               tailmorphend=1;
+                                               twitchdelay2=(float)(abs(Random()%40))/5;
+                                       }
+                                       if(tailmorphstart==1&&tailmorphend==1){
+                                               tailmorphness=0;
+                                               targettailmorphness=1;
+                                               tailmorphend=2;
+                                       }
+                                       if(tailmorphstart==2&&tailmorphend==2){
+                                               tailmorphness=0;
+                                               targettailmorphness=1;
+                                               tailmorphend=0;
+                                       }
+                               }
+                       }
+               }
+       }
+       if(creature==wolftype){                         
+               twitchdelay2-=multiplier*1.5;
+               if(tailmorphend!=0)
+                       if((isRun()||targetanimation==jumpupanim||targetanimation==jumpdownanim||targetanimation==backflipanim)&&!skeleton.free){
+                               tailmorphness=0;
+                               targettailmorphness=1;
+                               tailmorphend=0;
+                               twitchdelay2=.1;
+                       }
+                       if(tailmorphend!=5)
+                               if(targetanimation==flipanim||targetanimation==frontflipanim||targetanimation==rollanim||skeleton.free){
+                                       tailmorphness=0;
+                                       targettailmorphness=1;
+                                       tailmorphend=5;
+                                       twitchdelay2=.1;
+                               }
+                               if(twitchdelay2<=0){
+                                       if(((tailmorphstart==0&&tailmorphend==0)||(tailmorphstart==5&&tailmorphend==5))){
+                                               tailmorphness=0;
+                                               targettailmorphness=1;
+                                               tailmorphend=1;
+                                       }
+                                       if(tailmorphstart==1&&tailmorphend==1){
+                                               tailmorphness=0;
+                                               targettailmorphness=1;
+                                               tailmorphend=2;
+                                       }
+                                       if(tailmorphstart==2&&tailmorphend==2){
+                                               tailmorphness=0;
+                                               targettailmorphness=1;
+                                               tailmorphend=3;
+                                       }
+                                       if(tailmorphstart==3&&tailmorphend==3){
+                                               tailmorphness=0;
+                                               targettailmorphness=1;
+                                               tailmorphend=4;
+                                       }
+                                       if(tailmorphstart==4&&tailmorphend==4){
+                                               tailmorphness=0;
+                                               targettailmorphness=1;
+                                               tailmorphend=1;
+                                       }
+                               }
+       }
+
+       if(dead!=1)unconscioustime=0;
+
+       if(dead==1||howactive==typesleeping){
+               unconscioustime+=multiplier;
+               //If unconscious, close eyes and mouth
+               if(righthandmorphend!=0)righthandmorphness=0;
+               righthandmorphend=0;
+               targetrighthandmorphness=1;
+
+               if(lefthandmorphend!=0)lefthandmorphness=0;
+               lefthandmorphend=0;
+               targetlefthandmorphness=1;
+
+               if(headmorphend!=3&&headmorphend!=5)headmorphness=0;
+               headmorphend=3;
+               targetheadmorphness=1;
+       }
+
+
+       if(howactive>typesleeping){
+               XYZ headpoint;
+               headpoint=coords;
+               if(bloodtoggle&&!bled){
+                       terrain.MakeDecal(blooddecalslow,headpoint,.8,.5,0);
+               }
+               if(bloodtoggle&&!bled)
+                       for(l=0;l<terrain.patchobjectnum[whichpatchx][whichpatchz];l++){
+                               j=terrain.patchobjects[whichpatchx][whichpatchz][l];
+                               XYZ point=DoRotation(headpoint-objects.position[j],0,-objects.rotation[j],0);
+                               float size=.8;
+                               float opacity=.6;
+                               float rotation=0;
+                               objects.model[j].MakeDecal(blooddecalslow,&point,&size,&opacity,&rotation);
+                       }
+                       bled=1;
+       }
+
+       if(dead==2||howactive>typesleeping){
+               //If dead, open mouth and hands
+               if(righthandmorphend!=0)righthandmorphness=0;
+               righthandmorphend=0;
+               targetrighthandmorphness=1;
+
+               if(lefthandmorphend!=0)lefthandmorphness=0;
+               lefthandmorphend=0;
+               targetlefthandmorphness=1;
+
+               if(headmorphend!=2)headmorphness=0;
+               headmorphend=2;
+               targetheadmorphness=1;
+       }
+
+       if(stunned>0&&!dead&&headmorphend!=2){
+               if(headmorphend!=4)headmorphness=0;
+               headmorphend=4;
+               targetheadmorphness=1;
+       }
+
+       if(damage>damagetolerance&&!dead){
+
+               dead=1;
+               unconscioustime=0;
+
+               if(creature==wolftype){
+                       bonus=Wolfbonus;
+                       bonustime=0;
+                       bonusvalue=300; 
+               }
+
+               RagDoll(0);
+
+               if(weaponactive!=-1){
+                       weapons.owner[weaponids[0]]=-1;
+                       weapons.velocity[weaponids[0]]=velocity*scale*-.3;
+                       weapons.velocity[weaponids[0]].x+=.01;
+                       weapons.tipvelocity[weaponids[0]]=velocity*scale;
+                       weapons.missed[weaponids[0]]=1;
+                       weapons.hitsomething[weaponids[0]]=0;
+                       weapons.freetime[weaponids[0]]=0;
+                       weapons.firstfree[weaponids[0]]=1;
+                       weapons.physics[weaponids[0]]=1;
+                       num_weapons--;
+                       if(num_weapons){
+                               weaponids[0]=weaponids[num_weapons];
+                               if(weaponstuck==num_weapons)weaponstuck=0;
+                       }
+                       weaponactive=-1;
+                       for(i=0;i<numplayers;i++){
+                               player[i].wentforweapon=0;
+                       }
+               }
+
+
+
+               if((id==0||findDistancefast(&coords,&viewer)<50)&&autoslomo){
+                       slomo=1;
+                       slomodelay=.2;
+               }
+
+               damage+=20;
+
+               /*
+               if(bloodloss<damagetolerance)
+               for(i=0;i<skeleton.num_joints;i++){
+               skeleton.joints[i].velocity*=1.5;       
+               }*/
+       }
+
+       //if(dead)damage-=multiplier/4;
+       if(!dead)damage-=multiplier*13;
+       //if(!dead&&deathbleeding<=0&&id==0)bloodloss-=multiplier*4;
+       if(!dead)permanentdamage-=multiplier*4;
+       if(isIdle()||isCrouch()){
+               if(!dead)permanentdamage-=multiplier*4;
+               //if(!dead&&deathbleeding<=0&&id==0)bloodloss-=multiplier*4;
+       }
+       if(damage<0)damage=0;
+       if(permanentdamage<0)permanentdamage=0;
+       if(superpermanentdamage<0)superpermanentdamage=0;
+       if(permanentdamage<superpermanentdamage){
+               permanentdamage=superpermanentdamage;
+       }
+       if(damage<permanentdamage){
+               damage=permanentdamage;
+       }
+       if(dead==1&&damage<damagetolerance){
+               dead=0;
+               skeleton.free=1;
+               damage-=20;
+               for(i=0;i<skeleton.num_joints;i++){
+                       skeleton.joints[i].velocity=0;  
+               }
+       }
+       if(permanentdamage>damagetolerance&&dead!=2){
+               DoBlood(1,255);
+
+               if(weaponactive!=-1){
+                       weapons.owner[weaponids[0]]=-1;
+                       weapons.velocity[weaponids[0]]=velocity*scale*-.3;
+                       weapons.velocity[weaponids[0]].x+=.01;
+                       weapons.tipvelocity[weaponids[0]]=velocity*scale;
+                       weapons.missed[weaponids[0]]=1;
+                       weapons.hitsomething[weaponids[0]]=0;
+                       weapons.freetime[weaponids[0]]=0;
+                       weapons.firstfree[weaponids[0]]=1;
+                       weapons.physics[weaponids[0]]=1;
+                       num_weapons--;
+                       if(num_weapons){
+                               weaponids[0]=weaponids[num_weapons];
+                               if(weaponstuck==num_weapons)weaponstuck=0;
+                       }
+                       weaponactive=-1;
+                       for(i=0;i<numplayers;i++){
+                               player[i].wentforweapon=0;
+                       }
+               }
+
+               bled=0;
+
+               if(!dead&&creature==wolftype){
+                       bonus=Wolfbonus;
+                       bonustime=0;
+                       bonusvalue=300; 
+               }
+
+               if(id!=0&&unconscioustime<.1&&(bonus!=spinecrusher||bonustime>1)&&(bonus!=FinishedBonus||bonustime>1)&&bloodloss<damagetolerance){
+                       bonus=touchofdeath;
+                       bonustime=0;
+                       bonusvalue=150;
+               }
+               if(id!=0&&unconscioustime>.1){
+                       numafterkill++;
+               }
+
+               dead=2;
+
+               skeleton.free=1;
+
+               float gLoc[3];
+               float vel[3];
+               gLoc[0]=coords.x;
+               gLoc[1]=coords.y;
+               gLoc[2]=coords.z;
+               vel[0]=velocity.x;
+               vel[1]=velocity.y;
+               vel[2]=velocity.z;
+               PlaySoundEx( breaksound, samp[breaksound], NULL, TRUE);
+               FSOUND_3D_SetAttributes(channels[breaksound], gLoc, vel);
+               FSOUND_SetVolume(channels[breaksound], 512);
+               FSOUND_SetPaused(channels[breaksound], FALSE);
+               /*if(id==0||findDistancefast(&coords,&viewer)<50){
+               slomo=1;
+               slomodelay=.2;
+               }*/
+       }
+
+       if(skeleton.free==1){
+               if(id==0)FSOUND_SetPaused(channels[whooshsound], TRUE);
+
+               if(!dead){
+                       //If knocked over, open hands and close mouth
+                       if(righthandmorphend!=0)righthandmorphness=0;
+                       righthandmorphend=0;
+                       targetrighthandmorphness=1;
+
+                       if(lefthandmorphend!=0)lefthandmorphness=0;
+                       lefthandmorphend=0;
+                       targetlefthandmorphness=1;
+
+                       if(headmorphend!=3&&headmorphend!=5&&headmorphstart!=3&&headmorphstart!=5){
+                               if(headmorphend!=0)headmorphness=0;
+                               headmorphend=0;
+                               targetheadmorphness=1;
+                       }
+               }
+
+               skeleton.DoGravity(&scale);
+               float damageamount;
+               damageamount=skeleton.DoConstraints(&coords,&scale)*5;
+               if(id!=0&&damage>damagetolerance-damageamount&&!dead&&(bonus!=spinecrusher||bonustime>1)&&(bonus!=style||bonustime>1)&&(bonus!=cannon||bonustime>1)){
+                       bonus=deepimpact;
+                       bonustime=0;
+                       bonusvalue=50;
+               }
+               DoDamage(damageamount/((protectionhigh+protectionhead+protectionlow)/3));
+
+               average=0;
+               howmany=0;
+               for(j=0;j<skeleton.num_joints;j++){
+                       average+=skeleton.joints[j].position;
+                       howmany++;
+               }
+               average/=howmany;
+               coords+=average*scale;
+               for(j=0;j<skeleton.num_joints;j++){
+                       skeleton.joints[j].position-=average;
+               }
+               average/=multiplier;
+
+               //velocity=skeleton.joints[skeleton.jointlabels[groin]].velocity*scale;
+               velocity=0;
+               for(i=0;i<skeleton.num_joints;i++){
+                       velocity+=skeleton.joints[i].velocity*scale;
+               }
+               velocity/=skeleton.num_joints;
+
+               if(!isnormal(velocity.x)&&velocity.x){
+                       velocity=0;
+               }
+
+               float gLoc[3];
+               float vel[3];
+               gLoc[0]=coords.x;
+               gLoc[1]=coords.y;
+               gLoc[2]=coords.z;
+               vel[0]=velocity.x;
+               vel[1]=velocity.y;
+               vel[2]=velocity.z;
+
+               if(findLength(&average)<10&&dead&&skeleton.free){
+                       skeleton.longdead+=(2000-findLength(&average))*multiplier+multiplier;
+                       if(skeleton.longdead>2000){
+                               if(skeleton.longdead>6000){
+                                       if(id==0)FSOUND_SetPaused(channels[whooshsound], TRUE);
+                                       skeleton.free=3;
+                                       DrawSkeleton();
+                                       skeleton.free=2;
+                               }
+                               if(dead==2&&bloodloss<damagetolerance){
+                                       XYZ headpoint;
+                                       headpoint=(skeleton.joints[skeleton.jointlabels[head]].position+skeleton.joints[skeleton.jointlabels[neck]].position)/2*scale+coords;
+                                       DoBlood(1,255);
+                                       if(bloodtoggle&&!bled){
+                                               terrain.MakeDecal(blooddecal,headpoint,.2*1.2,.5,0);
+                                       }
+                                       if(bloodtoggle&&!bled)
+                                               for(l=0;l<terrain.patchobjectnum[whichpatchx][whichpatchz];l++){
+                                                       j=terrain.patchobjects[whichpatchx][whichpatchz][l];
+                                                       XYZ point=DoRotation(headpoint-objects.position[j],0,-objects.rotation[j],0);
+                                                       float size=.2*1.2;
+                                                       float opacity=.6;
+                                                       float rotation=0;
+                                                       objects.model[j].MakeDecal(blooddecal,&point,&size,&opacity,&rotation);
+                                               }
+                                               bled=1;
+                               }
+                               if(dead==2&&bloodloss>=damagetolerance){
+                                       XYZ headpoint;
+                                       headpoint=(skeleton.joints[skeleton.jointlabels[abdomen]].position+skeleton.joints[skeleton.jointlabels[neck]].position)/2*scale+coords;
+                                       if(bleeding<=0)DoBlood(1,255);
+                                       if(bloodtoggle&&!bled){
+                                               terrain.MakeDecal(blooddecalslow,headpoint,.8,.5,0);
+                                       }
+                                       if(bloodtoggle&&!bled)
+                                               for(l=0;l<terrain.patchobjectnum[whichpatchx][whichpatchz];l++){
+                                                       j=terrain.patchobjects[whichpatchx][whichpatchz][l];
+                                                       XYZ point=DoRotation(headpoint-objects.position[j],0,-objects.rotation[j],0);
+                                                       float size=.8;
+                                                       float opacity=.6;
+                                                       float rotation=0;
+                                                       objects.model[j].MakeDecal(blooddecalslow,&point,&size,&opacity,&rotation);
+                                               }
+                                               bled=1;
+                               }
+                       }
+               }
+
+               if(!dead&&crouchkeydown&&skeleton.freetime>.5&&id==0&&skeleton.free){
+                       bool canrecover=1;
+                       XYZ startpoint,endpoint,colpoint,colviewer,coltarget;
+                       startpoint=coords;
+                       endpoint=coords;
+                       endpoint.y-=.7;
+                       if(terrain.lineTerrain(startpoint,endpoint,&colpoint)!=-1)canrecover=0;
+                       if(velocity.y<-30)canrecover=0;
+                       for(i=0;i<objects.numobjects;i++){
+                               if(objects.type[i]!=treeleavestype&&objects.type[i]!=bushtype&&objects.type[i]!=firetype){
+                                       colviewer=startpoint;
+                                       coltarget=endpoint;
+                                       if(objects.model[i].LineCheck(&colviewer,&coltarget,&colpoint,&objects.position[i],&objects.rotation[i])!=-1)canrecover=0;      
+                               }
+                       }
+                       if(canrecover){
+                               skeleton.free=0;
+                               XYZ middle;
+                               middle=0;
+
+                               terrainnormal=skeleton.joints[skeleton.jointlabels[groin]].position-skeleton.joints[skeleton.jointlabels[abdomen]].position;
+                               if(skeleton.joints[skeleton.jointlabels[groin]].locked&&skeleton.joints[skeleton.jointlabels[abdomen]].locked){
+                                       terrainnormal=skeleton.joints[skeleton.jointlabels[groin]].position-skeleton.joints[skeleton.jointlabels[abdomen]].position;
+                                       middle=(skeleton.joints[skeleton.jointlabels[groin]].position+skeleton.joints[skeleton.jointlabels[abdomen]].position)/2;
+                               }
+                               if(skeleton.joints[skeleton.jointlabels[abdomen]].locked&&skeleton.joints[skeleton.jointlabels[neck]].locked){
+                                       terrainnormal=skeleton.joints[skeleton.jointlabels[abdomen]].position-skeleton.joints[skeleton.jointlabels[neck]].position;
+                                       middle=(skeleton.joints[skeleton.jointlabels[neck]].position+skeleton.joints[skeleton.jointlabels[abdomen]].position)/2;
+                               }
+                               if(skeleton.joints[skeleton.jointlabels[groin]].locked&&skeleton.joints[skeleton.jointlabels[neck]].locked){
+                                       terrainnormal=skeleton.joints[skeleton.jointlabels[groin]].position-skeleton.joints[skeleton.jointlabels[neck]].position;
+                                       middle=(skeleton.joints[skeleton.jointlabels[groin]].position+skeleton.joints[skeleton.jointlabels[neck]].position)/2;
+                               }
+                               Normalise(&terrainnormal);
+
+                               targetrotation=-asin(0-terrainnormal.x);
+                               targetrotation*=360/6.28;
+                               if(terrainnormal.z<0)targetrotation=180-targetrotation;
+                               rotation=targetrotation;
+
+                               //if(skeleton.forward.y<0){
+                               targetframe=0;
+                               //}
+                               //if(skeleton.forward.y>-.3){
+                               //      targetframe=2;
+                               //}
+                               targetanimation=flipanim;
+                               crouchtogglekeydown=1;
+                               target=0;
+                               tilt2=0;
+                               targettilt2=0;
+
+                               currentanimation=tempanim;
+                               currentframe=0;
+                               target=0;
+                               //tilt2=targettilt2;
+
+                               //if(middle.y>0)targetoffset.y=middle.y+1;
+
+                               for(i=0;i<skeleton.num_joints;i++){
+                                       tempanimation.position[i][0]=skeleton.joints[i].position;
+                                       tempanimation.position[i][0]=DoRotation(tempanimation.position[i][0],0,-rotation,0);
+                               }
+                       }
+               }
+
+               if(findLength(&average)<10&&!dead&&skeleton.free){
+                       skeleton.longdead+=(2000-findLength(&average))*multiplier+multiplier;
+                       if(skeleton.longdead>(damage+500)*1.5){
+                               if(id==0)FSOUND_SetPaused(channels[whooshsound], TRUE);
+                               skeleton.free=0;
+                               velocity=0;
+                               XYZ middle;
+                               middle=0;
+
+                               terrainnormal=skeleton.joints[skeleton.jointlabels[groin]].position-skeleton.joints[skeleton.jointlabels[abdomen]].position;
+                               if(skeleton.joints[skeleton.jointlabels[groin]].locked&&skeleton.joints[skeleton.jointlabels[abdomen]].locked){
+                                       terrainnormal=skeleton.joints[skeleton.jointlabels[groin]].position-skeleton.joints[skeleton.jointlabels[abdomen]].position;
+                                       middle=(skeleton.joints[skeleton.jointlabels[groin]].position+skeleton.joints[skeleton.jointlabels[abdomen]].position)/2;
+                               }
+                               if(skeleton.joints[skeleton.jointlabels[abdomen]].locked&&skeleton.joints[skeleton.jointlabels[neck]].locked){
+                                       terrainnormal=skeleton.joints[skeleton.jointlabels[abdomen]].position-skeleton.joints[skeleton.jointlabels[neck]].position;
+                                       middle=(skeleton.joints[skeleton.jointlabels[neck]].position+skeleton.joints[skeleton.jointlabels[abdomen]].position)/2;
+                               }
+                               if(skeleton.joints[skeleton.jointlabels[groin]].locked&&skeleton.joints[skeleton.jointlabels[neck]].locked){
+                                       terrainnormal=skeleton.joints[skeleton.jointlabels[groin]].position-skeleton.joints[skeleton.jointlabels[neck]].position;
+                                       middle=(skeleton.joints[skeleton.jointlabels[groin]].position+skeleton.joints[skeleton.jointlabels[neck]].position)/2;
+                               }
+                               Normalise(&terrainnormal);
+
+                               targetrotation=-asin(0-terrainnormal.x);
+                               targetrotation*=360/6.28;
+                               if(terrainnormal.z<0)targetrotation=180-targetrotation;
+                               rotation=targetrotation;
+
+                               /*if(onterrain){
+                               terrainnormal=terrain.getNormal(coords.x,coords.z);
+                               targettilt2=asin(terrainnormal.y)*180/3.14*-1;
+                               }
+                               else*/
+
+                               /*XYZ otherterrainnormal;
+                               otherterrainnormal=terrain.getNormal(coords.x,coords.y);
+                               otherterrainnormal.y=fast_sqrt(otherterrainnormal.x*otherterrainnormal.x+otherterrainnormal.z*otherterrainnormal.z)*-1;
+                               if(abs(terrainnormal.y)<abs(otherterrainnormal.y))terrainnormal.y=fast_sqrt(otherterrainnormal.x*otherterrainnormal.x+otherterrainnormal.z*otherterrainnormal.z)*-1;
+                               targettilt2=asin(otherterrainnormal.y)*180/3.14;
+                               */
+
+                               targettilt2=asin(terrainnormal.y)*180/3.14*-1;
+
+
+
+                               if(skeleton.forward.y<0){
+                                       targetanimation=getupfrombackanim;
+                                       targetframe=0;
+                                       targettilt2=0;
+                               }
+                               if(skeleton.forward.y>-.3){
+                                       targetanimation=getupfromfrontanim;
+                                       rotation+=180;
+                                       targetrotation+=180;
+                                       targettilt2*=-1;
+                                       targetframe=0;
+                                       targettilt2=0;
+                               }
+
+                               if((Random()%8==0&&id!=0&&creature==rabbittype)||(Random()%2==0&&id!=0&&creature==wolftype)||(id==0&&crouchkeydown&&(forwardkeydown||backkeydown||leftkeydown||rightkeydown))){
+                                       targetanimation=rollanim;
+                                       targetrotation=lookrotation;
+                                       if(id==0){
+                                               if(rightkeydown){
+                                                       targetrotation-=90;
+                                                       if(forwardkeydown)targetrotation+=45;
+                                                       if(backkeydown)targetrotation-=45;
+                                               }
+                                               if(leftkeydown){
+                                                       targetrotation+=90;
+                                                       if(forwardkeydown)targetrotation-=45;
+                                                       if(backkeydown)targetrotation+=45;
+                                               }
+                                               if(backkeydown){
+                                                       if ( !leftkeydown&&!rightkeydown)
+                                                               targetrotation+=180;
+                                               }
+                                               targetrotation+=180;
+                                       }
+                               }
+
+                               if(abs(targettilt2)>50)targettilt2=0;
+                               currentanimation=tempanim;
+                               currentframe=0;
+                               target=0;
+                               tilt2=targettilt2;
+
+                               if(middle.y>0&&targetanimation!=rollanim)targetoffset.y=middle.y+1;
+
+                               for(i=0;i<skeleton.num_joints;i++){
+                                       tempanimation.position[i][0]=skeleton.joints[i].position;
+                                       tempanimation.position[i][0]=DoRotation(tempanimation.position[i][0],0,-rotation,0);
+                               }
+                       }
+               }
+
+               bool hasstaff;
+               hasstaff=0;
+               if(num_weapons>0)if(weapons.type[0]==staff)hasstaff=1;
+               if(!skeleton.freefall&&freefall&&((jumpkeydown&&jumpkeydowntime<.2)||(hasstaff&&rabbitkickragdoll))&&!dead){
+                       if(velocity.y>-30){
+                               XYZ tempvelocity;
+                               tempvelocity=velocity;
+                               Normalise(&tempvelocity);
+                               targetrotation=-asin(0-tempvelocity.x);
+                               targetrotation*=360/6.28;
+                               if(velocity.z<0)targetrotation=180-targetrotation;
+                               //targetrotation+=180;
+
+                               skeleton.free=0;
+                               if(dotproduct(&skeleton.forward,&tempvelocity)<0){
+                                       targetanimation=rollanim;
+                                       targetframe=2;
+                               }
+                               else{
+                                       targetanimation=backhandspringanim;
+                                       targetrotation+=180;
+                                       targetframe=6;
+                               }
+                               target=0;
+
+                               float gLoc[3];
+                               float vel[3];
+                               gLoc[0]=coords.x;
+                               gLoc[1]=coords.y;
+                               gLoc[2]=coords.z;
+                               vel[0]=velocity.x;
+                               vel[1]=velocity.y;
+                               vel[2]=velocity.z;
+                               PlaySoundEx( movewhooshsound, samp[movewhooshsound], NULL, TRUE);
+                               FSOUND_3D_SetAttributes(channels[movewhooshsound], gLoc, vel);
+                               FSOUND_SetVolume(channels[movewhooshsound], 128);
+                               FSOUND_SetPaused(channels[movewhooshsound], FALSE);
+
+                               currentanimation=targetanimation;
+                               currentframe=targetframe-1;
+                               target=0;
+
+                               velocity=0;
+
+                               rotation=targetrotation;
+                               tilt=0;
+                               targettilt=0;
+                               tilt2=0;
+                               targettilt2=0;
+                       }
+               }
+               if(skeleton.freefall==0)freefall=0;
+
+               if(!isnormal(velocity.x)&&velocity.x){
+                       int xy=1;
+               }
+       }
+
+       if(aitype!=passivetype||skeleton.free==1)
+               if(findLengthfast(&velocity)>.1)
+                       for(i=0;i<objects.numobjects;i++){
+                               if(objects.type[i]==firetype)
+                                       if(findDistancefastflat(&coords,&objects.position[i])<objects.scale[i]*objects.scale[i]*12&&findDistancefast(&coords,&objects.position[i])<objects.scale[i]*objects.scale[i]*49){
+                                               if(onfire){
+                                                       if(!objects.onfire[i]){
+                                                               float gLoc[3];
+                                                               float vel[3];
+                                                               gLoc[0]=objects.position[i].x;
+                                                               gLoc[1]=objects.position[i].y;
+                                                               gLoc[2]=objects.position[i].z;
+                                                               vel[0]=0;
+                                                               vel[1]=0;
+                                                               vel[2]=0;
+                                                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[firestartsound], 256);
+                                                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                                                       }
+                                                       objects.onfire[i]=1;
+                                               }
+                                               if(!onfire){
+                                                       if(objects.onfire[i]){
+                                                               CatchFire();
+                                                       }
+                                               }
+                                       }
+                                       if(objects.type[i]==bushtype)
+                                               if(findDistancefastflat(&coords,&objects.position[i])<objects.scale[i]*objects.scale[i]*12&&findDistancefast(&coords,&objects.position[i])<objects.scale[i]*objects.scale[i]*49){
+                                                       if(onfire){
+                                                               if(!objects.onfire[i]){
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=objects.position[i].x;
+                                                                       gLoc[1]=objects.position[i].y;
+                                                                       gLoc[2]=objects.position[i].z;
+                                                                       vel[0]=0;
+                                                                       vel[1]=0;
+                                                                       vel[2]=0;
+                                                                       PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[firestartsound], 256);
+                                                                       FSOUND_SetPaused(channels[firestartsound], FALSE);
+                                                               }
+                                                               objects.onfire[i]=1;
+                                                       }
+
+                                                       if(!onfire){
+                                                               if(objects.onfire[i]){
+                                                                       CatchFire();
+                                                               }
+                                                       }
+                                                       if(objects.messedwith[i]<=0){
+                                                               XYZ tempvel;
+                                                               XYZ pos;
+
+                                                               float gLoc[3];
+                                                               float vel[3];
+                                                               gLoc[0]=coords.x;
+                                                               gLoc[1]=coords.y;
+                                                               gLoc[2]=coords.z;
+                                                               vel[0]=velocity.x;
+                                                               vel[1]=velocity.y;
+                                                               vel[2]=velocity.z;
+                                                               PlaySoundEx( bushrustle, samp[bushrustle], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[bushrustle], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[bushrustle], 40*findLength(&velocity));
+                                                               FSOUND_SetPaused(channels[bushrustle], FALSE);
+
+                                                               if(id==0){
+                                                                       envsound[numenvsounds]=coords;
+                                                                       envsoundvol[numenvsounds]=4*findLength(&velocity);
+                                                                       envsoundlife[numenvsounds]=.4;
+                                                                       numenvsounds++;
+                                                               }
+
+                                                               int howmany;
+                                                               if(environment==grassyenvironment)howmany=findLength(&velocity)*4;
+                                                               if(environment==snowyenvironment)howmany=findLength(&velocity)*2;
+                                                               if(detail==2)
+                                                                       if(environment!=desertenvironment)
+                                                                               for(j=0;j<howmany;j++){
+                                                                                       tempvel.x=float(abs(Random()%100)-50)/20;
+                                                                                       tempvel.y=float(abs(Random()%100)-50)/20;
+                                                                                       tempvel.z=float(abs(Random()%100)-50)/20;
+                                                                                       pos=coords;
+                                                                                       pos.y+=1;
+                                                                                       pos.x+=float(abs(Random()%100)-50)/200;
+                                                                                       pos.y+=float(abs(Random()%100)-50)/200;
+                                                                                       pos.z+=float(abs(Random()%100)-50)/200;
+                                                                                       sprites.MakeSprite(splintersprite, pos,tempvel*.5+velocity*float(abs(Random()%100))/100, 165/255+float(abs(Random()%100)-50)/400,0,0, .2+float(abs(Random()%100)-50)/1300, 1);
+                                                                                       sprites.special[sprites.numsprites-1]=1;
+                                                                               }
+                                                                               howmany=findLength(&velocity)*4;
+                                                                               if(detail==2)
+                                                                                       if(environment==snowyenvironment)
+                                                                                               for(j=0;j<howmany;j++){
+                                                                                                       tempvel.x=float(abs(Random()%100)-50)/20;
+                                                                                                       tempvel.y=float(abs(Random()%100)-50)/20;
+                                                                                                       tempvel.z=float(abs(Random()%100)-50)/20;
+                                                                                                       pos=coords;
+                                                                                                       pos.y+=1;
+                                                                                                       pos.x+=float(abs(Random()%100)-50)/200;
+                                                                                                       pos.y+=float(abs(Random()%100)-50)/200;
+                                                                                                       pos.z+=float(abs(Random()%100)-50)/200;
+                                                                                                       sprites.MakeSprite(splintersprite, pos,tempvel*.3+velocity*float(abs(Random()%100))/100/2, 1,1,1, .1, 1);
+                                                                                                       sprites.special[sprites.numsprites-1]=2;
+                                                                                               }
+                                                       }
+                                                       objects.rotx[i]+=velocity.x*multiplier*6;
+                                                       objects.roty[i]+=velocity.z*multiplier*6;       
+                                                       objects.messedwith[i]=.5;
+                                               }
+                                               XYZ tempcoord;
+                                               if(objects.type[i]==treeleavestype&&environment!=desertenvironment){
+                                                       if(objects.rotation2[i]==0)tempcoord=coords;
+                                                       else{
+                                                               tempcoord=coords-objects.position[i];
+                                                               tempcoord=DoRotation(tempcoord,0,-objects.rotation[i],0);
+                                                               tempcoord=DoRotation(tempcoord,-objects.rotation2[i],0,0);
+                                                               tempcoord+=objects.position[i];
+                                                       }
+                                                       if(findDistancefastflat(&tempcoord,&objects.position[i])<objects.scale[i]*objects.scale[i]*8&&findDistancefast(&tempcoord,&objects.position[i])<objects.scale[i]*objects.scale[i]*300&&tempcoord.y>objects.position[i].y+3*objects.scale[i]){
+                                                               /*if(onfire){
+                                                               if(!objects.onfire[i]){
+                                                               float gLoc[3];
+                                                               float vel[3];
+                                                               gLoc[0]=objects.position[i].x;
+                                                               gLoc[1]=objects.position[i].y;
+                                                               gLoc[2]=objects.position[i].z;
+                                                               vel[0]=0;
+                                                               vel[1]=0;
+                                                               vel[2]=0;
+                                                               PlaySoundEx( firestartsound, samp[firestartsound], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[firestartsound], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[firestartsound], 256);
+                                                               FSOUND_SetPaused(channels[firestartsound], FALSE);
+                                                               objects.onfire[i]=1;
+                                                               }
+                                                               }*/
+                                                               if(objects.messedwith[i]<=0){
+                                                                       XYZ tempvel;
+                                                                       XYZ pos;
+
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=coords.x;
+                                                                       gLoc[1]=coords.y;
+                                                                       gLoc[2]=coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+                                                                       PlaySoundEx( bushrustle, samp[bushrustle], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[bushrustle], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[bushrustle], 40*findLength(&velocity));
+                                                                       FSOUND_SetPaused(channels[bushrustle], FALSE);
+
+                                                                       if(id==0){
+                                                                               envsound[numenvsounds]=coords;
+                                                                               envsoundvol[numenvsounds]=4*findLength(&velocity);
+                                                                               envsoundlife[numenvsounds]=.4;
+                                                                               numenvsounds++;
+                                                                       }
+
+                                                                       int howmany;
+                                                                       if(environment==grassyenvironment)howmany=findLength(&velocity)*4;
+                                                                       if(environment==snowyenvironment)howmany=findLength(&velocity)*2;
+                                                                       if(detail==2)
+                                                                               if(environment!=desertenvironment)
+                                                                                       for(j=0;j<howmany;j++){
+                                                                                               tempvel.x=float(abs(Random()%100)-50)/20;
+                                                                                               tempvel.y=float(abs(Random()%100)-50)/20;
+                                                                                               tempvel.z=float(abs(Random()%100)-50)/20;
+                                                                                               pos=coords;
+                                                                                               pos+=velocity*.1;
+                                                                                               pos.y+=1;
+                                                                                               pos.x+=float(abs(Random()%100)-50)/150;
+                                                                                               pos.y+=float(abs(Random()%100)-50)/150;
+                                                                                               pos.z+=float(abs(Random()%100)-50)/150;
+                                                                                               sprites.MakeSprite(splintersprite, pos,tempvel*.5+velocity*float(abs(Random()%100))/100, 165/255+float(abs(Random()%100)-50)/400,0,0, .2+float(abs(Random()%100)-50)/1300, 1);
+                                                                                               sprites.special[sprites.numsprites-1]=1;
+                                                                                       }
+                                                                                       howmany=findLength(&velocity)*4;
+                                                                                       if(detail==2)
+                                                                                               if(environment==snowyenvironment)
+                                                                                                       for(j=0;j<howmany;j++){
+                                                                                                               tempvel.x=float(abs(Random()%100)-50)/20;
+                                                                                                               tempvel.y=float(abs(Random()%100)-50)/20;
+                                                                                                               tempvel.z=float(abs(Random()%100)-50)/20;
+                                                                                                               pos=coords;
+                                                                                                               pos+=velocity*.1;
+                                                                                                               pos.y+=1;
+                                                                                                               pos.x+=float(abs(Random()%100)-50)/150;
+                                                                                                               pos.y+=float(abs(Random()%100)-50)/150;
+                                                                                                               pos.z+=float(abs(Random()%100)-50)/150;
+                                                                                                               sprites.MakeSprite(splintersprite, pos,tempvel*.3+velocity*float(abs(Random()%100))/100/2, 1,1,1, .1, 1);
+                                                                                                               sprites.special[sprites.numsprites-1]=2;
+                                                                                                       }
+                                                               }
+                                                               objects.messedwith[i]=.5;
+                                                       }       
+                                               }
+                       }
+
+                       if(!skeleton.free){     
+                               bool play;
+                               play=0;
+                               if((stunned>0||surprised>0)&&numplayers>2&&aitype!=passivetype)play=1;
+                               if(hasvictim)
+                                       if(aitype!=passivetype&&victim->skeleton.free&&!victim->dead)play=1;
+                               if(tutoriallevel==1&&id!=0)play=0;
+                               if(play&&aitype!=playercontrolled){
+                                       int whichsound=-1;
+                                       float gLoc[3];
+                                       float vel[3];
+                                       gLoc[0]=coords.x;
+                                       gLoc[1]=coords.y;
+                                       gLoc[2]=coords.z;
+                                       vel[0]=velocity.x;
+                                       vel[1]=velocity.y;
+                                       vel[2]=velocity.z;
+                                       i=abs(Random()%4);
+                                       if(speechdelay<=0){
+                                               if(creature==rabbittype){
+                                                       if(i==0)whichsound=rabbitchitter;
+                                                       if(i==1)whichsound=rabbitchitter2;
+                                               }
+                                               if(creature==wolftype){
+                                                       if(i==0)whichsound=growlsound;
+                                                       if(i==1)whichsound=growl2sound;
+                                               }
+                                       }
+                                       speechdelay=.3;
+                                       //else if(animation[targetanimation].label[targetframe]==4)whichsound=knifeswishsound;
+                                       //if(animation[targetanimation].label[targetframe]==8)whichsound=landsound2;
+
+                                       if(whichsound!=-1){
+                                               PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                                               FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                                               FSOUND_SetVolume(channels[whichsound], 512);
+                                               FSOUND_SetPaused(channels[whichsound], FALSE);
+                                       }       
+                               }       
+
+                               if(targetanimation==staggerbackhighanim)staggerdelay=1;
+                               if(targetanimation==staggerbackhardanim)staggerdelay=1;
+                               staggerdelay-=multiplier;
+                               if(targetanimation!=crouchstabanim&&targetanimation!=swordgroundstabanim&&targetanimation!=staffgroundsmashanim)hasvictim=1;
+                               if(velocity.y<-30&&targetanimation==jumpdownanim)RagDoll(0);
+                               if(currentanimation!=getIdle()&&wasIdle()&&targetanimation!=getIdle()&&isIdle()){
+                                       targetanimation=getIdle();
+                                       targetframe=0;
+                                       target=0;
+                               }
+                               weaponmissdelay-=multiplier;
+                               highreversaldelay-=multiplier;
+                               lowreversaldelay-=multiplier;
+                               lastcollide-=multiplier;
+                               skiddelay-=multiplier;
+                               if(!isnormal(velocity.x)&&velocity.x){
+                                       velocity=0;
+                               }
+                               if(!isnormal(targettilt)&&targettilt){
+                                       targettilt=0;
+                               }
+                               if(!isnormal(targettilt2)&&targettilt2){
+                                       targettilt2=0;
+                               }
+                               if(!isnormal(targetrotation)&&targetrotation){
+                                       targetrotation=0;
+                               }
+
+                               if(targetanimation==bounceidleanim||targetanimation==wolfidle||targetanimation==walkanim||targetanimation==drawrightanim||targetanimation==crouchdrawrightanim||targetanimation==drawleftanim||targetanimation==fightidleanim||targetanimation==fightsidestep||targetanimation==hanganim||isCrouch()||targetanimation==backhandspringanim){
+                                       //open hands and close mouth
+                                       //if(targetanimation!=wolfidle){
+                                       if(righthandmorphend!=0&&righthandmorphness==targetrighthandmorphness){
+                                               righthandmorphness=0;
+                                               righthandmorphend=0;
+                                               targetrighthandmorphness=1;
+                                       }
+
+                                       if(lefthandmorphend!=0&&lefthandmorphness==targetlefthandmorphness){
+                                               lefthandmorphness=0;
+                                               lefthandmorphend=0;
+                                               targetlefthandmorphness=1;
+                                       }
+                                       //s}
+
+                                       if(headmorphend!=3&&headmorphend!=5&&headmorphstart!=3&&headmorphstart!=5&&headmorphend!=0&&headmorphness==targetheadmorphness){
+                                               headmorphness=0;
+                                               headmorphend=0;
+                                               targetheadmorphness=1;
+                                       }
+                               }
+
+                               if(targetanimation==rollanim||targetanimation==dodgebackanim||targetanimation==removeknifeanim||targetanimation==knifefightidleanim||targetanimation==swordfightidleanim||targetanimation==blockhighleftstrikeanim||targetanimation==crouchremoveknifeanim||targetanimation==sneakanim||targetanimation==sweepanim||targetanimation==spinkickreversedanim||targetanimation==jumpdownanim||isWallJump()||isFlip()||targetanimation==climbanim||isRun()||targetanimation==getupfrombackanim||targetanimation==getupfromfrontanim){
+                                       //open hands and mouth
+                                       if(righthandmorphend!=0&&righthandmorphness==targetrighthandmorphness){
+                                               righthandmorphness=0;
+                                               righthandmorphend=0;
+                                               targetrighthandmorphness=1;
+                                       }
+
+                                       if(lefthandmorphend!=0&&lefthandmorphness==targetlefthandmorphness){
+                                               lefthandmorphness=0;
+                                               lefthandmorphend=0;
+                                               targetlefthandmorphness=1;
+                                       }
+
+                                       if(headmorphend!=1&&headmorphness==targetheadmorphness){
+                                               headmorphness=0;
+                                               headmorphend=1;
+                                               targetheadmorphness=1;
+                                       }
+                               }
+
+                               if(targetanimation==jumpupanim||targetanimation==crouchstabanim||targetanimation==swordgroundstabanim||targetanimation==swordfightidlebothanim||targetanimation==blockhighleftanim||targetanimation==blockhighleftanim){
+                                       //close hands and mouth
+                                       if(righthandmorphend!=1&&righthandmorphness==targetrighthandmorphness){
+                                               righthandmorphness=0;
+                                               righthandmorphend=1;
+                                               targetrighthandmorphness=1;
+                                       }
+
+                                       if(lefthandmorphend!=1&&lefthandmorphness==targetlefthandmorphness){
+                                               lefthandmorphness=0;
+                                               lefthandmorphend=1;
+                                               targetlefthandmorphness=1;
+                                       }
+
+                                       if(headmorphend!=0&&headmorphness==targetheadmorphness){
+                                               headmorphness=0;
+                                               headmorphend=0;
+                                               targetheadmorphness=1;
+                                       }
+                               }
+
+                               if(targetanimation==spinkickanim||targetanimation==staffspinhitreversalanim||targetanimation==staffspinhitreversedanim||targetanimation==staffhitreversalanim||targetanimation==staffhitreversedanim||targetanimation==hurtidleanim||targetanimation==winduppunchanim||targetanimation==swordslashreversalanim||targetanimation==swordslashreversedanim||targetanimation==knifeslashreversalanim||targetanimation==knifeslashreversedanim||targetanimation==knifethrowanim||targetanimation==knifefollowanim||targetanimation==knifefollowedanim||targetanimation==killanim||targetanimation==dropkickanim||targetanimation==upunchanim||targetanimation==knifeslashstartanim||targetanimation==swordslashanim||targetanimation==staffhitanim||targetanimation==staffspinhitanim||targetanimation==staffgroundsmashanim||targetanimation==spinkickreversalanim||targetanimation==sweepreversalanim||targetanimation==lowkickanim||targetanimation==sweepreversedanim||targetanimation==rabbitkickreversalanim||targetanimation==rabbitkickreversedanim||targetanimation==jumpreversalanim||targetanimation==jumpreversedanim){
+                                       //close hands and yell
+                                       if(righthandmorphend!=1&&righthandmorphness==targetrighthandmorphness){
+                                               righthandmorphness=0;
+                                               righthandmorphend=1;
+                                               targetrighthandmorphness=1;
+                                       }
+
+                                       if(lefthandmorphend!=1&&lefthandmorphness==targetlefthandmorphness){
+                                               lefthandmorphness=0;
+                                               lefthandmorphend=1;
+                                               targetlefthandmorphness=1;
+                                       }
+
+                                       if(headmorphend!=2&&headmorphness==targetheadmorphness){
+                                               headmorphness=1;
+                                               headmorphend=2;
+                                               targetheadmorphness=1;
+                                       }
+                               }
+                               /*
+                               if(speechdelay>.25){                    
+                               if(headmorphend!=2)headmorphness=0;
+                               headmorphend=2;
+                               targetheadmorphness=1;
+                               }
+                               */
+                               bool behind;
+                               behind=0;
+                               if(hasvictim){
+                                       if(victim!=this&&!victim->dead&&victim->aitype!=passivetype&&victim->aitype!=searchtype&&aitype!=passivetype&&aitype!=searchtype&&victim->id<numplayers&&aitype!=passivetype){
+                                               behind=(normaldotproduct(facing,coords-victim->coords)>0);
+                                       }
+                               }
+
+                               if(!dead&&targetanimation!=hurtidleanim)
+                                       if(behind||targetanimation==killanim||targetanimation==knifethrowanim||targetanimation==knifefollowanim||targetanimation==spinkickreversalanim||targetanimation==rabbitkickreversedanim||targetanimation==jumpreversedanim){
+                                               if(headmorphend!=4||headmorphness==targetheadmorphness){
+                                                       headmorphend=4;
+                                                       //headmorphness=1;
+                                                       targetheadmorphness=1;
+                                               }
+                                       }
+
+                                       if(weaponactive!=-1){
+                                               if(weapons.type[weaponids[weaponactive]]!=staff){
+                                                       righthandmorphstart=1;
+                                                       righthandmorphend=1;
+                                               }
+                                               if(weapons.type[weaponids[weaponactive]]==staff){
+                                                       righthandmorphstart=2;
+                                                       righthandmorphend=2;
+                                               }
+                                               targetrighthandmorphness=1;
+                                       }
+
+                                       terrainnormal=terrain.getNormal(coords.x,coords.z);
+
+                                       if(animation[targetanimation].attack!=reversal){
+                                               if(!isnormal(coords.x))
+                                                       coords=oldcoords;
+                                               oldcoords=coords;
+                                       }
+
+                                       flatfacing=0;
+                                       flatfacing.z=1;
+
+                                       flatfacing=DoRotation(flatfacing,0,rotation,0);
+                                       facing=flatfacing;
+                                       ReflectVector(&facing,&terrainnormal);
+                                       Normalise(&facing);
+
+                                       if(isRun()||targetanimation==sneakanim||targetanimation==rollanim||targetanimation==walkanim){
+                                               if(onterrain)targettilt2=-facing.y*20;
+                                               else targettilt2=0;
+                                       }
+                                       onterrain=0;
+                                       if(!isRun()&&!animation[targetanimation].attack&&targetanimation!=getupfromfrontanim&&targetanimation!=getupfrombackanim&&targetanimation!=sneakanim)targettilt2=0;
+                                       if(targetanimation==jumpupanim||targetanimation==jumpdownanim||isFlip()){
+                                               flatvelocity=velocity;
+                                               flatvelocity.y=0;
+                                               flatvelspeed=findLength(&flatvelocity);
+                                               targettilt=flatvelspeed*fast_sqrt(abs(velocity.y)*.7)*normaldotproduct(DoRotation(flatfacing,0,-90,0),flatvelocity);
+                                               targettilt2=flatvelspeed*fast_sqrt(abs(velocity.y)*.7)*normaldotproduct(flatfacing,flatvelocity);
+                                               if(velocity.y<0)targettilt2*=-1;
+                                               if(velocity.y<0)targettilt*=-1;
+                                               if(targettilt>25)targettilt=25;
+                                               if(targettilt<-25)targettilt=-25;
+                                       }
+
+                                       if(targettilt2>45)targettilt2=45;
+                                       if(targettilt2<-45)targettilt2=-45;
+                                       if(abs(tilt2-targettilt2)<multiplier*400)tilt2=targettilt2;
+                                       else if(tilt2>targettilt2){
+                                               tilt2-=multiplier*400;
+                                       }
+                                       else if(tilt2<targettilt2){
+                                               tilt2+=multiplier*400;
+                                       }
+                                       if(!animation[targetanimation].attack&&targetanimation!=getupfrombackanim&&targetanimation!=getupfromfrontanim){
+                                               if(tilt2>25)tilt2=25;
+                                               if(tilt2<-25)tilt2=-25;
+                                       }
+
+                                       if(!isnormal(targettilt)&&targettilt){
+                                               targettilt=0;
+                                       }
+                                       if(!isnormal(targettilt2)&&targettilt2){
+                                               targettilt2=0;
+                                       }
+
+                                       //Running velocity
+                                       //if(!creature==wolftype||targetanimation==rabbitkickanim)
+                                       if(targetanimation==rabbittackleanim){
+                                               velocity+=facing*multiplier*speed*700*scale;
+                                               velspeed=findLength(&velocity); 
+                                               if(velspeed>speed*65*scale){
+                                                       velocity/=velspeed;
+                                                       velspeed=speed*65*scale;
+                                                       velocity*=velspeed;
+                                               }
+                                               velocity.y+=gravity*multiplier*20;
+                                               ReflectVector(&velocity,&terrain.getNormal(coords.x,coords.z));
+                                               velspeed=findLength(&velocity); 
+                                               velocity=flatfacing*velspeed;
+                                       }
+                                       if(targetanimation!=rabbitrunninganim&&targetanimation!=wolfrunninganim){
+                                               if(isRun()||targetanimation==rabbitkickanim){
+                                                       velocity+=facing*multiplier*speed*700*scale;
+                                                       velspeed=findLength(&velocity); 
+                                                       if(velspeed>speed*45*scale){
+                                                               velocity/=velspeed;
+                                                               velspeed=speed*45*scale;
+                                                               velocity*=velspeed;
+                                                       }
+                                                       velocity.y+=gravity*multiplier*20;
+                                                       ReflectVector(&velocity,&terrain.getNormal(coords.x,coords.z));
+                                                       velspeed=findLength(&velocity); 
+                                                       if(velspeed<speed*30*scale)velspeed=speed*30*scale;
+                                                       velocity=flatfacing*velspeed;
+                                               }
+                                       }
+                                       else if(isRun()){
+                                               velocity+=facing*multiplier*speed*700*scale;
+                                               velspeed=findLength(&velocity); 
+                                               if(creature==rabbittype){
+                                                       if(velspeed>speed*55*scale){
+                                                               velocity/=velspeed;
+                                                               velspeed=speed*55*scale;
+                                                               velocity*=velspeed;
+                                                       }
+                                               }
+                                               if(creature==wolftype){
+                                                       if(velspeed>speed*75*scale){
+                                                               velocity/=velspeed;
+                                                               velspeed=speed*75*scale;
+                                                               velocity*=velspeed;
+                                                       }
+                                               }
+                                               velocity.y+=gravity*multiplier*20;
+                                               ReflectVector(&velocity,&terrain.getNormal(coords.x,coords.z));
+                                               velspeed=findLength(&velocity); 
+                                               velocity=flatfacing*velspeed;
+                                       }
+
+                                       /*if(creature==wolftype)
+                                       if(isRun()){
+                                       velocity+=facing*multiplier*speed*700*scale;
+                                       velspeed=findLength(&velocity); 
+                                       if(velspeed>speed*55*scale){
+                                       velocity/=velspeed;
+                                       velspeed=speed*55*scale;
+                                       velocity*=velspeed;
+                                       }
+                                       velocity.y+=gravity*multiplier*20;
+                                       ReflectVector(&velocity,&terrain.getNormal(coords.x,coords.z));
+                                       velspeed=findLength(&velocity); 
+                                       velocity=flatfacing*velspeed;
+                                       }*/
+
+                                       if(targetanimation==rollanim&&animation[targetanimation].label[targetframe]!=6){
+                                               velocity+=facing*multiplier*speed*700*scale;
+                                               velspeed=findLength(&velocity); 
+                                               if(velspeed>speed*45*scale){
+                                                       velocity/=velspeed;
+                                                       velspeed=speed*45*scale;
+                                                       velocity*=velspeed;
+                                               }
+                                               velocity.y+=gravity*multiplier*20;
+                                               ReflectVector(&velocity,&terrain.getNormal(coords.x,coords.z));
+                                               velspeed=findLength(&velocity); 
+                                               velocity=flatfacing*velspeed;
+                                       }
+
+
+                                       /*if(currentanimation==rollanim&&(isCrouch()||isIdle())){
+                                       velocity+=facing*multiplier*speed*700*scale;
+                                       velspeed=findLength(&velocity); 
+                                       if(velspeed>speed*25*scale){
+                                       velocity/=velspeed;
+                                       velspeed=speed*25*scale;
+                                       velocity*=velspeed;
+                                       }
+                                       velocity.y+=gravity*multiplier*20;
+                                       ReflectVector(&velocity,&terrain.getNormal(coords.x,coords.z));
+                                       velspeed=findLength(&velocity); 
+                                       velocity=flatfacing*velspeed;
+                                       }*/
+
+                                       if(targetanimation==sneakanim||targetanimation==walkanim){
+                                               velocity+=facing*multiplier*speed*700*scale;
+                                               velspeed=findLength(&velocity); 
+                                               if(velspeed>speed*12*scale){
+                                                       velocity/=velspeed;
+                                                       velspeed=speed*12*scale;
+                                                       velocity*=velspeed;
+                                               }
+                                               velocity.y+=gravity*multiplier*20;
+                                               ReflectVector(&velocity,&terrain.getNormal(coords.x,coords.z));
+                                               velspeed=findLength(&velocity); 
+                                               velocity=flatfacing*velspeed;
+                                       }
+
+                                       if((targetanimation==fightidleanim||targetanimation==knifefightidleanim)&&(currentanimation==bounceidleanim||currentanimation==hurtidleanim)){
+                                               velocity+=facing*multiplier*speed*700*scale;
+                                               velspeed=findLength(&velocity); 
+                                               if(velspeed>speed*2*scale){
+                                                       velocity/=velspeed;
+                                                       velspeed=speed*2*scale;
+                                                       velocity*=velspeed;
+                                               }
+                                               velocity.y+=gravity*multiplier*20;
+                                               ReflectVector(&velocity,&terrain.getNormal(coords.x,coords.z));
+                                               velspeed=findLength(&velocity); 
+                                               velocity=flatfacing*velspeed;
+                                       }
+
+
+                                       if((targetanimation==bounceidleanim||currentanimation==hurtidleanim)&&(currentanimation==fightidleanim||currentanimation==knifefightidleanim)){
+                                               velocity-=facing*multiplier*speed*700*scale;
+                                               velspeed=findLength(&velocity); 
+                                               if(velspeed>speed*2*scale){
+                                                       velocity/=velspeed;
+                                                       velspeed=speed*2*scale;
+                                                       velocity*=velspeed;
+                                               }
+                                               velocity.y+=gravity*multiplier*20;
+                                               ReflectVector(&velocity,&terrain.getNormal(coords.x,coords.z));
+                                               velspeed=findLength(&velocity); 
+                                               velocity=flatfacing*velspeed*-1;
+                                       }
+
+                                       if(targetanimation==fightsidestep){
+                                               velocity+=DoRotation(facing*multiplier*speed*700*scale,0,-90,0);
+                                               velspeed=findLength(&velocity); 
+                                               if(velspeed>speed*12*scale){
+                                                       velocity/=velspeed;
+                                                       velspeed=speed*12*scale;
+                                                       velocity*=velspeed;
+                                               }
+                                               velocity.y+=gravity*multiplier*20;
+                                               ReflectVector(&velocity,&terrain.getNormal(coords.x,coords.z));
+                                               velspeed=findLength(&velocity); 
+                                               velocity=DoRotation(flatfacing*velspeed,0,-90,0);
+                                       }
+
+                                       if(targetanimation==staggerbackhighanim){
+                                               coords-=facing*multiplier*speed*16*scale;
+                                               velocity=0;
+                                       }
+                                       if(targetanimation==staggerbackhardanim&&animation[staggerbackhardanim].label[targetframe]!=6){
+                                               coords-=facing*multiplier*speed*20*scale;
+                                               velocity=0;
+                                       }
+
+                                       if(targetanimation==backhandspringanim){
+                                               //coords-=facing*multiplier*50*scale;
+                                               velocity+=facing*multiplier*speed*700*scale*-1;
+                                               velspeed=findLength(&velocity); 
+                                               if(velspeed>speed*50*scale){
+                                                       velocity/=velspeed;
+                                                       velspeed=speed*50*scale;
+                                                       velocity*=velspeed;
+                                               }
+                                               velocity.y+=gravity*multiplier*20;
+                                               ReflectVector(&velocity,&terrain.getNormal(coords.x,coords.z));
+                                               velspeed=findLength(&velocity); 
+                                               velocity=flatfacing*velspeed*-1;
+                                       }
+                                       if(targetanimation==dodgebackanim){
+                                               //coords-=facing*multiplier*50*scale;
+                                               velocity+=facing*multiplier*speed*700*scale*-1;
+                                               velspeed=findLength(&velocity); 
+                                               if(velspeed>speed*60*scale){
+                                                       velocity/=velspeed;
+                                                       velspeed=speed*60*scale;
+                                                       velocity*=velspeed;
+                                               }
+                                               velocity.y+=gravity*multiplier*20;
+                                               ReflectVector(&velocity,&terrain.getNormal(coords.x,coords.z));
+                                               velspeed=findLength(&velocity); 
+                                               velocity=flatfacing*velspeed*-1;
+                                       }
+
+                                       if(targetanimation==jumpupanim||targetanimation==jumpdownanim||isFlip()){
+                                               velspeed=findLength(&velocity); 
+                                       }
+
+
+                                       if(targetanimation==jumpupanim||targetanimation==jumpdownanim||isFlip()){
+                                               velocity.y+=gravity*multiplier;
+                                       }
+
+                                       if(targetanimation!=climbanim&&targetanimation!=hanganim&&!isWallJump())coords+=velocity*multiplier;
+
+                                       if(coords.y<terrain.getHeight(coords.x,coords.z)&&(targetanimation==jumpdownanim||targetanimation==jumpupanim||isFlip())){
+                                               if(isFlip()&&animation[targetanimation].label[targetframe]==7)RagDoll(0);
+
+                                               if(targetanimation==jumpupanim){jumppower=-4;targetanimation=getIdle();}
+                                               target=0;
+                                               targetframe=0;  
+                                               onterrain=1;
+
+                                               if(id==0){
+                                                       FSOUND_SetPaused(channels[whooshsound], TRUE);
+                                                       FSOUND_SetVolume(channels[whooshsound], 0);
+                                               }
+
+                                               if(targetanimation==jumpdownanim||isFlip()){
+                                                       if(isFlip())jumppower=-4;
+                                                       targetanimation=getLanding();
+                                                       float gLoc[3];
+                                                       float vel[3];
+                                                       gLoc[0]=coords.x;
+                                                       gLoc[1]=coords.y;
+                                                       gLoc[2]=coords.z;
+                                                       vel[0]=velocity.x;
+                                                       vel[1]=velocity.y;
+                                                       vel[2]=velocity.z;
+                                                       PlaySoundEx( landsound, samp[landsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[landsound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[landsound], 128);
+                                                       FSOUND_SetPaused(channels[landsound], FALSE);
+
+                                                       if(id==0){
+                                                               envsound[numenvsounds]=coords;
+                                                               envsoundvol[numenvsounds]=16;
+                                                               envsoundlife[numenvsounds]=.4;
+                                                               numenvsounds++;
+                                                       }
+                                               }
+                                       }
+
+                                       if(targetanimation!=jumpupanim&&targetanimation!=jumpdownanim&&!isFlip()&&targetanimation!=climbanim&&targetanimation!=hanganim&&!isWallJump())coords.y+=gravity*multiplier*2;
+                                       if(targetanimation!=jumpupanim&&targetanimation!=jumpdownanim&&!isFlip()&&coords.y<terrain.getHeight(coords.x,coords.z)){
+                                               coords.y=terrain.getHeight(coords.x,coords.z);
+                                               onterrain=1;
+                                       }
+
+
+                                       if(isIdle()||targetanimation==drawrightanim||targetanimation==drawleftanim||targetanimation==crouchdrawrightanim||targetanimation==crouchstabanim||targetanimation==swordgroundstabanim||isStop()||targetanimation==removeknifeanim||targetanimation==crouchremoveknifeanim||isLanding()||isCrouch()||animation[targetanimation].attack||(targetanimation==rollanim&&animation[targetanimation].label[targetframe]==6)){
+                                               velspeed=findLength(&velocity); 
+                                               velocity.y=0;
+                                               if(velspeed<multiplier*300*scale){
+                                                       velocity=0;
+                                               } else velocity-=velocity/velspeed*multiplier*300*scale;
+                                               if(velspeed>5&&(isLanding()||isLandhard())){
+                                                       skiddingdelay+=multiplier;
+                                                       if(skiddelay<=0){
+                                                               FootLand(0,.5);
+                                                               FootLand(1,.5);
+                                                               skiddelay=.02;
+                                                       }
+                                               }
+                                               else skiddingdelay=0;
+                                       }
+
+                                       if(isLandhard()){
+                                               velspeed=findLength(&velocity); 
+                                               velocity.y=0;
+                                               if(velspeed<multiplier*600*scale){
+                                                       velocity=0;
+                                               } else velocity-=velocity/velspeed*multiplier*600*scale;
+                                               velocity=0;
+                                               if(velspeed>5&&(isLanding()||isLandhard())){
+                                                       skiddingdelay+=multiplier;
+                                                       if(skiddelay<=0){
+                                                               FootLand(0,.5);
+                                                               FootLand(1,.5);
+                                                               skiddelay=.02;
+                                                       }
+                                               }
+                                               else skiddingdelay=0;
+                                       }
+
+                                       if(skiddingdelay<0)skiddingdelay+=multiplier;
+                                       if(skiddingdelay>.02&&!forwardkeydown&&!backkeydown&&!leftkeydown&&!rightkeydown&&!jumpkeydown&&isLanding()&&!landhard){
+                                               skiddingdelay=-1;
+                                               float gLoc[3];
+                                               float vel[3];
+                                               gLoc[0]=coords.x;
+                                               gLoc[1]=coords.y;
+                                               gLoc[2]=coords.z;
+                                               vel[0]=velocity.x;
+                                               vel[1]=velocity.y;
+                                               vel[2]=velocity.z;
+                                               if(!onterrain||environment==grassyenvironment){
+                                                       PlaySoundEx( skidsound, samp[skidsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[skidsound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[skidsound], 128*velspeed/10);
+                                                       FSOUND_SetPaused(channels[skidsound], FALSE);
+                                               }
+                                               else {
+                                                       PlaySoundEx( snowskidsound, samp[snowskidsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[snowskidsound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[snowskidsound], 128*velspeed/10);
+                                                       FSOUND_SetPaused(channels[snowskidsound], FALSE);
+                                               }
+                                       }
+
+                                       if(animation[targetanimation].attack==normalattack&&targetanimation!=rabbitkickanim&&!victim->skeleton.free){
+                                               terrainnormal=victim->coords-coords;
+                                               Normalise(&terrainnormal);
+                                               targetrotation=-asin(0-terrainnormal.x);
+                                               targetrotation*=360/6.28;
+                                               if(terrainnormal.z<0)targetrotation=180-targetrotation;
+                                               targettilt2=-asin(terrainnormal.y)*360/6.28;//*-70;
+                                       }
+
+                                       if(animation[targetanimation].attack==reversal&&targetanimation!=rabbittacklinganim){
+                                               targetrotation=victim->targetrotation;
+                                       }
+                                       if(targetanimation==rabbittacklinganim){
+                                               coords=victim->coords;
+                                       }
+                       }
+                       skeleton.oldfree=skeleton.free; 
+
+                       XYZ midterrain;
+                       midterrain=0;
+                       midterrain.x=terrain.size*terrain.scale/2;
+                       midterrain.z=terrain.size*terrain.scale/2;
+                       if(findDistancefastflat(&coords,&midterrain)>(terrain.size*terrain.scale/2-viewdistance)*(terrain.size*terrain.scale/2-viewdistance)){
+                               XYZ tempposit;
+                               tempposit=coords-midterrain;
+                               tempposit.y=0;
+                               Normalise(&tempposit);
+                               tempposit*=(terrain.size*terrain.scale/2-viewdistance);
+                               coords.x=tempposit.x+midterrain.x;
+                               coords.z=tempposit.z+midterrain.z;
+                       }
+}
+
+int Person::DrawSkeleton(){
+       int oldplayerdetail;
+       if((frustum.SphereInFrustum(coords.x,coords.y+scale*3,coords.z,scale*8)&&findDistancefast(&viewer,&coords)<viewdistance*viewdistance)||skeleton.free==3){  
+               if(onterrain&&(isIdle()||isCrouch()||wasIdle()||wasCrouch())&&!skeleton.free){
+                       calcrot=1;
+               }
+
+               if(headless){
+                       headmorphness=0;
+                       headmorphstart=6;
+                       headmorphend=6;
+               }
+
+               glAlphaFunc(GL_GREATER, 0.0001);
+               XYZ terrainlight;
+               float terrainheight;
+               float distance;
+               if(!isnormal(rotation))rotation=0;
+               if(!isnormal(tilt))tilt=0;
+               if(!isnormal(tilt2))tilt2=0;
+               oldplayerdetail=playerdetail;
+               playerdetail=0;
+               if(findDistancefast(&viewer,&coords)<viewdistance*viewdistance/32&&detail==2){
+                       playerdetail=1;
+               }
+               if(findDistancefast(&viewer,&coords)<viewdistance*viewdistance/128&&detail==1){
+                       playerdetail=1;
+               }
+               if(findDistancefast(&viewer,&coords)<viewdistance*viewdistance/256&&(detail!=1&&detail!=2)){
+                       playerdetail=1;
+               }
+               if(id==0)playerdetail=1;
+               if(playerdetail!=oldplayerdetail)updatedelay=0;
+               if(playerdetail!=oldplayerdetail)normalsupdatedelay=0;
+               static float updatedelaychange;
+               static float morphness;
+               static float framemult;
+               if(calcrot){
+                       skeleton.FindForwards();
+                       if(howactive==typesittingwall){
+                               skeleton.specialforward[1]=0;
+                               skeleton.specialforward[1].z=1;
+                       }
+               }
+               static XYZ mid;
+               static float M[16];
+               static int i,j,k;
+               static int weaponattachmuscle;
+               static int weaponrotatemuscle,weaponrotatemuscle2;
+               static XYZ weaponpoint;
+               static int start,endthing;
+               if((dead!=2||skeleton.free!=2)&&updatedelay<=0){
+                       if(!isSleeping()&&!isSitting()){
+                               if(onterrain&&((isIdle()||isCrouch()||isLanding()||isLandhard()||targetanimation==drawrightanim||targetanimation==drawleftanim||targetanimation==crouchdrawrightanim)&&(wasIdle()||wasCrouch()||wasLanding()||wasLandhard()||currentanimation==drawrightanim||currentanimation==drawleftanim||currentanimation==crouchdrawrightanim))&&!skeleton.free){
+                                       XYZ point,newpoint,change,change2;
+                                       point=DoRotation(skeleton.joints[skeleton.jointlabels[leftfoot]].position,0,rotation,0)*scale+coords;
+                                       heightleft=terrain.getHeight(point.x,point.z)+.04;
+                                       point.y=heightleft;
+                                       change=skeleton.joints[skeleton.jointlabels[leftankle]].position-skeleton.joints[skeleton.jointlabels[leftfoot]].position;
+                                       change2=skeleton.joints[skeleton.jointlabels[leftknee]].position-skeleton.joints[skeleton.jointlabels[leftfoot]].position;
+                                       skeleton.joints[skeleton.jointlabels[leftfoot]].position=DoRotation((point-coords)/scale,0,-rotation,0);
+                                       skeleton.joints[skeleton.jointlabels[leftankle]].position=skeleton.joints[skeleton.jointlabels[leftfoot]].position+change;
+                                       skeleton.joints[skeleton.jointlabels[leftknee]].position=(skeleton.joints[skeleton.jointlabels[leftfoot]].position+change2)/2+(skeleton.joints[skeleton.jointlabels[leftknee]].position)/2;
+
+                                       point=DoRotation(skeleton.joints[skeleton.jointlabels[rightfoot]].position,0,rotation,0)*scale+coords;
+                                       heightright=terrain.getHeight(point.x,point.z)+.04;
+                                       point.y=heightright;
+                                       change=skeleton.joints[skeleton.jointlabels[rightankle]].position-skeleton.joints[skeleton.jointlabels[rightfoot]].position;
+                                       change2=skeleton.joints[skeleton.jointlabels[rightknee]].position-skeleton.joints[skeleton.jointlabels[rightfoot]].position;
+                                       skeleton.joints[skeleton.jointlabels[rightfoot]].position=DoRotation((point-coords)/scale,0,-rotation,0);
+                                       skeleton.joints[skeleton.jointlabels[rightankle]].position=skeleton.joints[skeleton.jointlabels[rightfoot]].position+change;
+                                       skeleton.joints[skeleton.jointlabels[rightknee]].position=(skeleton.joints[skeleton.jointlabels[rightfoot]].position+change2)/2+(skeleton.joints[skeleton.jointlabels[rightknee]].position)/2;
+                                       skeleton.DoConstraints(&coords,&scale);
+
+                                       if(creature==wolftype){
+                                               point=DoRotation(skeleton.joints[skeleton.jointlabels[leftfoot]].position,0,rotation,0)*scale+coords;
+                                               heightleft=terrain.getHeight(point.x,point.z)+.04;
+                                               point.y=heightleft;
+                                               change=skeleton.joints[skeleton.jointlabels[leftankle]].position-skeleton.joints[skeleton.jointlabels[leftfoot]].position;
+                                               change2=skeleton.joints[skeleton.jointlabels[leftknee]].position-skeleton.joints[skeleton.jointlabels[leftfoot]].position;
+                                               skeleton.joints[skeleton.jointlabels[leftfoot]].position=DoRotation((point-coords)/scale,0,-rotation,0);
+                                               skeleton.joints[skeleton.jointlabels[leftankle]].position=skeleton.joints[skeleton.jointlabels[leftfoot]].position+change;
+                                               skeleton.joints[skeleton.jointlabels[leftknee]].position=(skeleton.joints[skeleton.jointlabels[leftfoot]].position+change2)/2+(skeleton.joints[skeleton.jointlabels[leftknee]].position)/2;
+
+                                               point=DoRotation(skeleton.joints[skeleton.jointlabels[rightfoot]].position,0,rotation,0)*scale+coords;
+                                               heightright=terrain.getHeight(point.x,point.z)+.04;
+                                               point.y=heightright;
+                                               change=skeleton.joints[skeleton.jointlabels[rightankle]].position-skeleton.joints[skeleton.jointlabels[rightfoot]].position;
+                                               change2=skeleton.joints[skeleton.jointlabels[rightknee]].position-skeleton.joints[skeleton.jointlabels[rightfoot]].position;
+                                               skeleton.joints[skeleton.jointlabels[rightfoot]].position=DoRotation((point-coords)/scale,0,-rotation,0);
+                                               skeleton.joints[skeleton.jointlabels[rightankle]].position=skeleton.joints[skeleton.jointlabels[rightfoot]].position+change;
+                                               skeleton.joints[skeleton.jointlabels[rightknee]].position=(skeleton.joints[skeleton.jointlabels[rightfoot]].position+change2)/2+(skeleton.joints[skeleton.jointlabels[rightknee]].position)/2;
+                                               skeleton.DoConstraints(&coords,&scale);
+                                       }
+                               }
+                               if(onterrain&&((isIdle()||isCrouch()||isLanding()||isLandhard()||targetanimation==drawrightanim||targetanimation==drawleftanim||targetanimation==crouchdrawrightanim)&&!(wasIdle()||wasCrouch()||wasLanding()||wasLandhard()||currentanimation==drawrightanim||currentanimation==drawleftanim||currentanimation==crouchdrawrightanim))&&!skeleton.free){
+                                       XYZ point,newpoint,change,change2;
+                                       point=DoRotation(skeleton.joints[skeleton.jointlabels[leftfoot]].position,0,rotation,0)*scale+coords;
+                                       heightleft=terrain.getHeight(point.x,point.z)+.04;
+                                       point.y=heightleft;
+                                       change=skeleton.joints[skeleton.jointlabels[leftankle]].position-skeleton.joints[skeleton.jointlabels[leftfoot]].position;
+                                       change2=skeleton.joints[skeleton.jointlabels[leftknee]].position-skeleton.joints[skeleton.jointlabels[leftfoot]].position;
+                                       skeleton.joints[skeleton.jointlabels[leftfoot]].position=DoRotation((point-coords)/scale,0,-rotation,0)*target+skeleton.joints[skeleton.jointlabels[leftfoot]].position*(1-target);
+                                       skeleton.joints[skeleton.jointlabels[leftankle]].position=skeleton.joints[skeleton.jointlabels[leftfoot]].position+change;
+                                       skeleton.joints[skeleton.jointlabels[leftknee]].position=(skeleton.joints[skeleton.jointlabels[leftfoot]].position+change2)/2+(skeleton.joints[skeleton.jointlabels[leftknee]].position)/2;
+
+                                       point=DoRotation(skeleton.joints[skeleton.jointlabels[rightfoot]].position,0,rotation,0)*scale+coords;
+                                       heightright=terrain.getHeight(point.x,point.z)+.04;
+                                       point.y=heightright;
+                                       change=skeleton.joints[skeleton.jointlabels[rightankle]].position-skeleton.joints[skeleton.jointlabels[rightfoot]].position;
+                                       change2=skeleton.joints[skeleton.jointlabels[rightknee]].position-skeleton.joints[skeleton.jointlabels[rightfoot]].position;
+                                       skeleton.joints[skeleton.jointlabels[rightfoot]].position=DoRotation((point-coords)/scale,0,-rotation,0)*target+skeleton.joints[skeleton.jointlabels[rightfoot]].position*(1-target);
+                                       skeleton.joints[skeleton.jointlabels[rightankle]].position=skeleton.joints[skeleton.jointlabels[rightfoot]].position+change;
+                                       skeleton.joints[skeleton.jointlabels[rightknee]].position=(skeleton.joints[skeleton.jointlabels[rightfoot]].position+change2)/2+(skeleton.joints[skeleton.jointlabels[rightknee]].position)/2;
+                                       skeleton.DoConstraints(&coords,&scale);
+
+                                       if(creature==wolftype){
+                                               point=DoRotation(skeleton.joints[skeleton.jointlabels[leftfoot]].position,0,rotation,0)*scale+coords;
+                                               heightleft=terrain.getHeight(point.x,point.z)+.04;
+                                               point.y=heightleft;
+                                               change=skeleton.joints[skeleton.jointlabels[leftankle]].position-skeleton.joints[skeleton.jointlabels[leftfoot]].position;
+                                               change2=skeleton.joints[skeleton.jointlabels[leftknee]].position-skeleton.joints[skeleton.jointlabels[leftfoot]].position;
+                                               skeleton.joints[skeleton.jointlabels[leftfoot]].position=DoRotation((point-coords)/scale,0,-rotation,0)*target+skeleton.joints[skeleton.jointlabels[leftfoot]].position*(1-target);
+                                               skeleton.joints[skeleton.jointlabels[leftankle]].position=skeleton.joints[skeleton.jointlabels[leftfoot]].position+change;
+                                               skeleton.joints[skeleton.jointlabels[leftknee]].position=(skeleton.joints[skeleton.jointlabels[leftfoot]].position+change2)/2+(skeleton.joints[skeleton.jointlabels[leftknee]].position)/2;
+
+                                               point=DoRotation(skeleton.joints[skeleton.jointlabels[rightfoot]].position,0,rotation,0)*scale+coords;
+                                               heightright=terrain.getHeight(point.x,point.z)+.04;
+                                               point.y=heightright;
+                                               change=skeleton.joints[skeleton.jointlabels[rightankle]].position-skeleton.joints[skeleton.jointlabels[rightfoot]].position;
+                                               change2=skeleton.joints[skeleton.jointlabels[rightknee]].position-skeleton.joints[skeleton.jointlabels[rightfoot]].position;
+                                               skeleton.joints[skeleton.jointlabels[rightfoot]].position=DoRotation((point-coords)/scale,0,-rotation,0)*target+skeleton.joints[skeleton.jointlabels[rightfoot]].position*(1-target);
+                                               skeleton.joints[skeleton.jointlabels[rightankle]].position=skeleton.joints[skeleton.jointlabels[rightfoot]].position+change;
+                                               skeleton.joints[skeleton.jointlabels[rightknee]].position=(skeleton.joints[skeleton.jointlabels[rightfoot]].position+change2)/2+(skeleton.joints[skeleton.jointlabels[rightknee]].position)/2;
+                                               skeleton.DoConstraints(&coords,&scale);
+                                       }
+                               }
+
+                               if(onterrain&&(!(isIdle()||isCrouch()||isLanding()||isLandhard()||targetanimation==drawrightanim||targetanimation==drawleftanim||targetanimation==crouchdrawrightanim)&&(wasIdle()||wasCrouch()||wasLanding()||wasLandhard()||currentanimation==drawrightanim||currentanimation==drawleftanim||currentanimation==crouchdrawrightanim))&&!skeleton.free){
+                                       XYZ point,newpoint,change,change2;
+                                       point=DoRotation(skeleton.joints[skeleton.jointlabels[leftfoot]].position,0,rotation,0)*scale+coords;
+                                       heightleft=terrain.getHeight(point.x,point.z)+.04;
+                                       point.y=heightleft;
+                                       change=skeleton.joints[skeleton.jointlabels[leftankle]].position-skeleton.joints[skeleton.jointlabels[leftfoot]].position;
+                                       change2=skeleton.joints[skeleton.jointlabels[leftknee]].position-skeleton.joints[skeleton.jointlabels[leftfoot]].position;
+                                       skeleton.joints[skeleton.jointlabels[leftfoot]].position=DoRotation((point-coords)/scale,0,-rotation,0)*(1-target)+skeleton.joints[skeleton.jointlabels[leftfoot]].position*target;
+                                       skeleton.joints[skeleton.jointlabels[leftankle]].position=skeleton.joints[skeleton.jointlabels[leftfoot]].position+change;
+                                       skeleton.joints[skeleton.jointlabels[leftknee]].position=(skeleton.joints[skeleton.jointlabels[leftfoot]].position+change2)/2+(skeleton.joints[skeleton.jointlabels[leftknee]].position)/2;
+
+                                       point=DoRotation(skeleton.joints[skeleton.jointlabels[rightfoot]].position,0,rotation,0)*scale+coords;
+                                       heightright=terrain.getHeight(point.x,point.z)+.04;
+                                       point.y=heightright;
+                                       change=skeleton.joints[skeleton.jointlabels[rightankle]].position-skeleton.joints[skeleton.jointlabels[rightfoot]].position;
+                                       change2=skeleton.joints[skeleton.jointlabels[rightknee]].position-skeleton.joints[skeleton.jointlabels[rightfoot]].position;
+                                       skeleton.joints[skeleton.jointlabels[rightfoot]].position=DoRotation((point-coords)/scale,0,-rotation,0)*(1-target)+skeleton.joints[skeleton.jointlabels[rightfoot]].position*target;
+                                       skeleton.joints[skeleton.jointlabels[rightankle]].position=skeleton.joints[skeleton.jointlabels[rightfoot]].position+change;
+                                       skeleton.joints[skeleton.jointlabels[rightknee]].position=(skeleton.joints[skeleton.jointlabels[rightfoot]].position+change2)/2+(skeleton.joints[skeleton.jointlabels[rightknee]].position)/2;
+                                       skeleton.DoConstraints(&coords,&scale);
+
+                                       if(creature==wolftype){
+                                               point=DoRotation(skeleton.joints[skeleton.jointlabels[leftfoot]].position,0,rotation,0)*scale+coords;
+                                               heightleft=terrain.getHeight(point.x,point.z)+.04;
+                                               point.y=heightleft;
+                                               change=skeleton.joints[skeleton.jointlabels[leftankle]].position-skeleton.joints[skeleton.jointlabels[leftfoot]].position;
+                                               change2=skeleton.joints[skeleton.jointlabels[leftknee]].position-skeleton.joints[skeleton.jointlabels[leftfoot]].position;
+                                               skeleton.joints[skeleton.jointlabels[leftfoot]].position=DoRotation((point-coords)/scale,0,-rotation,0)*(1-target)+skeleton.joints[skeleton.jointlabels[leftfoot]].position*target;
+                                               skeleton.joints[skeleton.jointlabels[leftankle]].position=skeleton.joints[skeleton.jointlabels[leftfoot]].position+change;
+                                               skeleton.joints[skeleton.jointlabels[leftknee]].position=(skeleton.joints[skeleton.jointlabels[leftfoot]].position+change2)/2+(skeleton.joints[skeleton.jointlabels[leftknee]].position)/2;
+
+                                               point=DoRotation(skeleton.joints[skeleton.jointlabels[rightfoot]].position,0,rotation,0)*scale+coords;
+                                               heightright=terrain.getHeight(point.x,point.z)+.04;
+                                               point.y=heightright;
+                                               change=skeleton.joints[skeleton.jointlabels[rightankle]].position-skeleton.joints[skeleton.jointlabels[rightfoot]].position;
+                                               change2=skeleton.joints[skeleton.jointlabels[rightknee]].position-skeleton.joints[skeleton.jointlabels[rightfoot]].position;
+                                               skeleton.joints[skeleton.jointlabels[rightfoot]].position=DoRotation((point-coords)/scale,0,-rotation,0)*(1-target)+skeleton.joints[skeleton.jointlabels[rightfoot]].position*target;
+                                               skeleton.joints[skeleton.jointlabels[rightankle]].position=skeleton.joints[skeleton.jointlabels[rightfoot]].position+change;
+                                               skeleton.joints[skeleton.jointlabels[rightknee]].position=(skeleton.joints[skeleton.jointlabels[rightfoot]].position+change2)/2+(skeleton.joints[skeleton.jointlabels[rightknee]].position)/2;
+                                               skeleton.DoConstraints(&coords,&scale);
+                                       }
+                               }
+                       }
+                       if(!skeleton.free&&(!animation[targetanimation].attack&&targetanimation!=getupfrombackanim&&targetanimation!=getupfrombackanim&&((targetanimation!=rollanim&&!isFlip())||animation[targetanimation].label[targetframe]==6)&&targetanimation!=getupfromfrontanim&&targetanimation!=wolfrunninganim&&targetanimation!=rabbitrunninganim&&targetanimation!=backhandspringanim&&targetanimation!=walljumpfrontanim&&targetanimation!=hurtidleanim&&!isLandhard()&&!isSleeping()))DoHead();
+                       else {
+                               targetheadrotation=-targetrotation;
+                               targetheadrotation2=0;
+                               if(animation[targetanimation].attack==3)targetheadrotation+=180;
+                       }
+                       for(i=0;i<skeleton.drawmodel.vertexNum;i++){
+                               skeleton.drawmodel.vertex[i]=0;
+                               skeleton.drawmodel.vertex[i].y=999;
+                       }
+                       for(i=0;i<skeleton.drawmodellow.vertexNum;i++){
+                               skeleton.drawmodellow.vertex[i]=0;
+                               skeleton.drawmodellow.vertex[i].y=999;
+                       }
+                       for(i=0;i<skeleton.drawmodelclothes.vertexNum;i++){
+                               skeleton.drawmodelclothes.vertex[i]=0;
+                               skeleton.drawmodelclothes.vertex[i].y=999;
+                       }
+                       for(i=0;i<skeleton.num_muscles;i++){
+                               if((skeleton.muscles[i].numvertices>0&&playerdetail)||(skeleton.muscles[i].numverticeslow>0&&!playerdetail)){
+                                       morphness=0;
+                                       start=0;
+                                       endthing=0;
+                                       if(skeleton.muscles[i].parent1->label==righthand||skeleton.muscles[i].parent2->label==righthand){
+                                               morphness=righthandmorphness;
+                                               start=righthandmorphstart;
+                                               endthing=righthandmorphend;
+                                       }
+                                       if(skeleton.muscles[i].parent1->label==lefthand||skeleton.muscles[i].parent2->label==lefthand){
+                                               morphness=lefthandmorphness;
+                                               start=lefthandmorphstart;
+                                               endthing=lefthandmorphend;
+                                       }
+                                       if(skeleton.muscles[i].parent1->label==head||skeleton.muscles[i].parent2->label==head){
+                                               morphness=headmorphness;
+                                               start=headmorphstart;
+                                               endthing=headmorphend;
+                                       }
+                                       if((skeleton.muscles[i].parent1->label==neck&&skeleton.muscles[i].parent2->label==abdomen)||(skeleton.muscles[i].parent2->label==neck&&skeleton.muscles[i].parent1->label==abdomen)){
+                                               morphness=chestmorphness;
+                                               start=chestmorphstart;
+                                               endthing=chestmorphend;
+                                       }
+                                       if((skeleton.muscles[i].parent1->label==groin&&skeleton.muscles[i].parent2->label==abdomen)||(skeleton.muscles[i].parent2->label==groin&&skeleton.muscles[i].parent1->label==abdomen)){
+                                               morphness=tailmorphness;
+                                               start=tailmorphstart;
+                                               endthing=tailmorphend;
+                                       }
+                                       if(calcrot)skeleton.FindRotationMuscle(i,targetanimation);
+                                       mid=(skeleton.muscles[i].parent1->position+skeleton.muscles[i].parent2->position)/2;
+                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                       glPushMatrix();
+                                               glLoadIdentity();
+                                               if(!skeleton.free)glRotatef(tilt2,1,0,0);
+                                               if(!skeleton.free)glRotatef(tilt,0,0,1);
+
+
+                                               glTranslatef(mid.x,mid.y,mid.z);
+
+                                               skeleton.muscles[i].lastrotate1=skeleton.muscles[i].rotate1;
+                                               glRotatef(-skeleton.muscles[i].lastrotate1+90,0,1,0);
+
+                                               skeleton.muscles[i].lastrotate2=skeleton.muscles[i].rotate2;
+                                               glRotatef(-skeleton.muscles[i].lastrotate2+90,0,0,1);
+
+                                               skeleton.muscles[i].lastrotate3=skeleton.muscles[i].rotate3;
+                                               glRotatef(-skeleton.muscles[i].lastrotate3,0,1,0);
+                                               /*
+                                               if(!isnormal(proportionbody.x)||!isnormal(proportionbody.y)||!isnormal(proportionbody.z)){
+                                               proportionbody=1;
+                                               proportionweird=1;
+                                               }
+                                               if(!isnormal(proportionarms.x)||!isnormal(proportionarms.y)||!isnormal(proportionarms.z)){
+                                               proportionarms=1;
+                                               proportionweird=1;
+                                               }
+                                               if(!isnormal(proportionhead.x)||!isnormal(proportionhead.y)||!isnormal(proportionhead.z)){
+                                               proportionhead=1;
+                                               proportionweird=1;
+                                               }
+                                               if(!isnormal(proportionlegs.x)||!isnormal(proportionlegs.y)||!isnormal(proportionlegs.z)){
+                                               proportionlegs=1;
+                                               proportionweird=1;
+                                               }*/
+
+                                               if(playerdetail||skeleton.free==3)
+                                               {
+                                                       for(j=0;j<skeleton.muscles[i].numvertices;j++)
+                                                       {
+                                                               /*if(!isnormal(skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].x))vertexweird[0]=1;
+                                                               if(!isnormal(skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].y))vertexweird[1]=1;
+                                                               if(!isnormal(skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].z))vertexweird[2]=1;
+                                                               if(!isnormal(skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].x))vertexweird[3]=1;
+                                                               if(!isnormal(skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].y))vertexweird[4]=1;
+                                                               if(!isnormal(skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].z))vertexweird[5]=1;
+                                                               if(skeleton.muscles[i].vertices[j]<skeleton.model[start].vertexNum&&skeleton.muscles[i].vertices[j]>=0){*/
+                                                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                               glPushMatrix();
+                                                                       if(skeleton.muscles[i].parent1->label==abdomen||skeleton.muscles[i].parent2->label==abdomen)
+                                                                               glTranslatef((skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].x*(1-morphness)+skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].x*morphness)*proportionbody.x,
+                                                                               (skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].y*(1-morphness)+skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].y*morphness)*proportionbody.y,
+                                                                               (skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].z*(1-morphness)+skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].z*morphness)*proportionbody.z);
+                                                                       if(skeleton.muscles[i].parent1->label==lefthand||skeleton.muscles[i].parent1->label==righthand||skeleton.muscles[i].parent1->label==leftwrist||skeleton.muscles[i].parent1->label==rightwrist||skeleton.muscles[i].parent1->label==leftelbow||skeleton.muscles[i].parent1->label==rightelbow||skeleton.muscles[i].parent2->label==leftelbow||skeleton.muscles[i].parent2->label==rightelbow)
+                                                                               glTranslatef((skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].x*(1-morphness)+skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].x*morphness)*proportionarms.x,
+                                                                               (skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].y*(1-morphness)+skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].y*morphness)*proportionarms.y,
+                                                                               (skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].z*(1-morphness)+skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].z*morphness)*proportionarms.z);
+                                                                       if(skeleton.muscles[i].parent1->label==leftfoot||skeleton.muscles[i].parent1->label==rightfoot||skeleton.muscles[i].parent1->label==leftankle||skeleton.muscles[i].parent1->label==rightankle||skeleton.muscles[i].parent1->label==leftknee||skeleton.muscles[i].parent1->label==rightknee||skeleton.muscles[i].parent2->label==leftknee||skeleton.muscles[i].parent2->label==rightknee)
+                                                                               glTranslatef((skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].x*(1-morphness)+skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].x*morphness)*proportionlegs.x,
+                                                                               (skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].y*(1-morphness)+skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].y*morphness)*proportionlegs.y,
+                                                                               (skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].z*(1-morphness)+skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].z*morphness)*proportionlegs.z);
+                                                                       if(skeleton.muscles[i].parent1->label==head||skeleton.muscles[i].parent2->label==head)
+                                                                               glTranslatef((skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].x*(1-morphness)+skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].x*morphness)*proportionhead.x,
+                                                                               (skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].y*(1-morphness)+skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].y*morphness)*proportionhead.y,
+                                                                               (skeleton.model[start].vertex[skeleton.muscles[i].vertices[j]].z*(1-morphness)+skeleton.model[endthing].vertex[skeleton.muscles[i].vertices[j]].z*morphness)*proportionhead.z);
+                                                                       glGetFloatv(GL_MODELVIEW_MATRIX,M);
+                                                                       //if(!isnormal(M[12])||!isnormal(M[13])||!isnormal(M[14]))test=0;
+                                                                       //if(isnormal(M[12])&&isnormal(M[13])&&isnormal(M[14])){
+                                                                       //if(!isnormal(scale))test=1;
+                                                                       //if(isnormal(scale)){
+                                                                       skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].x=M[12]*scale;
+                                                                       skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].y=M[13]*scale;
+                                                                       skeleton.drawmodel.vertex[skeleton.muscles[i].vertices[j]].z=M[14]*scale;
+                                                                       //test=2;
+                                                                       //}
+                                                                       //}
+                                                               glPopMatrix();
+                                                               //}
+                                                       }
+                                               }
+                                               if(!playerdetail||skeleton.free==3)
+                                               {
+                                                       for(j=0;j<skeleton.muscles[i].numverticeslow;j++)
+                                                       {
+                                                               //if(skeleton.muscles[i].verticeslow[j]<skeleton.modellow.vertexNum&&skeleton.muscles[i].verticeslow[j]>=0){
+                                                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                               glPushMatrix();
+                                                                       if(skeleton.muscles[i].parent1->label==abdomen||skeleton.muscles[i].parent2->label==abdomen)
+                                                                               glTranslatef((skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]].x)*proportionbody.x,
+                                                                               (skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]].y)*proportionbody.y,
+                                                                               (skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]].z)*proportionbody.z);
+                                                                       if(skeleton.muscles[i].parent1->label==lefthand||skeleton.muscles[i].parent1->label==righthand||skeleton.muscles[i].parent1->label==leftwrist||skeleton.muscles[i].parent1->label==rightwrist||skeleton.muscles[i].parent1->label==leftelbow||skeleton.muscles[i].parent1->label==rightelbow||skeleton.muscles[i].parent2->label==leftelbow||skeleton.muscles[i].parent2->label==rightelbow)
+                                                                               glTranslatef((skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]].x)*proportionarms.x,
+                                                                               (skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]].y)*proportionarms.y,
+                                                                               (skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]].z)*proportionarms.z);
+                                                                       if(skeleton.muscles[i].parent1->label==leftfoot||skeleton.muscles[i].parent1->label==rightfoot||skeleton.muscles[i].parent1->label==leftankle||skeleton.muscles[i].parent1->label==rightankle||skeleton.muscles[i].parent1->label==leftknee||skeleton.muscles[i].parent1->label==rightknee||skeleton.muscles[i].parent2->label==leftknee||skeleton.muscles[i].parent2->label==rightknee)
+                                                                               glTranslatef((skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]].x)*proportionlegs.x,
+                                                                               (skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]].y)*proportionlegs.y,
+                                                                               (skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]].z)*proportionlegs.z);
+                                                                       if(skeleton.muscles[i].parent1->label==head||skeleton.muscles[i].parent2->label==head)
+                                                                               glTranslatef((skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]].x)*proportionhead.x,
+                                                                               (skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]].y)*proportionhead.y,
+                                                                               (skeleton.modellow.vertex[skeleton.muscles[i].verticeslow[j]].z)*proportionhead.z);
+
+                                                                       glGetFloatv(GL_MODELVIEW_MATRIX,M);
+                                                                       skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].x=M[12]*scale;
+                                                                       skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].y=M[13]*scale;
+                                                                       skeleton.drawmodellow.vertex[skeleton.muscles[i].verticeslow[j]].z=M[14]*scale;
+                                                               glPopMatrix();
+                                                               //}
+                                                       }
+                                               }
+                                       glPopMatrix();
+                               }
+                               if(skeleton.clothes&&skeleton.muscles[i].numverticesclothes>0){
+                                       mid=(skeleton.muscles[i].parent1->position+skeleton.muscles[i].parent2->position)/2;
+
+                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                       glPushMatrix();
+                                               glLoadIdentity();
+                                               if(!skeleton.free)glRotatef(tilt2,1,0,0);
+                                               if(!skeleton.free)glRotatef(tilt,0,0,1);
+                                               glTranslatef(mid.x,mid.y,mid.z);
+                                               skeleton.muscles[i].lastrotate1=skeleton.muscles[i].rotate1;
+                                               glRotatef(-skeleton.muscles[i].lastrotate1+90,0,1,0);
+
+                                               skeleton.muscles[i].lastrotate2=skeleton.muscles[i].rotate2;
+                                               glRotatef(-skeleton.muscles[i].lastrotate2+90,0,0,1);
+
+                                               skeleton.muscles[i].lastrotate3=skeleton.muscles[i].rotate3;
+                                               glRotatef(-skeleton.muscles[i].lastrotate3,0,1,0);
+
+                                               for(j=0;j<skeleton.muscles[i].numverticesclothes;j++){
+                                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                       glPushMatrix();
+                                                               if(skeleton.muscles[i].parent1->label==abdomen||skeleton.muscles[i].parent2->label==abdomen)
+                                                                       glTranslatef((skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].x)*proportionbody.x,
+                                                                       (skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].y)*proportionbody.y,
+                                                                       (skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].z)*proportionbody.z);
+                                                               if(skeleton.muscles[i].parent1->label==lefthand||skeleton.muscles[i].parent1->label==righthand||skeleton.muscles[i].parent1->label==leftwrist||skeleton.muscles[i].parent1->label==rightwrist||skeleton.muscles[i].parent1->label==leftelbow||skeleton.muscles[i].parent1->label==rightelbow||skeleton.muscles[i].parent2->label==leftelbow||skeleton.muscles[i].parent2->label==rightelbow)
+                                                                       glTranslatef((skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].x)*proportionarms.x,
+                                                                       (skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].y)*proportionarms.y,
+                                                                       (skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].z)*proportionarms.z);
+                                                               if(skeleton.muscles[i].parent1->label==leftfoot||skeleton.muscles[i].parent1->label==rightfoot||skeleton.muscles[i].parent1->label==leftankle||skeleton.muscles[i].parent1->label==rightankle||skeleton.muscles[i].parent1->label==leftknee||skeleton.muscles[i].parent1->label==rightknee||skeleton.muscles[i].parent2->label==leftknee||skeleton.muscles[i].parent2->label==rightknee)
+                                                                       glTranslatef((skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].x)*proportionlegs.x,
+                                                                       (skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].y)*proportionlegs.y,
+                                                                       (skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].z)*proportionlegs.z);
+                                                               if(skeleton.muscles[i].parent1->label==head||skeleton.muscles[i].parent2->label==head)
+                                                                       glTranslatef((skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].x)*proportionhead.x,
+                                                                       (skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].y)*proportionhead.y,
+                                                                       (skeleton.modelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].z)*proportionhead.z);
+                                                               glGetFloatv(GL_MODELVIEW_MATRIX,M);
+                                                               skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].x=M[12]*scale;
+                                                               skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].y=M[13]*scale;
+                                                               skeleton.drawmodelclothes.vertex[skeleton.muscles[i].verticesclothes[j]].z=M[14]*scale;
+                                                       glPopMatrix();
+                                               }
+                                       glPopMatrix();
+                               }
+                               updatedelay=1+(float)(Random()%100)/1000;
+                       }
+                       if(skeleton.free!=2&&(skeleton.free==1||skeleton.free==3||id==0||(normalsupdatedelay<=0)||targetanimation==getupfromfrontanim||targetanimation==getupfrombackanim||currentanimation==getupfromfrontanim||currentanimation==getupfrombackanim)){
+                               normalsupdatedelay=1;
+                               if(playerdetail||skeleton.free==3)skeleton.drawmodel.CalculateNormals(0);
+                               if(!playerdetail||skeleton.free==3)skeleton.drawmodellow.CalculateNormals(0);
+                               if(skeleton.clothes)skeleton.drawmodelclothes.CalculateNormals(0);
+                       }
+                       else
+                       {
+                               if(playerdetail||skeleton.free==3)skeleton.drawmodel.UpdateVertexArrayNoTexNoNorm();
+                               if(!playerdetail||skeleton.free==3)skeleton.drawmodellow.UpdateVertexArrayNoTexNoNorm();
+                               if(skeleton.clothes){
+                                       skeleton.drawmodelclothes.UpdateVertexArrayNoTexNoNorm();
+                               }
+                       }
+               }
+               framemult=.01;
+               updatedelaychange=-framemult*4*(45-findDistance(&viewer,&coords)*1);
+               if(updatedelaychange>-realmultiplier*30)updatedelaychange=-realmultiplier*30;
+               if(updatedelaychange>-framemult*4)updatedelaychange=-framemult*4;
+               if(skeleton.free==1)updatedelaychange*=6;
+               if(id==0)updatedelaychange*=8;
+               updatedelay+=updatedelaychange;
+
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+               glPushMatrix();
+               if(!skeleton.free)glTranslatef(coords.x,coords.y-.02,coords.z);
+               if(skeleton.free)glTranslatef(coords.x,coords.y-.02,coords.z);
+               if(!skeleton.free)glTranslatef(offset.x*scale,offset.y*scale,offset.z*scale);
+               if(!skeleton.free)glRotatef(rotation,0,1,0);
+               if(showpoints){
+                       glPointSize(5);
+                       glColor4f(.4,1,.4,1);
+                       glDisable(GL_LIGHTING);
+                       glDisable(GL_TEXTURE_2D);
+                       glBegin(GL_POINTS);
+                       if(playerdetail)
+                               for(i=0;i<skeleton.drawmodel.vertexNum;i++){
+                                       glVertex3f(skeleton.drawmodel.vertex[i].x,skeleton.drawmodel.vertex[i].y,skeleton.drawmodel.vertex[i].z);
+                               }
+                               glEnd();
+                               glBegin(GL_LINES);
+
+                               if(playerdetail)
+                                       for(i=0;i<skeleton.drawmodel.TriangleNum;i++){
+                                               glVertex3f(skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[0]].x,skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[0]].y,skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[0]].z);
+                                               glVertex3f(skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[1]].x,skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[1]].y,skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[1]].z);
+                                               glVertex3f(skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[1]].x,skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[1]].y,skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[1]].z);
+                                               glVertex3f(skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[2]].x,skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[2]].y,skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[2]].z);
+                                               glVertex3f(skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[2]].x,skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[2]].y,skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[2]].z);
+                                               glVertex3f(skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[0]].x,skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[0]].y,skeleton.drawmodel.vertex[skeleton.drawmodel.Triangles[i].vertex[0]].z);
+                                       }
+
+                               glEnd();
+               }
+
+               terrainlight=terrain.getLighting(coords.x,coords.z);
+               distance=findDistancefast(&viewer,&coords);
+               distance=(viewdistance*viewdistance-(distance-(viewdistance*viewdistance*fadestart))*(1/(1-fadestart)))/viewdistance/viewdistance;
+               if(distance>1)distance=1;
+               if(distance>0){
+                       terrainheight=(coords.y-terrain.getHeight(coords.x,coords.z))/3+1;
+                       if(terrainheight<1)terrainheight=1;
+                       if(terrainheight>1.7)terrainheight=1.7;
+
+                       //burnt=0;
+                       glColor4f((1-(1-terrainlight.x)/terrainheight)-burnt,(1-(1-terrainlight.y)/terrainheight)-burnt,(1-(1-terrainlight.z)/terrainheight)-burnt,distance);
+                       glDisable(GL_BLEND);
+                       glAlphaFunc(GL_GREATER, 0.0001);
+                       glEnable(GL_TEXTURE_2D);
+                       if(cellophane){
+                               glDisable(GL_TEXTURE_2D);
+                               glColor4f(.7,.35,0,.5);
+                               glDepthMask(0);
+                               glEnable(GL_LIGHTING);
+                               glEnable(GL_BLEND);
+                       }
+                       if(tutoriallevel&&id!=0){
+                               //glDisable(GL_TEXTURE_2D);
+                               glColor4f(.7,.7,.7,0.6);
+                               glDepthMask(0);
+                               glEnable(GL_LIGHTING);
+                               glEnable(GL_BLEND);
+                               if(canattack&&cananger)
+                                       if(animation[targetanimation].attack==normalattack||animation[targetanimation].attack==reversed){
+                                               glDisable(GL_TEXTURE_2D);
+                                               glColor4f(1,0,0,0.8);
+                                       }
+                                       glMatrixMode(GL_TEXTURE);
+                                       glPushMatrix();
+                                       glTranslatef(0,-smoketex,0);
+                                       glTranslatef(-smoketex,0,0);
+                       }
+                       if(playerdetail){
+                               if(!showpoints){
+                                       if((tutoriallevel&&id!=0))skeleton.drawmodel.drawdifftex(sprites.cloudimpacttexture);
+                                       else skeleton.drawmodel.draw();
+                               }
+                       }
+                       if(!playerdetail){
+                               if((tutoriallevel&&id!=0))skeleton.drawmodellow.drawdifftex(sprites.cloudimpacttexture);
+                               else skeleton.drawmodellow.drawdifftex(skeleton.drawmodel.textureptr);
+                       }
+
+                       if(!(animation[targetanimation].attack==normalattack||animation[targetanimation].attack==reversed))
+                               if(tutoriallevel&&id!=0){
+                                       glPopMatrix();
+                                       glMatrixMode(GL_MODELVIEW);
+                                       glEnable(GL_TEXTURE_2D);
+                                       glColor4f(.7,.7,.7,0.6);
+                                       glDepthMask(0);
+                                       glEnable(GL_LIGHTING);
+                                       glEnable(GL_BLEND);
+                                       if(canattack&&cananger)
+                                               if(animation[targetanimation].attack==normalattack||animation[targetanimation].attack==reversed){
+                                                       glDisable(GL_TEXTURE_2D);
+                                                       glColor4f(1,0,0,0.8);
+                                               }
+                                               glMatrixMode(GL_TEXTURE);
+                                               glPushMatrix();
+                                               glTranslatef(0,-smoketex*.6,0);
+                                               glTranslatef(smoketex*.6,0,0);
+                                               if(playerdetail){
+                                                       if(!showpoints){
+                                                               if((tutoriallevel&&id!=0))skeleton.drawmodel.drawdifftex(sprites.cloudimpacttexture);
+                                                               else skeleton.drawmodel.draw();
+                                                       }
+                                               }
+                                               if(!playerdetail){
+                                                       if((tutoriallevel&&id!=0))skeleton.drawmodellow.drawdifftex(sprites.cloudimpacttexture);
+                                                       else skeleton.drawmodellow.drawdifftex(skeleton.drawmodel.textureptr);
+                                               }
+                               }
+
+
+                               if(tutoriallevel&&id!=0){
+                                       glPopMatrix();
+                                       glMatrixMode(GL_MODELVIEW);
+                                       glEnable(GL_TEXTURE_2D);
+                               }
+                               if(skeleton.clothes){
+                                       glDepthMask(0);
+                                       glEnable(GL_BLEND);
+                                       if(!immediate)skeleton.drawmodelclothes.draw();
+                                       if(immediate)skeleton.drawmodelclothes.drawimmediate();
+                                       glDepthMask(1);
+                               }
+               }
+               glPopMatrix();
+
+               if(num_weapons>0){
+                       for(k=0;k<num_weapons;k++){
+                               i=weaponids[k];
+                               if(weaponactive==k){                                            
+                                       if(weapons.type[i]!=staff){
+                                               for(j=0;j<skeleton.num_muscles;j++){
+                                                       if((skeleton.muscles[j].parent1->label==righthand||skeleton.muscles[j].parent2->label==righthand)&&skeleton.muscles[j].numvertices>0){
+                                                               weaponattachmuscle=j;
+                                                       }
+                                               }
+                                               for(j=0;j<skeleton.num_muscles;j++){
+                                                       if((skeleton.muscles[j].parent1->label==rightwrist||skeleton.muscles[j].parent2->label==rightwrist)&&(skeleton.muscles[j].parent1->label!=righthand&&skeleton.muscles[j].parent2->label!=righthand)&&skeleton.muscles[j].numvertices>0){
+                                                               weaponrotatemuscle=j;
+                                                       }
+                                               }
+                                               weaponpoint=(skeleton.muscles[weaponattachmuscle].parent1->position+skeleton.muscles[weaponattachmuscle].parent2->position)/2;
+                                               if(creature==wolftype)weaponpoint=(skeleton.joints[skeleton.jointlabels[rightwrist]].position*.7+skeleton.joints[skeleton.jointlabels[righthand]].position*.3);
+                                       }
+                                       if(weapons.type[i]==staff){
+                                               for(j=0;j<skeleton.num_muscles;j++){
+                                                       if((skeleton.muscles[j].parent1->label==righthand||skeleton.muscles[j].parent2->label==righthand)&&skeleton.muscles[j].numvertices>0){
+                                                               weaponattachmuscle=j;
+                                                       }
+                                               }
+                                               for(j=0;j<skeleton.num_muscles;j++){
+                                                       if((skeleton.muscles[j].parent1->label==rightelbow||skeleton.muscles[j].parent2->label==rightelbow)&&(skeleton.muscles[j].parent1->label!=rightshoulder&&skeleton.muscles[j].parent2->label!=rightshoulder)&&skeleton.muscles[j].numvertices>0){
+                                                               weaponrotatemuscle=j;
+                                                       }
+                                               }
+                                               //weaponpoint=skeleton.joints[skeleton.jointlabels[rightwrist]].position;
+                                               weaponpoint=(skeleton.muscles[weaponattachmuscle].parent1->position+skeleton.muscles[weaponattachmuscle].parent2->position)/2;
+                                               //weaponpoint+=skeleton.specialforward[1]*.1+(skeleton.joints[skeleton.jointlabels[rightwrist]].position-skeleton.joints[skeleton.jointlabels[rightelbow]].position);
+                                               XYZ tempnormthing,vec1,vec2;
+                                               vec1=(skeleton.joints[skeleton.jointlabels[rightwrist]].position-skeleton.joints[skeleton.jointlabels[rightelbow]].position);
+                                               vec2=(skeleton.joints[skeleton.jointlabels[rightwrist]].position-skeleton.joints[skeleton.jointlabels[rightshoulder]].position);
+                                               CrossProduct(&vec1,&vec2,&tempnormthing);
+                                               Normalise(&tempnormthing);
+                                               if(targetanimation!=staffhitanim&&currentanimation!=staffhitanim&&targetanimation!=staffgroundsmashanim&&currentanimation!=staffgroundsmashanim&&targetanimation!=staffspinhitanim&&currentanimation!=staffspinhitanim)weaponpoint+=tempnormthing*.1-skeleton.specialforward[1]*.3+(skeleton.joints[skeleton.jointlabels[rightwrist]].position-skeleton.joints[skeleton.jointlabels[rightelbow]].position);
+                                               /*if(targetanimation==staffhitanim||currentanimation==staffhitanim){
+                                               XYZ weaptargnorm;
+                                               weaptargnorm=DoRotation(weapons.tippoint[i]-weapons.position[i],0,-rotation,0);
+                                               //weaptargnorm=animation[currentanimation].weapontarget[currentframe]*(1-target)+animation[targetanimation].weapontarget[targetframe]*(target);
+                                               Normalise(&weaptargnorm);
+                                               weaponpoint-=weaptargnorm*2;
+                                               }*/
+                                       }
+                               }
+                               if(weaponactive!=k&&weaponstuck!=k){                                            
+                                       if(weapons.type[i]==knife)weaponpoint=skeleton.joints[skeleton.jointlabels[abdomen]].position+(skeleton.joints[skeleton.jointlabels[righthip]].position-skeleton.joints[skeleton.jointlabels[lefthip]].position)*.1+(skeleton.joints[skeleton.jointlabels[rightshoulder]].position-skeleton.joints[skeleton.jointlabels[leftshoulder]].position)*.35;
+                                       if(weapons.type[i]==sword)weaponpoint=skeleton.joints[skeleton.jointlabels[abdomen]].position+(skeleton.joints[skeleton.jointlabels[lefthip]].position-skeleton.joints[skeleton.jointlabels[righthip]].position)*.09+(skeleton.joints[skeleton.jointlabels[leftshoulder]].position-skeleton.joints[skeleton.jointlabels[rightshoulder]].position)*.33;
+                                       if(weapons.type[i]==staff)weaponpoint=skeleton.joints[skeleton.jointlabels[abdomen]].position+(skeleton.joints[skeleton.jointlabels[lefthip]].position-skeleton.joints[skeleton.jointlabels[righthip]].position)*.09+(skeleton.joints[skeleton.jointlabels[leftshoulder]].position-skeleton.joints[skeleton.jointlabels[rightshoulder]].position)*.33;
+                                       for(j=0;j<skeleton.num_muscles;j++){
+                                               if((skeleton.muscles[j].parent1->label==abdomen||skeleton.muscles[j].parent2->label==abdomen)&&(skeleton.muscles[j].parent1->label==neck||skeleton.muscles[j].parent2->label==neck)&&skeleton.muscles[j].numvertices>0){
+                                                       weaponrotatemuscle=j;
+                                               }
+                                       }
+                               }
+                               if(weaponstuck==k){                                             
+                                       if(weaponstuckwhere==0)weaponpoint=skeleton.joints[skeleton.jointlabels[abdomen]].position*.5+skeleton.joints[skeleton.jointlabels[neck]].position*.5-skeleton.forward*.8;
+                                       else weaponpoint=skeleton.joints[skeleton.jointlabels[abdomen]].position*.5+skeleton.joints[skeleton.jointlabels[neck]].position*.5+skeleton.forward*.8;
+                                       for(j=0;j<skeleton.num_muscles;j++){
+                                               if((skeleton.muscles[j].parent1->label==abdomen||skeleton.muscles[j].parent2->label==abdomen)&&(skeleton.muscles[j].parent1->label==neck||skeleton.muscles[j].parent2->label==neck)&&skeleton.muscles[j].numvertices>0){
+                                                       weaponrotatemuscle=j;
+                                               }
+                                       }
+                               }
+                               if(!skeleton.free){
+                                       weapons.position[i]=DoRotation(DoRotation(DoRotation(weaponpoint,0,0,tilt),tilt2,0,0),0,rotation,0)*scale+coords+currentoffset*(1-target)*scale+targetoffset*target*scale;
+                                       weapons.bigrotation[i]=rotation;
+                                       weapons.bigtilt[i]=tilt;
+                                       weapons.bigtilt2[i]=tilt2;
+                               }
+                               if(skeleton.free){
+                                       weapons.position[i]=weaponpoint*scale+coords;
+                                       weapons.bigrotation[i]=0;
+                                       weapons.bigtilt[i]=0;
+                                       weapons.bigtilt2[i]=0;
+                               }
+                               weapons.rotation1[i]=skeleton.muscles[weaponrotatemuscle].lastrotate1;
+                               weapons.rotation2[i]=skeleton.muscles[weaponrotatemuscle].lastrotate2;
+                               weapons.rotation3[i]=skeleton.muscles[weaponrotatemuscle].lastrotate3;
+                               if(weaponactive==k){
+                                       if(weapons.type[i]==knife){
+                                               weapons.smallrotation[i]=180;
+                                               weapons.smallrotation2[i]=0;
+                                               if(isCrouch()||wasCrouch()){
+                                                       weapons.smallrotation2[i]=20;
+                                               }
+                                               if(targetanimation==hurtidleanim){
+                                                       weapons.smallrotation2[i]=50;
+                                               }
+                                               if((currentanimation==crouchstabanim&&targetanimation==crouchstabanim)||(currentanimation==backhandspringanim&&targetanimation==backhandspringanim)){
+                                                       XYZ temppoint1,temppoint2,tempforward;
+                                                       float distance;
+
+                                                       temppoint1=skeleton.joints[skeleton.jointlabels[righthand]].position;
+                                                       temppoint2=animation[currentanimation].weapontarget[currentframe]*(1-target)+animation[targetanimation].weapontarget[targetframe]*(target);
+                                                       distance=findDistance(&temppoint1,&temppoint2);
+                                                       weapons.rotation2[i]=asin((temppoint1.y-temppoint2.y)/distance);
+                                                       weapons.rotation2[i]*=360/6.28;
+                                                       temppoint1.y=0;
+                                                       temppoint2.y=0;
+                                                       weapons.rotation1[i]=acos((temppoint1.z-temppoint2.z)/findDistance(&temppoint1,&temppoint2));
+                                                       weapons.rotation1[i]*=360/6.28;
+                                                       weapons.rotation3[i]=0;
+                                                       weapons.smallrotation[i]=-90;
+                                                       weapons.smallrotation2[i]=0;
+                                                       if(temppoint1.x>temppoint2.x)weapons.rotation1[i]=360-weapons.rotation1[i];                                                     
+                                               }
+                                               if((currentanimation==knifeslashreversalanim&&targetanimation==knifeslashreversalanim)||(currentanimation==knifeslashreversedanim&&targetanimation==knifeslashreversedanim)){
+                                                       XYZ temppoint1,temppoint2,tempforward;
+                                                       float distance;
+
+                                                       temppoint1=skeleton.joints[skeleton.jointlabels[righthand]].position;
+                                                       temppoint2=animation[currentanimation].weapontarget[currentframe]*(1-target)+animation[targetanimation].weapontarget[targetframe]*(target);
+                                                       distance=findDistance(&temppoint1,&temppoint2);
+                                                       weapons.rotation2[i]=asin((temppoint1.y-temppoint2.y)/distance);
+                                                       weapons.rotation2[i]*=360/6.28;
+                                                       temppoint1.y=0;
+                                                       temppoint2.y=0;
+                                                       weapons.rotation1[i]=acos((temppoint1.z-temppoint2.z)/findDistance(&temppoint1,&temppoint2));
+                                                       weapons.rotation1[i]*=360/6.28;
+                                                       weapons.rotation3[i]=0;
+                                                       weapons.smallrotation[i]=90;
+                                                       weapons.smallrotation2[i]=0;
+                                                       if(temppoint1.x>temppoint2.x)weapons.rotation1[i]=360-weapons.rotation1[i];                                                     
+                                               }
+                                               if(targetanimation==knifethrowanim){
+                                                       weapons.smallrotation[i]=90;
+                                                       //weapons.smallrotation2[i]=-90;
+                                                       weapons.smallrotation2[i]=0;
+                                                       weapons.rotation1[i]=0;
+                                                       weapons.rotation2[i]=0;
+                                                       weapons.rotation3[i]=0;
+                                               }
+                                               if(targetanimation==knifesneakattackanim&&targetframe<5){
+                                                       weapons.smallrotation[i]=-90;
+                                                       weapons.rotation1[i]=0;
+                                                       weapons.rotation2[i]=0;
+                                                       weapons.rotation3[i]=0;
+                                               }
+                                       }
+                                       if(weapons.type[i]==sword){
+                                               weapons.smallrotation[i]=0;
+                                               weapons.smallrotation2[i]=0;
+                                               if(targetanimation==knifethrowanim){
+                                                       weapons.smallrotation[i]=-90;
+                                                       weapons.smallrotation2[i]=0;
+                                                       weapons.rotation1[i]=0;
+                                                       weapons.rotation2[i]=0;
+                                                       weapons.rotation3[i]=0;
+                                               }
+                                               if((targetanimation==swordgroundstabanim&&currentanimation==swordgroundstabanim)||(targetanimation==swordsneakattackanim&&currentanimation==swordsneakattackanim)||(targetanimation==swordslashparryanim&&currentanimation==swordslashparryanim)||(targetanimation==swordslashparriedanim&&currentanimation==swordslashparriedanim)||(targetanimation==swordslashreversalanim&&currentanimation==swordslashreversalanim)||(targetanimation==swordslashreversedanim&&currentanimation==swordslashreversedanim)||(targetanimation==knifeslashreversalanim&&currentanimation==knifeslashreversalanim)||(targetanimation==knifeslashreversedanim&&currentanimation==knifeslashreversedanim)||(targetanimation==swordslashanim&&currentanimation==swordslashanim)||(targetanimation==drawleftanim&&currentanimation==drawleftanim)||(currentanimation==backhandspringanim&&targetanimation==backhandspringanim)){
+                                                       XYZ temppoint1,temppoint2,tempforward;
+                                                       float distance;
+
+                                                       temppoint1=animation[currentanimation].position[skeleton.jointlabels[righthand]][currentframe]*(1-target)+animation[targetanimation].position[skeleton.jointlabels[righthand]][targetframe]*(target); //skeleton.joints[skeleton.jointlabels[righthand]].position;
+                                                       temppoint2=animation[currentanimation].weapontarget[currentframe]*(1-target)+animation[targetanimation].weapontarget[targetframe]*(target);
+                                                       distance=findDistance(&temppoint1,&temppoint2);
+                                                       weapons.rotation2[i]=asin((temppoint1.y-temppoint2.y)/distance);
+                                                       weapons.rotation2[i]*=360/6.28;
+                                                       temppoint1.y=0;
+                                                       temppoint2.y=0;
+                                                       weapons.rotation1[i]=acos((temppoint1.z-temppoint2.z)/findDistance(&temppoint1,&temppoint2));
+                                                       weapons.rotation1[i]*=360/6.28;
+                                                       weapons.rotation3[i]=0;
+                                                       weapons.smallrotation[i]=90;
+                                                       weapons.smallrotation2[i]=0;
+                                                       if(temppoint1.x>temppoint2.x)weapons.rotation1[i]=360-weapons.rotation1[i];                     
+                                               }
+                                       }
+                                       if(weapons.type[i]==staff){
+                                               weapons.smallrotation[i]=100;
+                                               weapons.smallrotation2[i]=0;
+                                               if((targetanimation==staffhitanim&&currentanimation==staffhitanim)||(targetanimation==staffhitreversedanim&&currentanimation==staffhitreversedanim)||(targetanimation==staffspinhitreversedanim&&currentanimation==staffspinhitreversedanim)||(targetanimation==staffgroundsmashanim&&currentanimation==staffgroundsmashanim)||(targetanimation==staffspinhitanim&&currentanimation==staffspinhitanim)){
+                                                       XYZ temppoint1,temppoint2,tempforward;
+                                                       float distance;
+
+                                                       temppoint1=animation[currentanimation].position[skeleton.jointlabels[righthand]][currentframe]*(1-target)+animation[targetanimation].position[skeleton.jointlabels[righthand]][targetframe]*(target); //skeleton.joints[skeleton.jointlabels[righthand]].position;
+                                                       temppoint2=animation[currentanimation].weapontarget[currentframe]*(1-target)+animation[targetanimation].weapontarget[targetframe]*(target);
+                                                       distance=findDistance(&temppoint1,&temppoint2);
+                                                       weapons.rotation2[i]=asin((temppoint1.y-temppoint2.y)/distance);
+                                                       weapons.rotation2[i]*=360/6.28;
+                                                       temppoint1.y=0;
+                                                       temppoint2.y=0;
+                                                       weapons.rotation1[i]=acos((temppoint1.z-temppoint2.z)/findDistance(&temppoint1,&temppoint2));
+                                                       weapons.rotation1[i]*=360/6.28;
+                                                       weapons.rotation3[i]=0;
+                                                       weapons.smallrotation[i]=90;
+                                                       weapons.smallrotation2[i]=0;
+                                                       if(temppoint1.x>temppoint2.x)weapons.rotation1[i]=360-weapons.rotation1[i];                     
+                                               }
+                                       }
+                               }
+                               if(weaponactive!=k&&weaponstuck!=k){
+                                       if(weapons.type[i]==knife){
+                                               weapons.smallrotation[i]=-70;
+                                               weapons.smallrotation2[i]=10;
+                                       }
+                                       if(weapons.type[i]==sword){
+                                               weapons.smallrotation[i]=-100;
+                                               weapons.smallrotation2[i]=-8;
+                                       }
+                                       if(weapons.type[i]==staff){
+                                               weapons.smallrotation[i]=-100;
+                                               weapons.smallrotation2[i]=-8;
+                                       }
+                               }
+                               if(weaponstuck==k){
+                                       if(weaponstuckwhere==0)weapons.smallrotation[i]=180;
+                                       else weapons.smallrotation[i]=0;
+                                       weapons.smallrotation2[i]=10;
+                                       //if(animation[targetanimation].height==lowheight&&animation[targetanimation].attack==neutral){
+                                       //}
+                               }
+                       }
+               }
+       }
+
+       calcrot=0;
+       if(skeleton.free)calcrot=1;
+       if(animation[targetanimation].attack||isRun()||targetanimation==staggerbackhardanim||isFlip()||targetanimation==climbanim||targetanimation==sneakanim||targetanimation==rollanim||targetanimation==walkanim||targetanimation==backhandspringanim||isFlip()||isWallJump())calcrot=1;
+       if(currentanimation!=targetanimation)calcrot=1;
+       //if(id==0)calcrot=1;
+       if(skeleton.free==2)calcrot=0;
+
+       return 0;
+}
+
+
+int Person::SphereCheck(XYZ *p1,float radius, XYZ *p, XYZ *move, float *rotate, Model *model)
+{
+       static int i,j;
+       static float distance;
+       static float olddistance;
+       static int intersecting;
+       static int firstintersecting;
+       static XYZ point;
+       static XYZ oldp1;
+       static XYZ start,end;
+       static float slopethreshold=-.4;
+
+       firstintersecting=-1;
+
+       oldp1=*p1;
+       *p1=*p1-*move;
+       if(findDistancefast(p1,&model->boundingspherecenter)>radius*radius+model->boundingsphereradius*model->boundingsphereradius)return -1;
+       if(*rotate)*p1=DoRotation(*p1,0,-*rotate,0);
+       for(i=0;i<4;i++){
+               for (j=0;j<model->TriangleNum;j++){
+                       if(model->facenormals[j].y<=slopethreshold){
+                               intersecting=0;
+                               distance=abs((model->facenormals[j].x*p1->x)+(model->facenormals[j].y*p1->y)+(model->facenormals[j].z*p1->z)-((model->facenormals[j].x*model->vertex[model->Triangles[j].vertex[0]].x)+(model->facenormals[j].y*model->vertex[model->Triangles[j].vertex[0]].y)+(model->facenormals[j].z*model->vertex[model->Triangles[j].vertex[0]].z)));
+                               if(distance<radius){
+                                       point=*p1-model->facenormals[j]*distance;
+                                       if(PointInTriangle( &point, model->facenormals[j], &model->vertex[model->Triangles[j].vertex[0]], &model->vertex[model->Triangles[j].vertex[1]], &model->vertex[model->Triangles[j].vertex[2]]))intersecting=1;
+                                       if(!intersecting)intersecting=sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[0]],
+                                               &model->vertex[model->Triangles[j].vertex[1]],
+                                               p1, &radius);
+                                       if(!intersecting)intersecting=sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[1]],
+                                               &model->vertex[model->Triangles[j].vertex[2]],
+                                               p1, &radius);
+                                       if(!intersecting)intersecting=sphere_line_intersection(&model->vertex[model->Triangles[j].vertex[0]],
+                                               &model->vertex[model->Triangles[j].vertex[2]],
+                                               p1, &radius);
+                                       end=*p1-point;
+                                       if(dotproduct(&model->facenormals[j],&end)>0&&intersecting){
+                                               start=*p1;
+                                               end=*p1;
+                                               end.y-=radius;
+                                               if(LineFacetd(&start,&end,&model->vertex[model->Triangles[j].vertex[0]],&model->vertex[model->Triangles[j].vertex[1]],&model->vertex[model->Triangles[j].vertex[2]],&model->facenormals[j],&point)){
+                                                       p1->y=point.y+radius;
+                                                       if((targetanimation==jumpdownanim||isFlip())){
+                                                               if(isFlip()&&(targetframe<5||animation[targetanimation].label[targetframe]==7||animation[targetanimation].label[targetframe]==4))RagDoll(0);
+
+                                                               if(targetanimation==jumpupanim){jumppower=-4;targetanimation=getIdle();}
+                                                               target=0;
+                                                               targetframe=0;  
+                                                               onterrain=1;
+
+                                                               if(id==0){
+                                                                       FSOUND_SetPaused(channels[whooshsound], TRUE);
+                                                                       FSOUND_SetVolume(channels[whooshsound], 0);
+                                                               }
+
+                                                               if((targetanimation==jumpdownanim||isFlip())&&!wasLanding()&&!wasLandhard()){
+                                                                       if(isFlip())jumppower=-4;
+                                                                       targetanimation=getLanding();
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=coords.x;
+                                                                       gLoc[1]=coords.y;
+                                                                       gLoc[2]=coords.z;
+                                                                       vel[0]=velocity.x;
+                                                                       vel[1]=velocity.y;
+                                                                       vel[2]=velocity.z;
+                                                                       PlaySoundEx( landsound, samp[landsound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[landsound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[landsound], 128);
+                                                                       FSOUND_SetPaused(channels[landsound], FALSE);
+
+                                                                       if(id==0){
+                                                                               envsound[numenvsounds]=coords;
+                                                                               envsoundvol[numenvsounds]=16;
+                                                                               envsoundlife[numenvsounds]=.4;
+                                                                               numenvsounds++;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               if((distance<olddistance||firstintersecting==-1)&&intersecting){olddistance=distance; firstintersecting=j; *p=point;}
+                       }
+               }
+               for (j=0;j<model->TriangleNum;j++){
+                       if(model->facenormals[j].y>slopethreshold){
+                               intersecting=0;
+                               start=*p1;
+                               start.y-=radius/4;
+                               distance=abs((model->facenormals[j].x*start.x)+(model->facenormals[j].y*start.y)+(model->facenormals[j].z*start.z)-((model->facenormals[j].x*model->vertex[model->Triangles[j].vertex[0]].x)+(model->facenormals[j].y*model->vertex[model->Triangles[j].vertex[0]].y)+(model->facenormals[j].z*model->vertex[model->Triangles[j].vertex[0]].z)));
+                               if(distance<radius*.5){
+                                       point=start-model->facenormals[j]*distance;
+                                       if(PointInTriangle( &point, model->facenormals[j], &model->vertex[model->Triangles[j].vertex[0]], &model->vertex[model->Triangles[j].vertex[1]], &model->vertex[model->Triangles[j].vertex[2]]))intersecting=1;
+                                       if(!intersecting)intersecting=sphere_line_intersection(model->vertex[model->Triangles[j].vertex[0]].x,model->vertex[model->Triangles[j].vertex[0]].y,model->vertex[model->Triangles[j].vertex[0]].z,
+                                               model->vertex[model->Triangles[j].vertex[1]].x,model->vertex[model->Triangles[j].vertex[1]].y,model->vertex[model->Triangles[j].vertex[1]].z,
+                                               p1->x, p1->y, p1->z, radius/2);
+                                       if(!intersecting)intersecting=sphere_line_intersection(model->vertex[model->Triangles[j].vertex[1]].x,model->vertex[model->Triangles[j].vertex[1]].y,model->vertex[model->Triangles[j].vertex[1]].z,
+                                               model->vertex[model->Triangles[j].vertex[2]].x,model->vertex[model->Triangles[j].vertex[2]].y,model->vertex[model->Triangles[j].vertex[2]].z,
+                                               p1->x, p1->y, p1->z, radius/2);
+                                       if(!intersecting)intersecting=sphere_line_intersection(model->vertex[model->Triangles[j].vertex[0]].x,model->vertex[model->Triangles[j].vertex[0]].y,model->vertex[model->Triangles[j].vertex[0]].z,
+                                               model->vertex[model->Triangles[j].vertex[2]].x,model->vertex[model->Triangles[j].vertex[2]].y,model->vertex[model->Triangles[j].vertex[2]].z,
+                                               p1->x, p1->y, p1->z, radius/2);
+                                       end=*p1-point;
+                                       if(dotproduct(&model->facenormals[j],&end)>0&&intersecting){
+                                               if((targetanimation==jumpdownanim||targetanimation==jumpupanim||isFlip())){
+                                                       start=velocity;
+                                                       velocity-=DoRotation(model->facenormals[j],0,*rotate,0)*findLength(&velocity)*abs(normaldotproduct(velocity,DoRotation(model->facenormals[j],0,*rotate,0)));//(distance-radius*.5)/multiplier;
+                                                       if(findLengthfast(&start)<findLengthfast(&velocity))velocity=start;
+                                               }
+                                               *p1+=model->facenormals[j]*(distance-radius*.5);
+                                       }
+                               }
+                               if((distance<olddistance||firstintersecting==-1)&&intersecting){olddistance=distance; firstintersecting=j; *p=point;}
+                       }
+               }
+       }
+       if(*rotate)*p=DoRotation(*p,0,*rotate,0);
+       *p=*p+*move;
+       if(*rotate)*p1=DoRotation(*p1,0,*rotate,0);
+       *p1+=*move;
+       return firstintersecting;
+}
+
+Person::Person()
+{
+       whichpatchx = 0;
+       whichpatchz = 0;
+
+       currentframe = 0;
+       targetframe = 0;
+       currentanimation = 0;
+       targetanimation = 0;
+       oldcurrentframe = 0;
+       oldtargetframe = 0;
+       oldcurrentanimation = 0;
+       oldtargetanimation = 0;
+
+       howactive = 0;
+
+       parriedrecently = 0;
+
+       superruntoggle = 0;
+
+       lastattack = 0,lastattack2 = 0,lastattack3 = 0;
+
+       currentoffset = 0,targetoffset = 0,offset = 0;
+       target = 0;
+       transspeed = 0;
+
+       realoldcoords = 0;
+       oldcoords = 0;
+       coords = 0;
+       originalcoords = 0;
+       velocity = 0;
+
+       proportionhead = 0;
+       proportionlegs = 0;
+       proportionarms = 0;
+       proportionbody = 0;
+
+       heightleft = 0;
+       heightright = 0;
+
+       unconscioustime = 0;
+
+       immobile = 0;
+
+       velspeed = 0;
+       targetrotation = 0;
+       targetrot = 0;
+       rot = 0;
+       oldrot = 0;
+       lookrotation = 0;
+       lookrotation2 = 0;
+       rotation = 0;
+       rotation2 = 0;
+       lowrotation = 0;
+       tilt = 0;
+       targettilt = 0;
+       tilt2 = 0;
+       targettilt2 = 0;
+       rabbitkickenabled = 0;
+
+       bloodloss = 0;
+       bleeddelay = 0;
+       skiddelay = 0;
+       skiddingdelay = 0;
+       deathbleeding = 0;
+       tempdeltav = 0;
+
+       damagetolerance = 0;
+       damage = 0;
+       permanentdamage = 0;
+       superpermanentdamage = 0;       lastcollide = 0;
+       dead = 0;
+
+       jumppower = 0;
+       onground = 0;
+       madskills = 0;
+
+       wentforweapon = 0;
+
+       calcrot = 0;
+
+       backwardsanim = 0;
+
+       facing = 0;
+
+       bleeding = 0;
+       bleedx = 0,bleedy;
+       direction = 0;
+       texupdatedelay = 0;
+
+       headrotation = 0,headrotation2 = 0;
+       targetheadrotation = 0,targetheadrotation2 = 0;
+
+       onterrain = 0;
+       pause = 0;
+
+       grabdelay = 0;
+
+       victim = 0;
+       hasvictim = 0;
+
+       updatedelay = 0;
+       normalsupdatedelay = 0;
+
+       jumpstart = 0;
+
+       forwardkeydown = 0;
+       forwardstogglekeydown = 0;
+       rightkeydown = 0;
+       leftkeydown = 0;
+       backkeydown = 0;
+       jumpkeydown = 0;
+       jumptogglekeydown = 0;
+       crouchkeydown = 0;
+       crouchtogglekeydown = 0;
+       drawkeydown = 0;
+       drawtogglekeydown = 0;
+       throwkeydown = 0;
+       throwtogglekeydown = 0;
+       attackkeydown = 0;
+       feint = 0;
+       lastfeint = 0;
+       headless = 0;
+
+       crouchkeydowntime = 0;
+       jumpkeydowntime = 0;
+       freefall = 0;
+
+
+       turnspeed = 0;
+
+       aitype = 0;
+       aitarget = 0;
+       aiupdatedelay = 0;
+       losupdatedelay = 0;
+       ally = 0;
+       movetarget = 0;
+       collide = 0;
+       collided = 0;
+       avoidcollided = 0;
+       loaded = 0;
+       whichdirection = 0;
+       whichdirectiondelay = 0;
+       avoidsomething = 0;     avoidwhere = 0;
+       blooddimamount = 0;
+
+       staggerdelay = 0;
+       blinkdelay = 0;
+       twitchdelay = 0;
+       twitchdelay2 = 0;
+       twitchdelay3 = 0;
+       lefthandmorphness = 0;
+       righthandmorphness = 0;
+       headmorphness = 0;
+       chestmorphness = 0;
+       tailmorphness = 0;
+       targetlefthandmorphness = 0;
+       targetrighthandmorphness = 0;
+       targetheadmorphness = 0;
+       targetchestmorphness = 0;
+       targettailmorphness = 0;
+       lefthandmorphstart = 0,lefthandmorphend = 0;
+       righthandmorphstart = 0,righthandmorphend = 0;
+       headmorphstart = 0,headmorphend = 0;
+       chestmorphstart = 0,chestmorphend = 0;
+       tailmorphstart = 0,tailmorphend = 0;
+
+       weaponmissdelay = 0;
+       highreversaldelay = 0;
+       lowreversaldelay = 0;
+       nocollidedelay = 0;
+
+       creature = 0;
+
+       id = 0;
+
+       //Skeleton skeleton;
+
+       speed = 0;
+       scale = 0;
+       power = 0;
+       speedmult = 0;
+
+       protectionhead = 0;
+       protectionhigh = 0;
+       protectionlow = 0;
+       armorhead = 0;
+       armorhigh = 0;
+       armorlow = 0;
+       metalhead = 0;
+       metalhigh = 0;
+       metallow = 0;
+
+       numclothes = 0;
+
+       memset(clothes, 0, sizeof(clothes));
+       memset(clothestintr, 0, sizeof(clothestintr));
+       memset(clothestintg, 0, sizeof(clothestintg));
+       memset(clothestintb, 0, sizeof(clothestintb));
+
+       landhard = 0;
+       bled = 0;
+       spurt = 0;
+       onfire = 0;
+       onfiredelay = 0;        burnt = 0;
+       fireduration = 0;
+
+       flamedelay = 0;
+       updatestuffdelay = 0;
+
+       playerdetail = 0;
+
+       num_weapons = 0;
+
+       memset(weaponids, 0, sizeof(weaponids));
+
+       weaponactive = 0;
+       weaponstuck = 0;
+       weaponstuckwhere = 0;
+       weaponwhere = 0;
+
+       numwaypoints = 0;
+
+       memset(waypoints, 0, sizeof(waypoints));
+       memset(waypointtype, 0, sizeof(waypointtype));
+
+       pausetime = 0;
+       hastempwaypoint = 0;
+       tempwaypoint = 0;
+
+       headtarget = 0;
+       interestdelay = 0;
+
+       finalfinaltarget = 0;
+       finaltarget = 0;
+       finalpathfindpoint = 0;
+       targetpathfindpoint = 0;
+       lastpathfindpoint = 0;
+       lastpathfindpoint2 = 0;
+       lastpathfindpoint3 = 0;
+       lastpathfindpoint4 = 0;
+       onpath = 0;
+
+       waypoint = 0;
+       jumppath = 0;
+
+       lastseen = 0;
+       lastseentime = 0;
+       lastchecktime = 0;
+       stunned = 0;
+       surprised = 0;
+       runninghowlong = 0;     lastoccluded = 0;
+       laststanding = 0;
+       escapednum = 0;
+
+       speechdelay = 0;
+       neckspurtdelay = 0;
+       neckspurtparticledelay = 0;
+       neckspurtamount = 0;
+
+       whichskin = 0;
+       rabbitkickragdoll = 0;
+
+       averageloc = 0;
+       oldaverageloc = 0;
+
+       //Animation tempanimation;
+
+       occluded = 0;
+
+       jumpclimb = 0;
+}
+
+Person::~Person()
+{
+}
diff --git a/Source/Person.h b/Source/Person.h
new file mode 100644 (file)
index 0000000..a7dee6b
--- /dev/null
@@ -0,0 +1,366 @@
+#ifndef _PERSON_H_
+#define _PERSON_H_
+
+/**> HEADER FILES <**/
+
+#include "gl.h"
+#include "Quaternions.h"
+#include "fmod.h"
+#include "skeleton.h"
+#include "models.h"
+#include "Constants.h"
+#include "Terrain.h"
+#include "Sprites.h"
+#include <cmath>
+#include "Weapons.h"
+
+#define passivetype 0
+#define guardtype 1
+#define searchtype 2
+#define attacktype 3
+#define attacktypecutoff 4
+#define playercontrolled 5
+#define gethelptype 6
+#define getweapontype 7
+#define pathfindtype 8
+
+#define rabbittype 0
+#define wolftype 1
+
+class HitStruct
+{
+       public:
+               Joint *joint1;
+               Joint *joint2;
+               XYZ hitlocation;
+               bool collision;
+};
+
+class Person
+{
+       public:
+               Person();
+               ~Person();
+
+               int whichpatchx;
+               int whichpatchz;
+               
+               int currentframe;
+               int targetframe;
+               int currentanimation;
+               int targetanimation;
+               int oldcurrentframe;
+               int oldtargetframe;
+               int oldcurrentanimation;
+               int oldtargetanimation;
+               
+               int howactive;
+               
+               float parriedrecently;
+               
+               bool superruntoggle;
+               
+               int lastattack,lastattack2,lastattack3;
+               
+               XYZ currentoffset,targetoffset,offset;
+               float target;
+               float transspeed;
+               
+               XYZ realoldcoords;
+               XYZ oldcoords;
+               XYZ coords;
+               XYZ originalcoords;
+               XYZ velocity;
+               
+               XYZ proportionhead;
+               XYZ proportionlegs;
+               XYZ proportionarms;
+               XYZ proportionbody;
+               
+               float heightleft;
+               float heightright;
+               
+               float unconscioustime;
+               
+               bool immobile;
+               
+               float velspeed;
+               float targetrotation;
+               float targetrot;
+               float rot;
+               float oldrot;
+               float lookrotation;
+               float lookrotation2;
+               float rotation;
+               float rotation2;
+               float lowrotation;
+               float tilt;
+               float targettilt;
+               float tilt2;
+               float targettilt2;
+               bool rabbitkickenabled;
+               
+               float bloodloss;
+               float bleeddelay;
+               float skiddelay;
+               float skiddingdelay;
+               float deathbleeding;
+               float tempdeltav;
+               
+               float damagetolerance;
+               float damage;
+               float permanentdamage;
+               float superpermanentdamage;             float lastcollide;
+               int dead;
+               
+               float jumppower;
+               bool onground;
+               int madskills;
+               
+               int wentforweapon;
+               
+               bool calcrot;
+               
+               bool backwardsanim;
+               
+               XYZ facing;
+               
+               float bleeding;
+               float bleedx,bleedy;
+               int direction;
+               float texupdatedelay;
+               
+               float headrotation,headrotation2;
+               float targetheadrotation,targetheadrotation2;
+               
+               bool onterrain;
+               bool pause;
+               
+               float grabdelay;
+               
+               Person *victim;
+               bool hasvictim;
+               
+               float updatedelay;
+               float normalsupdatedelay;
+               
+               bool jumpstart;
+               
+               bool forwardkeydown;
+               bool forwardstogglekeydown;
+               bool rightkeydown;
+               bool leftkeydown;
+               bool backkeydown;
+               bool jumpkeydown;
+               bool jumptogglekeydown;
+               bool crouchkeydown;
+               bool crouchtogglekeydown;
+               bool drawkeydown;
+               bool drawtogglekeydown;
+               bool throwkeydown;
+               bool throwtogglekeydown;
+               bool attackkeydown;
+               bool feint;
+               bool lastfeint;
+               bool headless;
+               
+               float crouchkeydowntime;
+               float jumpkeydowntime;
+               bool freefall;
+               
+               
+               float turnspeed;
+               
+               int aitype;
+               int aitarget;
+               float aiupdatedelay;
+               float losupdatedelay;
+               int ally;
+               XYZ movetarget;
+               float collide;
+               float collided;
+               float avoidcollided;
+               bool loaded;
+               bool whichdirection;
+               float whichdirectiondelay;
+               bool avoidsomething;            XYZ avoidwhere;         
+               float blooddimamount;
+               
+               float staggerdelay;
+               float blinkdelay;
+               float twitchdelay;
+               float twitchdelay2;
+               float twitchdelay3;
+               float lefthandmorphness;
+               float righthandmorphness;
+               float headmorphness;
+               float chestmorphness;
+               float tailmorphness;
+               float targetlefthandmorphness;
+               float targetrighthandmorphness;
+               float targetheadmorphness;
+               float targetchestmorphness;
+               float targettailmorphness;
+               int lefthandmorphstart,lefthandmorphend;
+               int righthandmorphstart,righthandmorphend;
+               int headmorphstart,headmorphend;
+               int chestmorphstart,chestmorphend;
+               int tailmorphstart,tailmorphend;
+               
+               float weaponmissdelay;
+               float highreversaldelay;
+               float lowreversaldelay;
+               float nocollidedelay;
+               
+               int creature;
+               
+               int id;
+               
+               Skeleton skeleton;
+               
+               float speed;
+               float scale;
+               float power;
+               float speedmult;
+               
+               float protectionhead;
+               float protectionhigh;
+               float protectionlow;
+               float armorhead;
+               float armorhigh;
+               float armorlow;
+               bool metalhead;
+               bool metalhigh;
+               bool metallow;
+               
+               int numclothes;
+               char clothes[10][256];
+               float clothestintr[10];
+               float clothestintg[10];
+               float clothestintb[10];
+               
+               bool landhard;
+               bool bled;
+               bool spurt;
+               bool onfire;
+               float onfiredelay;              float burnt;
+               float fireduration;
+               
+               float flamedelay;
+               float updatestuffdelay;
+               
+               int playerdetail;
+               
+               int num_weapons;
+               int weaponids[4];
+               int weaponactive;
+               int weaponstuck;
+               int weaponstuckwhere;
+               int weaponwhere;
+               
+               int numwaypoints;
+               XYZ waypoints[90];
+               int waypointtype[90];
+               float pausetime;
+               bool hastempwaypoint;
+               XYZ tempwaypoint;
+               
+               XYZ headtarget;
+               float interestdelay;
+               
+               XYZ finalfinaltarget;
+               XYZ finaltarget;
+               int finalpathfindpoint;
+               int targetpathfindpoint;
+               int lastpathfindpoint;
+               int lastpathfindpoint2;
+               int lastpathfindpoint3;
+               int lastpathfindpoint4;
+               bool onpath;
+               
+               int waypoint;
+               bool jumppath;
+               
+               XYZ lastseen;
+               float lastseentime;
+               float lastchecktime;
+               float stunned;
+               float surprised;
+               float runninghowlong;           int lastoccluded;
+               int laststanding;
+               int escapednum;
+               
+               float speechdelay;
+               float neckspurtdelay;
+               float neckspurtparticledelay;
+               float neckspurtamount;
+               
+               int whichskin;
+               bool rabbitkickragdoll;
+               
+               XYZ averageloc;
+               XYZ oldaverageloc;
+               
+               Animation tempanimation;
+               
+               float occluded;
+               
+               void CheckKick();
+               void CatchFire();
+               void DoBlood(float howmuch, int which);
+               void DoBloodBig(float howmuch, int which);
+               bool DoBloodBigWhere(float howmuch, int which, XYZ where);
+               
+               bool wasIdle();
+               bool isIdle();
+               int getIdle();
+               
+               bool isSitting();
+               bool isSleeping();
+               
+               
+               bool wasCrouch();
+               bool isCrouch();
+               int getCrouch();
+               
+               bool wasStop();
+               bool isStop();
+               int getStop();
+               
+               bool wasSneak();
+               bool isSneak();
+               int getSneak();
+               
+               bool wasRun();
+               bool isRun();
+               int getRun();
+               
+               bool wasLanding();
+               bool isLanding();
+               int getLanding();
+               
+               bool wasLandhard();
+               bool isLandhard();
+               int getLandhard();
+               
+               bool isFlip();
+               bool wasFlip();
+               
+               bool jumpclimb;
+               
+               bool isWallJump();
+               void Reverse();
+               void DoDamage(float howmuch);
+               void DoHead();
+               void DoMipmaps(int howmanylevels, float startx, float endx, float starty, float endy);
+               int SphereCheck(XYZ *p1,float radius, XYZ *p, XYZ *move, float *rotate, Model *model);
+               int DrawSkeleton();
+               void Puff(int whichlabel);
+               void FootLand(int which, float opacity);
+               void DoStuff();
+               void DoAnimations();
+               void RagDoll(bool checkcollision);
+               HitStruct BulletCollideWithPlayer(XYZ start, XYZ end);
+};
+
+#endif
\ No newline at end of file
diff --git a/Source/PhysicsMath.h b/Source/PhysicsMath.h
new file mode 100644 (file)
index 0000000..064829e
--- /dev/null
@@ -0,0 +1,738 @@
+#ifndef _PHYSICSMATH_H_
+#define _PHYSICSMATH_H_
+
+//#include <Carbon.h>
+
+#ifdef WIN32
+#include "WinDefs.h"
+#endif
+
+//------------------------------------------------------------------------//
+// Misc. Constants
+//------------------------------------------------------------------------//
+
+float  const   pi      = 3.14159265f;
+float  const   g       = -32.174f;             // acceleration due to gravity, ft/s^2
+float  const   rho = 0.0023769f;       // desity of air at sea level, slugs/ft^3
+float  const   tol = 0.0000000001f;            // float type tolerance 
+
+
+//------------------------------------------------------------------------//
+// Misc. Functions
+//------------------------------------------------------------------------//
+inline float   DegreesToRadians(float deg);
+inline float   RadiansToDegrees(float rad);
+
+inline float   DegreesToRadians(float deg)
+{
+       return deg * pi / 180.0f;
+}
+
+inline float   RadiansToDegrees(float rad)
+{      
+       return rad * 180.0f / pi;
+}
+
+//------------------------------------------------------------------------//
+// Vector Class and vector functions
+//------------------------------------------------------------------------//
+class Vector {
+public:
+       float x;
+       float y;
+       float z;
+
+       Vector(void);
+       Vector(float xi, float yi, float zi);
+
+       float Magnitude(void);
+       void  Normalize(void);
+       void  Reverse(void);
+
+       Vector& operator+=(Vector u);   // vector addition
+       Vector& operator-=(Vector u);   // vector subtraction
+       Vector& operator*=(float s);    // scalar multiply
+       Vector& operator/=(float s);    // scalar divide
+
+       Vector operator-(void);
+
+};
+
+inline Vector operator+(Vector u, Vector v);
+inline Vector operator-(Vector u, Vector v);
+inline Vector operator^(Vector u, Vector v);
+inline float operator*(Vector u, Vector v);
+inline Vector operator*(float s, Vector u);
+inline Vector operator*(Vector u, float s);
+inline Vector operator/(Vector u, float s);
+inline float TripleScalarProduct(Vector u, Vector v, Vector w);
+/*
+float fast_sqrt2 (register float arg);
+float fast_sqrt2 (register float arg)
+{      
+// Can replace with slower return std::sqrt(arg);
+register float result;
+
+if (arg == 0.0) return 0.0;
+
+asm {
+frsqrte                result,arg                      // Calculate Square root
+}      
+
+// Newton Rhapson iterations.
+result = result + 0.5 * result * (1.0 - arg * result * result);
+result = result + 0.5 * result * (1.0 - arg * result * result);
+
+return result * arg;
+}
+*/
+inline Vector::Vector(void)
+{
+       x = 0;
+       y = 0;
+       z = 0;
+}
+
+inline Vector::Vector(float xi, float yi, float zi)
+{
+       x = xi;
+       y = yi;
+       z = zi;
+}
+
+inline float Vector::Magnitude(void)
+{
+       return (float) sqrt(x*x + y*y + z*z);
+}
+
+inline void  Vector::Normalize(void)
+{
+       float m = (float) sqrt(x*x + y*y + z*z);
+       if(m <= tol) m = 1;
+       x /= m;
+       y /= m;
+       z /= m; 
+
+       if (fabs(x) < tol) x = 0.0f;
+       if (fabs(y) < tol) y = 0.0f;
+       if (fabs(z) < tol) z = 0.0f;
+}
+
+inline void  Vector::Reverse(void)
+{
+       x = -x;
+       y = -y;
+       z = -z;
+}
+
+inline Vector& Vector::operator+=(Vector u)
+{
+       x += u.x;
+       y += u.y;
+       z += u.z;
+       return *this;
+}
+
+inline Vector& Vector::operator-=(Vector u)
+{
+       x -= u.x;
+       y -= u.y;
+       z -= u.z;
+       return *this;
+}
+
+inline Vector& Vector::operator*=(float s)
+{
+       x *= s;
+       y *= s;
+       z *= s;
+       return *this;
+}
+
+inline Vector& Vector::operator/=(float s)
+{
+       x /= s;
+       y /= s;
+       z /= s;
+       return *this;
+}
+
+inline Vector Vector::operator-(void)
+{
+       return Vector(-x, -y, -z);
+}
+
+
+inline Vector operator+(Vector u, Vector v)
+{
+       return Vector(u.x + v.x, u.y + v.y, u.z + v.z);
+}
+
+inline Vector operator-(Vector u, Vector v)
+{
+       return Vector(u.x - v.x, u.y - v.y, u.z - v.z);
+}
+
+// Vector cross product (u cross v)
+inline Vector operator^(Vector u, Vector v)
+{
+       return Vector(  u.y*v.z - u.z*v.y,
+               -u.x*v.z + u.z*v.x,
+               u.x*v.y - u.y*v.x );
+}
+
+// Vector dot product
+inline float operator*(Vector u, Vector v)
+{
+       return (u.x*v.x + u.y*v.y + u.z*v.z);
+}
+
+inline Vector operator*(float s, Vector u)
+{
+       return Vector(u.x*s, u.y*s, u.z*s);
+}
+
+inline Vector operator*(Vector u, float s)
+{
+       return Vector(u.x*s, u.y*s, u.z*s);
+}
+
+inline Vector operator/(Vector u, float s)
+{
+       return Vector(u.x/s, u.y/s, u.z/s);
+}
+
+// triple scalar product (u dot (v cross w))
+inline float TripleScalarProduct(Vector u, Vector v, Vector w)
+{
+       return float(   (u.x * (v.y*w.z - v.z*w.y)) +
+               (u.y * (-v.x*w.z + v.z*w.x)) +
+               (u.z * (v.x*w.y - v.y*w.x)) );
+       //return u*(v^w);
+
+}
+
+
+
+//------------------------------------------------------------------------//
+// Matrix Class and matrix functions
+//------------------------------------------------------------------------//
+
+class Matrix3x3 {
+public:
+       // elements eij: i -> row, j -> column
+       float   e11, e12, e13, e21, e22, e23, e31, e32, e33;    
+
+       Matrix3x3(void);
+       Matrix3x3(      float r1c1, float r1c2, float r1c3, 
+               float r2c1, float r2c2, float r2c3, 
+               float r3c1, float r3c2, float r3c3 );
+
+       float   det(void);
+       Matrix3x3       Transpose(void);
+       Matrix3x3       Inverse(void);
+
+       Matrix3x3& operator+=(Matrix3x3 m);
+       Matrix3x3& operator-=(Matrix3x3 m);
+       Matrix3x3& operator*=(float s);
+       Matrix3x3& operator/=(float s);
+};
+
+inline Matrix3x3 operator+(Matrix3x3 m1, Matrix3x3 m2);
+inline Matrix3x3 operator-(Matrix3x3 m1, Matrix3x3 m2);
+inline Matrix3x3 operator/(Matrix3x3 m, float s);
+inline Matrix3x3 operator*(Matrix3x3 m1, Matrix3x3 m2);
+inline Matrix3x3 operator*(Matrix3x3 m, float s);
+inline Matrix3x3 operator*(float s, Matrix3x3 m);
+inline Vector operator*(Matrix3x3 m, Vector u);
+inline Vector operator*(Vector u, Matrix3x3 m);
+
+
+
+
+
+inline Matrix3x3::Matrix3x3(void)
+{
+       e11 = 0;
+       e12 = 0;
+       e13 = 0;
+       e21 = 0;
+       e22 = 0;
+       e23 = 0;
+       e31 = 0;
+       e32 = 0;
+       e33 = 0;
+}
+
+inline Matrix3x3::Matrix3x3(   float r1c1, float r1c2, float r1c3, 
+                                                        float r2c1, float r2c2, float r2c3, 
+                                                        float r3c1, float r3c2, float r3c3 )
+{
+       e11 = r1c1;
+       e12 = r1c2;
+       e13 = r1c3;
+       e21 = r2c1;
+       e22 = r2c2;
+       e23 = r2c3;
+       e31 = r3c1;
+       e32 = r3c2;
+       e33 = r3c3;
+}
+
+inline float   Matrix3x3::det(void)
+{
+       return  e11*e22*e33 - 
+               e11*e32*e23 + 
+               e21*e32*e13 - 
+               e21*e12*e33 + 
+               e31*e12*e23 - 
+               e31*e22*e13;    
+}
+
+inline Matrix3x3       Matrix3x3::Transpose(void)
+{
+       return Matrix3x3(e11,e21,e31,e12,e22,e32,e13,e23,e33);
+}
+
+inline Matrix3x3       Matrix3x3::Inverse(void)
+{
+       float   d = e11*e22*e33 - 
+               e11*e32*e23 + 
+               e21*e32*e13 - 
+               e21*e12*e33 + 
+               e31*e12*e23 - 
+               e31*e22*e13;
+
+       if (d == 0) d = 1;
+
+       return  Matrix3x3(      (e22*e33-e23*e32)/d,
+               -(e12*e33-e13*e32)/d,
+               (e12*e23-e13*e22)/d,
+               -(e21*e33-e23*e31)/d,
+               (e11*e33-e13*e31)/d,
+               -(e11*e23-e13*e21)/d,
+               (e21*e32-e22*e31)/d,
+               -(e11*e32-e12*e31)/d,
+               (e11*e22-e12*e21)/d );  
+}
+
+inline Matrix3x3& Matrix3x3::operator+=(Matrix3x3 m)
+{
+       e11 += m.e11;
+       e12 += m.e12;
+       e13 += m.e13;
+       e21 += m.e21;
+       e22 += m.e22;
+       e23 += m.e23;
+       e31 += m.e31;
+       e32 += m.e32;
+       e33 += m.e33;
+       return *this;
+}
+
+inline Matrix3x3& Matrix3x3::operator-=(Matrix3x3 m)
+{
+       e11 -= m.e11;
+       e12 -= m.e12;
+       e13 -= m.e13;
+       e21 -= m.e21;
+       e22 -= m.e22;
+       e23 -= m.e23;
+       e31 -= m.e31;
+       e32 -= m.e32;
+       e33 -= m.e33;
+       return *this;
+}
+
+inline Matrix3x3& Matrix3x3::operator*=(float s)
+{
+       e11 *= s;
+       e12 *= s;
+       e13 *= s;
+       e21 *= s;
+       e22 *= s;
+       e23 *= s;
+       e31 *= s;
+       e32 *= s;
+       e33 *= s;
+       return *this;
+}
+
+inline Matrix3x3& Matrix3x3::operator/=(float s)
+{
+       e11 /= s;
+       e12 /= s;
+       e13 /= s;
+       e21 /= s;
+       e22 /= s;
+       e23 /= s;
+       e31 /= s;
+       e32 /= s;
+       e33 /= s;
+       return *this;
+}
+
+inline Matrix3x3 operator+(Matrix3x3 m1, Matrix3x3 m2)
+{
+       return  Matrix3x3(      m1.e11+m2.e11,
+               m1.e12+m2.e12,
+               m1.e13+m2.e13,
+               m1.e21+m2.e21,
+               m1.e22+m2.e22,
+               m1.e23+m2.e23,
+               m1.e31+m2.e31,
+               m1.e32+m2.e32,
+               m1.e33+m2.e33);
+}
+
+inline Matrix3x3 operator-(Matrix3x3 m1, Matrix3x3 m2)
+{
+       return  Matrix3x3(      m1.e11-m2.e11,
+               m1.e12-m2.e12,
+               m1.e13-m2.e13,
+               m1.e21-m2.e21,
+               m1.e22-m2.e22,
+               m1.e23-m2.e23,
+               m1.e31-m2.e31,
+               m1.e32-m2.e32,
+               m1.e33-m2.e33);
+}
+
+inline Matrix3x3 operator/(Matrix3x3 m, float s)
+{      
+       return  Matrix3x3(      m.e11/s,
+               m.e12/s,
+               m.e13/s,
+               m.e21/s,
+               m.e22/s,
+               m.e23/s,
+               m.e31/s,
+               m.e32/s,
+               m.e33/s);
+}
+
+inline Matrix3x3 operator*(Matrix3x3 m1, Matrix3x3 m2)
+{
+       return Matrix3x3(       m1.e11*m2.e11 + m1.e12*m2.e21 + m1.e13*m2.e31,
+               m1.e11*m2.e12 + m1.e12*m2.e22 + m1.e13*m2.e32,
+               m1.e11*m2.e13 + m1.e12*m2.e23 + m1.e13*m2.e33,
+               m1.e21*m2.e11 + m1.e22*m2.e21 + m1.e23*m2.e31,
+               m1.e21*m2.e12 + m1.e22*m2.e22 + m1.e23*m2.e32,
+               m1.e21*m2.e13 + m1.e22*m2.e23 + m1.e23*m2.e33,
+               m1.e31*m2.e11 + m1.e32*m2.e21 + m1.e33*m2.e31,
+               m1.e31*m2.e12 + m1.e32*m2.e22 + m1.e33*m2.e32,
+               m1.e31*m2.e13 + m1.e32*m2.e23 + m1.e33*m2.e33 );
+}
+
+inline Matrix3x3 operator*(Matrix3x3 m, float s)
+{
+       return  Matrix3x3(      m.e11*s,
+               m.e12*s,
+               m.e13*s,
+               m.e21*s,
+               m.e22*s,
+               m.e23*s,
+               m.e31*s,
+               m.e32*s,
+               m.e33*s);
+}
+
+inline Matrix3x3 operator*(float s, Matrix3x3 m)
+{
+       return  Matrix3x3(      m.e11*s,
+               m.e12*s,
+               m.e13*s,
+               m.e21*s,
+               m.e22*s,
+               m.e23*s,
+               m.e31*s,
+               m.e32*s,
+               m.e33*s);
+}
+
+inline Vector operator*(Matrix3x3 m, Vector u)
+{
+       return Vector(  m.e11*u.x + m.e12*u.y + m.e13*u.z,
+               m.e21*u.x + m.e22*u.y + m.e23*u.z,
+               m.e31*u.x + m.e32*u.y + m.e33*u.z);                                     
+}
+
+inline Vector operator*(Vector u, Matrix3x3 m)
+{
+       return Vector(  u.x*m.e11 + u.y*m.e21 + u.z*m.e31,
+               u.x*m.e12 + u.y*m.e22 + u.z*m.e32,
+               u.x*m.e13 + u.y*m.e23 + u.z*m.e33);
+}
+
+//------------------------------------------------------------------------//
+// Quaternion Class and Quaternion functions
+//------------------------------------------------------------------------//
+
+class Quaternion {
+public:
+       float   n;      // number (scalar) part
+       Vector  v;      // vector part: v.x, v.y, v.z
+
+       Quaternion(void);
+       Quaternion(float e0, float e1, float e2, float e3);
+
+       float   Magnitude(void);
+       Vector  GetVector(void);
+       float   GetScalar(void);
+       Quaternion      operator+=(Quaternion q);
+       Quaternion      operator-=(Quaternion q);
+       Quaternion operator*=(float s);
+       Quaternion operator/=(float s);
+       Quaternion      operator~(void) const { return Quaternion(n, -v.x, -v.y, -v.z);}
+};
+
+inline Quaternion operator+(Quaternion q1, Quaternion q2);
+inline Quaternion operator-(Quaternion q1, Quaternion q2);
+inline Quaternion operator*(Quaternion q1, Quaternion q2);
+inline Quaternion operator*(Quaternion q, float s);
+inline Quaternion operator*(float s, Quaternion q);
+inline Quaternion operator*(Quaternion q, Vector v);
+inline Quaternion operator*(Vector v, Quaternion q);
+inline Quaternion operator/(Quaternion q, float s);
+inline float QGetAngle(Quaternion q);
+inline Vector QGetAxis(Quaternion q);
+inline Quaternion QRotate(Quaternion q1, Quaternion q2);
+inline Vector  QVRotate(Quaternion q, Vector v);
+inline Quaternion      MakeQFromEulerAngles(float x, float y, float z);
+inline Vector  MakeEulerAnglesFromQ(Quaternion q);
+
+
+inline Quaternion::Quaternion(void)
+{
+       n = 0;
+       v.x = 0;
+       v.y =  0;
+       v.z = 0;
+}
+
+inline Quaternion::Quaternion(float e0, float e1, float e2, float e3)
+{
+       n = e0;
+       v.x = e1;
+       v.y = e2;
+       v.z = e3;
+}
+
+inline float   Quaternion::Magnitude(void)
+{
+       return (float) sqrt(n*n + v.x*v.x + v.y*v.y + v.z*v.z);
+}
+
+inline Vector  Quaternion::GetVector(void)
+{
+       return Vector(v.x, v.y, v.z);
+}
+
+inline float   Quaternion::GetScalar(void)
+{
+       return n;
+}
+
+inline Quaternion      Quaternion::operator+=(Quaternion q)
+{
+       n += q.n;
+       v.x += q.v.x;
+       v.y += q.v.y;
+       v.z += q.v.z;
+       return *this;
+}
+
+inline Quaternion      Quaternion::operator-=(Quaternion q)
+{
+       n -= q.n;
+       v.x -= q.v.x;
+       v.y -= q.v.y;
+       v.z -= q.v.z;
+       return *this;
+}
+
+inline Quaternion Quaternion::operator*=(float s)
+{
+       n *= s;
+       v.x *= s;
+       v.y *= s;
+       v.z *= s;
+       return *this;
+}
+
+inline Quaternion Quaternion::operator/=(float s)
+{
+       n /= s;
+       v.x /= s;
+       v.y /= s;
+       v.z /= s;
+       return *this;
+}
+
+/*inline       Quaternion      Quaternion::operator~()
+{
+return Quaternion(n, -v.x, -v.y, -v.z);
+}*/
+
+inline Quaternion operator+(Quaternion q1, Quaternion q2)
+{
+       return  Quaternion(     q1.n + q2.n,
+               q1.v.x + q2.v.x,
+               q1.v.y + q2.v.y,
+               q1.v.z + q2.v.z);
+}
+
+inline Quaternion operator-(Quaternion q1, Quaternion q2)
+{
+       return  Quaternion(     q1.n - q2.n,
+               q1.v.x - q2.v.x,
+               q1.v.y - q2.v.y,
+               q1.v.z - q2.v.z);
+}
+
+inline Quaternion operator*(Quaternion q1, Quaternion q2)
+{
+       return  Quaternion(     q1.n*q2.n - q1.v.x*q2.v.x - q1.v.y*q2.v.y - q1.v.z*q2.v.z,
+               q1.n*q2.v.x + q1.v.x*q2.n + q1.v.y*q2.v.z - q1.v.z*q2.v.y,
+               q1.n*q2.v.y + q1.v.y*q2.n + q1.v.z*q2.v.x - q1.v.x*q2.v.z,
+               q1.n*q2.v.z + q1.v.z*q2.n + q1.v.x*q2.v.y - q1.v.y*q2.v.x);                                                     
+}
+
+inline Quaternion operator*(Quaternion q, float s)
+{
+       return  Quaternion(q.n*s, q.v.x*s, q.v.y*s, q.v.z*s);
+}
+
+inline Quaternion operator*(float s, Quaternion q)
+{
+       return  Quaternion(q.n*s, q.v.x*s, q.v.y*s, q.v.z*s);
+}
+
+inline Quaternion operator*(Quaternion q, Vector v)
+{
+       return  Quaternion(     -(q.v.x*v.x + q.v.y*v.y + q.v.z*v.z),
+               q.n*v.x + q.v.y*v.z - q.v.z*v.y,
+               q.n*v.y + q.v.z*v.x - q.v.x*v.z,
+               q.n*v.z + q.v.x*v.y - q.v.y*v.x);
+}
+
+inline Quaternion operator*(Vector v, Quaternion q)
+{
+       return  Quaternion(     -(q.v.x*v.x + q.v.y*v.y + q.v.z*v.z),
+               q.n*v.x + q.v.z*v.y - q.v.y*v.z,
+               q.n*v.y + q.v.x*v.z - q.v.z*v.x,
+               q.n*v.z + q.v.y*v.x - q.v.x*v.y);
+}
+
+inline Quaternion operator/(Quaternion q, float s)
+{
+       return  Quaternion(q.n/s, q.v.x/s, q.v.y/s, q.v.z/s);
+}
+
+inline float QGetAngle(Quaternion q)
+{
+       return  (float) (2*acosf(q.n));
+}
+
+inline Vector QGetAxis(Quaternion q)
+{
+       Vector v;
+       float m;
+
+       v = q.GetVector();
+       m = v.Magnitude();
+
+       if (m <= tol)
+               return Vector();
+       else
+               return v/m;     
+}
+
+inline Quaternion QRotate(Quaternion q1, Quaternion q2)
+{
+       return  q1*q2*(~q1);
+}
+
+inline Vector  QVRotate(Quaternion q, Vector v)
+{
+       Quaternion t;
+
+
+       t = q*v*(~q);
+
+       return  t.GetVector();
+}
+
+inline Quaternion      MakeQFromEulerAngles(float x, float y, float z)
+{
+       Quaternion      q;
+       double  roll = DegreesToRadians(x);
+       double  pitch = DegreesToRadians(y);
+       double  yaw = DegreesToRadians(z);
+
+       double  cyaw, cpitch, croll, syaw, spitch, sroll;
+       double  cyawcpitch, syawspitch, cyawspitch, syawcpitch;
+
+       cyaw = cos(0.5f * yaw);
+       cpitch = cos(0.5f * pitch);
+       croll = cos(0.5f * roll);
+       syaw = sin(0.5f * yaw);
+       spitch = sin(0.5f * pitch);
+       sroll = sin(0.5f * roll);
+
+       cyawcpitch = cyaw*cpitch;
+       syawspitch = syaw*spitch;
+       cyawspitch = cyaw*spitch;
+       syawcpitch = syaw*cpitch;
+
+       q.n = (float) (cyawcpitch * croll + syawspitch * sroll);
+       q.v.x = (float) (cyawcpitch * sroll - syawspitch * croll); 
+       q.v.y = (float) (cyawspitch * croll + syawcpitch * sroll);
+       q.v.z = (float) (syawcpitch * croll - cyawspitch * sroll);
+
+       return q;
+}
+
+inline Vector  MakeEulerAnglesFromQ(Quaternion q)
+{
+       double  r11, r21, r31, r32, r33, r12, r13;
+       double  q00, q11, q22, q33;
+       double  tmp;
+       Vector  u;
+
+       q00 = q.n * q.n;
+       q11 = q.v.x * q.v.x;
+       q22 = q.v.y * q.v.y;
+       q33 = q.v.z * q.v.z;
+
+       r11 = q00 + q11 - q22 - q33;
+       r21 = 2 * (q.v.x*q.v.y + q.n*q.v.z);
+       r31 = 2 * (q.v.x*q.v.z - q.n*q.v.y);
+       r32 = 2 * (q.v.y*q.v.z + q.n*q.v.x);
+       r33 = q00 - q11 - q22 + q33;
+
+       tmp = fabs(r31);
+       if(tmp > 0.999999)
+       {
+               r12 = 2 * (q.v.x*q.v.y - q.n*q.v.z);
+               r13 = 2 * (q.v.x*q.v.z + q.n*q.v.y);
+
+               u.x = RadiansToDegrees(0.0f); //roll
+               u.y = RadiansToDegrees((float) (-(pi/2) * r31/tmp)); // pitch
+               u.z = RadiansToDegrees((float) atan2(-r12, -r31*r13)); // yaw
+               return u;
+       }
+
+       u.x = RadiansToDegrees((float) atan2(r32, r33)); // roll
+       u.y = RadiansToDegrees((float) asinf(-r31));             // pitch
+       u.z = RadiansToDegrees((float) atan2(r21, r11)); // yaw
+       return u;
+
+
+}
+
+
+
+
+
+#endif
\ No newline at end of file
diff --git a/Source/Pointer.h b/Source/Pointer.h
new file mode 100644 (file)
index 0000000..37595e1
--- /dev/null
@@ -0,0 +1,70 @@
+// Pointer.h: interface for the Pointer class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#ifndef _POINTER_H
+#define _POINTER_H
+
+template <class T>
+class Pointer 
+{
+private:
+       void Destroy()
+       {
+               p = NULL;
+               GC::Collect();          
+       }
+
+public:
+    T* p;
+
+    Pointer( T* p_ = NULL ) : p( p_ ) 
+       {
+       }
+
+    ~Pointer() 
+       { 
+               GC::SetTotalBytesAllocated( GC::GetTotalBytesAllocated() - sizeof( *p ) );
+
+               p->~T(); // Explicitely call the destructor
+               
+               Destroy();
+
+       }
+       
+    Pointer& operator = ( Pointer<T>& p_ )
+       {
+               return operator = ( ( T* ) p_);
+       }
+    
+       Pointer& operator = ( T* p_ ) 
+       {     
+               Destroy();
+               p = p_; 
+               return *this;
+    }
+
+    operator T*() 
+       { 
+               return p; 
+       }
+    
+       T& operator*() 
+       { 
+               return *p; 
+       }
+    
+       T* operator->() 
+       { 
+               return p; 
+       }
+    
+// For automatic type conversion during new call
+       operator void**()
+       {
+               return ( void** ) & p;
+       }
+};
+
+
+#endif 
diff --git a/Source/Quaternions.cpp b/Source/Quaternions.cpp
new file mode 100644 (file)
index 0000000..ab9034d
--- /dev/null
@@ -0,0 +1,508 @@
+#include "Quaternions.h"
+
+// Functions
+quaternion Quat_Mult(quaternion q1, quaternion q2)
+{
+       quaternion QResult;
+       float a, b, c, d, e, f, g, h;
+       a = (q1.w + q1.x) * (q2.w + q2.x);
+       b = (q1.z - q1.y) * (q2.y - q2.z);
+       c = (q1.w - q1.x) * (q2.y + q2.z);
+       d = (q1.y + q1.z) * (q2.w - q2.x);
+       e = (q1.x + q1.z) * (q2.x + q2.y);
+       f = (q1.x - q1.z) * (q2.x - q2.y);
+       g = (q1.w + q1.y) * (q2.w - q2.z);
+       h = (q1.w - q1.y) * (q2.w + q2.z);
+       QResult.w = b + (-e - f + g + h) / 2;
+       QResult.x = a - (e + f + g + h) / 2;
+       QResult.y = c + (e - f + g - h) / 2;
+       QResult.z = d + (e - f - g + h) / 2;
+       return QResult;
+}
+
+
+
+quaternion To_Quat(Matrix_t m)
+{
+       // From Jason Shankel, (C) 2000.
+       static quaternion Quat;
+
+       static double Tr = m[0][0] + m[1][1] + m[2][2] + 1.0, fourD;
+       static double q[4];
+
+       static int i,j,k;
+       if (Tr >= 1.0)
+       {
+               fourD = 2.0*fast_sqrt(Tr);
+               q[3] = fourD/4.0;
+               q[0] = (m[2][1] - m[1][2]) / fourD;
+               q[1] = (m[0][2] - m[2][0]) / fourD;
+               q[2] = (m[1][0] - m[0][1]) / fourD;
+       }
+       else
+       {
+               if (m[0][0] > m[1][1])
+               {
+                       i = 0;
+               }
+               else
+               {
+                       i = 1;
+               }
+               if (m[2][2] > m[i][i])
+               {
+                       i = 2;
+               }
+               j = (i+1)%3;
+               k = (j+1)%3;
+               fourD = 2.0*fast_sqrt(m[i][i] - m[j][j] - m[k][k] + 1.0);
+               q[i] = fourD / 4.0;
+               q[j] = (m[j][i] + m[i][j]) / fourD;
+               q[k] = (m[k][i] + m[i][k]) / fourD;
+               q[3] = (m[j][k] - m[k][j]) / fourD;
+       }
+
+       Quat.x = q[0];
+       Quat.y = q[1];
+       Quat.z = q[2];
+       Quat.w = q[3];
+       return Quat;
+}
+void Quat_2_Matrix(quaternion Quat, Matrix_t m)
+{
+       // From the GLVelocity site (http://glvelocity.gamedev.net)
+       float fW = Quat.w;
+       float fX = Quat.x;
+       float fY = Quat.y;
+       float fZ = Quat.z;
+       float fXX = fX * fX;
+       float fYY = fY * fY;
+       float fZZ = fZ * fZ;
+       m[0][0] = 1.0f - 2.0f * (fYY + fZZ);
+       m[1][0] = 2.0f * (fX * fY + fW * fZ);
+       m[2][0] = 2.0f * (fX * fZ - fW * fY);
+       m[3][0] = 0.0f;
+       m[0][1] = 2.0f * (fX * fY - fW * fZ);
+       m[1][1] = 1.0f - 2.0f * (fXX + fZZ);
+       m[2][1] = 2.0f * (fY * fZ + fW * fX);
+       m[3][1] = 0.0f;
+       m[0][2] = 2.0f * (fX * fZ + fW * fY);
+       m[1][2] = 2.0f * (fX * fZ - fW * fX);
+       m[2][2] = 1.0f - 2.0f * (fXX + fYY);
+       m[3][2] = 0.0f;
+       m[0][3] = 0.0f;
+       m[1][3] = 0.0f;
+       m[2][3] = 0.0f;
+       m[3][3] = 1.0f;
+}
+quaternion To_Quat(angle_axis Ang_Ax)
+{
+       // From the Quaternion Powers article on gamedev.net
+       static quaternion Quat;
+
+       Quat.x = Ang_Ax.x * sin(Ang_Ax.angle / 2);
+       Quat.y = Ang_Ax.y * sin(Ang_Ax.angle / 2);
+       Quat.z = Ang_Ax.z * sin(Ang_Ax.angle / 2);
+       Quat.w = cos(Ang_Ax.angle / 2);
+       return Quat;
+}
+angle_axis Quat_2_AA(quaternion Quat)
+{
+       static angle_axis Ang_Ax;
+       static float scale, tw;
+       tw = (float)acosf(Quat.w) * 2;
+       scale = (float)sin(tw / 2.0);
+       Ang_Ax.x = Quat.x / scale;
+       Ang_Ax.y = Quat.y / scale;
+       Ang_Ax.z = Quat.z / scale;
+
+       Ang_Ax.angle = 2.0 * acosf(Quat.w)/(float)PI*180;
+       return Ang_Ax;
+}
+
+quaternion To_Quat(int In_Degrees, euler Euler)
+{
+       // From the gamasutra quaternion article
+       static quaternion Quat;
+       static float cr, cp, cy, sr, sp, sy, cpcy, spsy;
+       //If we are in Degree mode, convert to Radians
+       if (In_Degrees) {
+               Euler.x = Euler.x * (float)PI / 180;
+               Euler.y = Euler.y * (float)PI / 180;
+               Euler.z = Euler.z * (float)PI / 180;
+       }
+       //Calculate trig identities
+       //Formerly roll, pitch, yaw
+       cr = float(cos(Euler.x/2));
+       cp = float(cos(Euler.y/2));
+       cy = float(cos(Euler.z/2));
+       sr = float(sin(Euler.x/2));
+       sp = float(sin(Euler.y/2));
+       sy = float(sin(Euler.z/2));
+
+       cpcy = cp * cy;
+       spsy = sp * sy;
+       Quat.w = cr * cpcy + sr * spsy;
+       Quat.x = sr * cpcy - cr * spsy;
+       Quat.y = cr * sp * cy + sr * cp * sy;
+       Quat.z = cr * cp * sy - sr * sp * cy;
+
+       return Quat;
+}
+
+quaternion QNormalize(quaternion Quat)
+{
+       static float norm;
+       norm =  Quat.x * Quat.x + 
+               Quat.y * Quat.y + 
+               Quat.z * Quat.z + 
+               Quat.w * Quat.w;
+       Quat.x = float(Quat.x / norm);
+       Quat.y = float(Quat.y / norm);
+       Quat.z = float(Quat.z / norm);
+       Quat.w = float(Quat.w / norm);
+       return Quat;
+}
+
+XYZ Quat2Vector(quaternion Quat)
+{
+       QNormalize(Quat);
+
+       float fW = Quat.w;
+       float fX = Quat.x;
+       float fY = Quat.y;
+       float fZ = Quat.z;
+
+       XYZ tempvec;
+
+       tempvec.x = 2.0f*(fX*fZ-fW*fY);
+       tempvec.y = 2.0f*(fY*fZ+fW*fX);
+       tempvec.z = 1.0f-2.0f*(fX*fX+fY*fY);
+
+       return tempvec;
+}
+
+bool PointInTriangle(Vector *p, Vector normal, float p11, float p12, float p13, float p21, float p22, float p23, float p31, float p32, float p33)
+{
+       static float u0, u1, u2;
+       static float v0, v1, v2;
+       static float a, b;
+       static float max;
+       static int i, j;
+       static bool bInter;
+       static float pointv[3];
+       static float p1v[3];
+       static float p2v[3];
+       static float p3v[3];
+       static float normalv[3];
+
+       bInter=0;
+
+       pointv[0]=p->x;
+       pointv[1]=p->y;
+       pointv[2]=p->z;
+
+
+       p1v[0]=p11;
+       p1v[1]=p12;
+       p1v[2]=p13;
+
+       p2v[0]=p21;
+       p2v[1]=p22;
+       p2v[2]=p23;
+
+       p3v[0]=p31;
+       p3v[1]=p32;
+       p3v[2]=p33;
+
+       normalv[0]=normal.x;
+       normalv[1]=normal.y;
+       normalv[2]=normal.z;
+
+#define ABS(X) (((X)<0.f)?-(X):(X) )
+#define MAX(A, B) (((A)<(B))?(B):(A))  
+       max = MAX(MAX(ABS(normalv[0]), ABS(normalv[1])), ABS(normalv[2]));
+#undef MAX
+       if (max == ABS(normalv[0])) {i = 1; j = 2;} // y, z
+       if (max == ABS(normalv[1])) {i = 0; j = 2;} // x, z
+       if (max == ABS(normalv[2])) {i = 0; j = 1;} // x, y
+#undef ABS
+
+       u0 = pointv[i] - p1v[i];
+       v0 = pointv[j] - p1v[j];
+       u1 = p2v[i] - p1v[i];
+       v1 = p2v[j] - p1v[j];
+       u2 = p3v[i] - p1v[i];
+       v2 = p3v[j] - p1v[j];
+
+       if (u1 > -1.0e-05f && u1 < 1.0e-05f)// == 0.0f)
+       {
+               b = u0 / u2;
+               if (0.0f <= b && b <= 1.0f)
+               {
+                       a = (v0 - b * v2) / v1;
+                       if ((a >= 0.0f) && (( a + b ) <= 1.0f))
+                               bInter = 1;
+               }
+       }
+       else
+       {
+               b = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
+               if (0.0f <= b && b <= 1.0f)
+               {
+                       a = (u0 - b * u2) / u1;
+                       if ((a >= 0.0f) && (( a + b ) <= 1.0f ))
+                               bInter = 1;
+               }
+       }
+
+       return bInter;
+}
+
+bool LineFacet(Vector p1,Vector p2,Vector pa,Vector pb,Vector pc,Vector *p)
+{
+       static float d;
+       static float a1,a2,a3;
+       static float total,denom,mu;
+       static Vector n,pa1,pa2,pa3;
+
+       //Calculate the parameters for the plane 
+       n.x = (pb.y - pa.y)*(pc.z - pa.z) - (pb.z - pa.z)*(pc.y - pa.y);
+       n.y = (pb.z - pa.z)*(pc.x - pa.x) - (pb.x - pa.x)*(pc.z - pa.z);
+       n.z = (pb.x - pa.x)*(pc.y - pa.y) - (pb.y - pa.y)*(pc.x - pa.x);
+       n.Normalize();
+       d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
+
+       //Calculate the position on the line that intersects the plane 
+       denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
+       if (abs(denom) < 0.0000001)        // Line and plane don't intersect 
+               return 0;
+       mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
+       p->x = p1.x + mu * (p2.x - p1.x);
+       p->y = p1.y + mu * (p2.y - p1.y);
+       p->z = p1.z + mu * (p2.z - p1.z);
+       if (mu < 0 || mu > 1)   // Intersection not along line segment 
+               return 0;
+
+       if(!PointInTriangle( p, n, pa.x, pa.y, pa.z, pb.x, pb.y, pb.z, pc.x, pc.y, pc.z)){return 0;}
+
+       return 1;
+}
+
+bool PointInTriangle(XYZ *p, XYZ normal, XYZ *p1, XYZ *p2, XYZ *p3)
+{
+       static float u0, u1, u2;
+       static float v0, v1, v2;
+       static float a, b;
+       static float max;
+       static int i, j;
+       static bool bInter = 0;
+       static float pointv[3];
+       static float p1v[3];
+       static float p2v[3];
+       static float p3v[3];
+       static float normalv[3];
+
+       bInter=0;
+
+       pointv[0]=p->x;
+       pointv[1]=p->y;
+       pointv[2]=p->z;
+
+
+       p1v[0]=p1->x;
+       p1v[1]=p1->y;
+       p1v[2]=p1->z;
+
+       p2v[0]=p2->x;
+       p2v[1]=p2->y;
+       p2v[2]=p2->z;
+
+       p3v[0]=p3->x;
+       p3v[1]=p3->y;
+       p3v[2]=p3->z;
+
+       normalv[0]=normal.x;
+       normalv[1]=normal.y;
+       normalv[2]=normal.z;
+
+#define ABS(X) (((X)<0.f)?-(X):(X) )
+#define MAX(A, B) (((A)<(B))?(B):(A))  
+       max = MAX(MAX(ABS(normalv[0]), ABS(normalv[1])), ABS(normalv[2]));
+#undef MAX
+       if (max == ABS(normalv[0])) {i = 1; j = 2;} // y, z
+       if (max == ABS(normalv[1])) {i = 0; j = 2;} // x, z
+       if (max == ABS(normalv[2])) {i = 0; j = 1;} // x, y
+#undef ABS
+
+       u0 = pointv[i] - p1v[i];
+       v0 = pointv[j] - p1v[j];
+       u1 = p2v[i] - p1v[i];
+       v1 = p2v[j] - p1v[j];
+       u2 = p3v[i] - p1v[i];
+       v2 = p3v[j] - p1v[j];
+
+       if (u1 > -1.0e-05f && u1 < 1.0e-05f)// == 0.0f)
+       {
+               b = u0 / u2;
+               if (0.0f <= b && b <= 1.0f)
+               {
+                       a = (v0 - b * v2) / v1;
+                       if ((a >= 0.0f) && (( a + b ) <= 1.0f))
+                               bInter = 1;
+               }
+       }
+       else
+       {
+               b = (v0 * u1 - u0 * v1) / (v2 * u1 - u2 * v1);
+               if (0.0f <= b && b <= 1.0f)
+               {
+                       a = (u0 - b * u2) / u1;
+                       if ((a >= 0.0f) && (( a + b ) <= 1.0f ))
+                               bInter = 1;
+               }
+       }
+
+       return bInter;
+}
+
+bool LineFacet(XYZ p1,XYZ p2,XYZ pa,XYZ pb,XYZ pc,XYZ *p)
+{
+       static float d;
+       static float a1,a2,a3;
+       static float total,denom,mu;
+       static XYZ n,pa1,pa2,pa3;
+
+       //Calculate the parameters for the plane 
+       n.x = (pb.y - pa.y)*(pc.z - pa.z) - (pb.z - pa.z)*(pc.y - pa.y);
+       n.y = (pb.z - pa.z)*(pc.x - pa.x) - (pb.x - pa.x)*(pc.z - pa.z);
+       n.z = (pb.x - pa.x)*(pc.y - pa.y) - (pb.y - pa.y)*(pc.x - pa.x);
+       Normalise(&n);
+       d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
+
+       //Calculate the position on the line that intersects the plane 
+       denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
+       if (abs(denom) < 0.0000001)        // Line and plane don't intersect 
+               return 0;
+       mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
+       p->x = p1.x + mu * (p2.x - p1.x);
+       p->y = p1.y + mu * (p2.y - p1.y);
+       p->z = p1.z + mu * (p2.z - p1.z);
+       if (mu < 0 || mu > 1)   // Intersection not along line segment 
+               return 0;
+
+       if(!PointInTriangle( p, n, &pa, &pb, &pc)){return 0;}
+
+       return 1;
+}
+
+float LineFacetd(XYZ p1,XYZ p2,XYZ pa,XYZ pb,XYZ pc,XYZ *p)
+{
+       static float d;
+       static float a1,a2,a3;
+       static float total,denom,mu;
+       static XYZ n,pa1,pa2,pa3;
+
+       //Calculate the parameters for the plane 
+       n.x = (pb.y - pa.y)*(pc.z - pa.z) - (pb.z - pa.z)*(pc.y - pa.y);
+       n.y = (pb.z - pa.z)*(pc.x - pa.x) - (pb.x - pa.x)*(pc.z - pa.z);
+       n.z = (pb.x - pa.x)*(pc.y - pa.y) - (pb.y - pa.y)*(pc.x - pa.x);
+       Normalise(&n);
+       d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
+
+       //Calculate the position on the line that intersects the plane 
+       denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
+       if (abs(denom) < 0.0000001)        // Line and plane don't intersect 
+               return 0;
+       mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
+       p->x = p1.x + mu * (p2.x - p1.x);
+       p->y = p1.y + mu * (p2.y - p1.y);
+       p->z = p1.z + mu * (p2.z - p1.z);
+       if (mu < 0 || mu > 1)   // Intersection not along line segment 
+               return 0;
+
+       if(!PointInTriangle( p, n, &pa, &pb, &pc)){return 0;}
+
+       return 1;
+}
+
+float LineFacetd(XYZ p1,XYZ p2,XYZ pa,XYZ pb,XYZ pc, XYZ n, XYZ *p)
+{
+       static float d;
+       static float a1,a2,a3;
+       static float total,denom,mu;
+       static XYZ pa1,pa2,pa3;
+
+       //Calculate the parameters for the plane 
+       d = - n.x * pa.x - n.y * pa.y - n.z * pa.z;
+
+       //Calculate the position on the line that intersects the plane 
+       denom = n.x * (p2.x - p1.x) + n.y * (p2.y - p1.y) + n.z * (p2.z - p1.z);
+       if (abs(denom) < 0.0000001)        // Line and plane don't intersect 
+               return 0;
+       mu = - (d + n.x * p1.x + n.y * p1.y + n.z * p1.z) / denom;
+       p->x = p1.x + mu * (p2.x - p1.x);
+       p->y = p1.y + mu * (p2.y - p1.y);
+       p->z = p1.z + mu * (p2.z - p1.z);
+       if (mu < 0 || mu > 1)   // Intersection not along line segment 
+               return 0;
+
+       if(!PointInTriangle( p, n, &pa, &pb, &pc)){return 0;}
+       return 1;
+}
+
+float LineFacetd(XYZ *p1,XYZ *p2,XYZ *pa,XYZ *pb,XYZ *pc, XYZ *p)
+{
+       static float d;
+       static float a1,a2,a3;
+       static float total,denom,mu;
+       static XYZ pa1,pa2,pa3,n;
+
+       //Calculate the parameters for the plane 
+       n.x = (pb->y - pa->y)*(pc->z - pa->z) - (pb->z - pa->z)*(pc->y - pa->y);
+       n.y = (pb->z - pa->z)*(pc->x - pa->x) - (pb->x - pa->x)*(pc->z - pa->z);
+       n.z = (pb->x - pa->x)*(pc->y - pa->y) - (pb->y - pa->y)*(pc->x - pa->x);
+       Normalise(&n);
+       d = - n.x * pa->x - n.y * pa->y - n.z * pa->z;
+
+
+       //Calculate the position on the line that intersects the plane 
+       denom = n.x * (p2->x - p1->x) + n.y * (p2->y - p1->y) + n.z * (p2->z - p1->z);
+       if (abs(denom) < 0.0000001)        // Line and plane don't intersect 
+               return 0;
+       mu = - (d + n.x * p1->x + n.y * p1->y + n.z * p1->z) / denom;
+       p->x = p1->x + mu * (p2->x - p1->x);
+       p->y = p1->y + mu * (p2->y - p1->y);
+       p->z = p1->z + mu * (p2->z - p1->z);
+       if (mu < 0 || mu > 1)   // Intersection not along line segment 
+               return 0;
+
+       if(!PointInTriangle( p, n, pa, pb, pc)){return 0;}
+       return 1;
+}
+
+float LineFacetd(XYZ *p1,XYZ *p2,XYZ *pa,XYZ *pb,XYZ *pc, XYZ *n, XYZ *p)
+{
+       static float d;
+       static float a1,a2,a3;
+       static float total,denom,mu;
+       static XYZ pa1,pa2,pa3;
+
+       //Calculate the parameters for the plane 
+       d = - n->x * pa->x - n->y * pa->y - n->z * pa->z;
+
+       //Calculate the position on the line that intersects the plane 
+       denom = n->x * (p2->x - p1->x) + n->y * (p2->y - p1->y) + n->z * (p2->z - p1->z);
+       if (abs(denom) < 0.0000001)        // Line and plane don't intersect 
+               return 0;
+       mu = - (d + n->x * p1->x + n->y * p1->y + n->z * p1->z) / denom;
+       p->x = p1->x + mu * (p2->x - p1->x);
+       p->y = p1->y + mu * (p2->y - p1->y);
+       p->z = p1->z + mu * (p2->z - p1->z);
+       if (mu < 0 || mu > 1)   // Intersection not along line segment 
+               return 0;
+
+       if(!PointInTriangle( p, *n, pa, pb, pc)){return 0;}
+       return 1;
+}
+
diff --git a/Source/Quaternions.h b/Source/Quaternions.h
new file mode 100644 (file)
index 0000000..872500c
--- /dev/null
@@ -0,0 +1,466 @@
+
+#ifndef _QUATERNIONS_H_
+#define _QUATERNIONS_H_
+
+#ifndef WIN32
+#pragma mark -
+#endif
+
+//#include "Carbon.h"
+#include "math.h"
+#include "Physicsmath.h"
+#include "gl.h"
+
+/**> Quaternion Structures <**/
+#define PI      3.14159265355555897932384626
+#define RADIANS 0
+#define DEGREES 1
+#define deg2rad .0174532925
+
+//using namespace std;
+typedef float Matrix_t [4][4];
+struct euler
+{
+       float x, y, z;
+};
+struct angle_axis
+{
+       float x, y, z, angle;
+};
+struct quaternion
+{
+       float x, y, z, w;
+};
+
+class XYZ{
+public:
+       float x;
+       float y;
+       float z;
+       inline XYZ operator+(XYZ add);
+       inline XYZ operator-(XYZ add);
+       inline XYZ operator*(float add);
+       inline XYZ operator*(XYZ add);
+       inline XYZ operator/(float add);
+       inline void operator+=(XYZ add);
+       inline void operator-=(XYZ add);
+       inline void operator*=(float add);
+       inline void operator*=(XYZ add);
+       inline void operator/=(float add);
+       inline void operator=(float add);
+       inline void vec(Vector add);
+       inline bool operator==(XYZ add);
+};
+
+/*********************> Quaternion Function definition <********/
+quaternion To_Quat(int Degree_Flag, euler Euler);
+quaternion To_Quat(angle_axis Ang_Ax);
+quaternion To_Quat(Matrix_t m);
+angle_axis Quat_2_AA(quaternion Quat);
+void Quat_2_Matrix(quaternion Quat, Matrix_t m);
+quaternion Normalize(quaternion Quat);
+quaternion Quat_Mult(quaternion q1, quaternion q2);
+quaternion QNormalize(quaternion Quat);
+XYZ Quat2Vector(quaternion Quat);
+
+inline void CrossProduct(XYZ *P, XYZ *Q, XYZ *V);
+inline void CrossProduct(XYZ P, XYZ Q, XYZ *V);
+inline void Normalise(XYZ *vectory);
+inline float normaldotproduct(XYZ point1, XYZ point2);
+inline float fast_sqrt (register float arg);
+bool PointInTriangle(XYZ *p, XYZ normal, XYZ *p1, XYZ *p2, XYZ *p3);
+bool LineFacet(XYZ p1,XYZ p2,XYZ pa,XYZ pb,XYZ pc,XYZ *p);
+float LineFacetd(XYZ p1,XYZ p2,XYZ pa,XYZ pb,XYZ pc,XYZ *p);
+float LineFacetd(XYZ p1,XYZ p2,XYZ pa,XYZ pb,XYZ pc,XYZ n, XYZ *p);
+float LineFacetd(XYZ *p1,XYZ *p2,XYZ *pa,XYZ *pb,XYZ *pc,XYZ *n, XYZ *p);
+float LineFacetd(XYZ *p1,XYZ *p2,XYZ *pa,XYZ *pb,XYZ *pc, XYZ *p);
+bool PointInTriangle(Vector *p, Vector normal, float p11, float p12, float p13, float p21, float p22, float p23, float p31, float p32, float p33);
+bool LineFacet(Vector p1,Vector p2,Vector pa,Vector pb,Vector pc,Vector *p);
+inline void ReflectVector(XYZ *vel, XYZ *n);
+inline XYZ DoRotation(XYZ thePoint, float xang, float yang, float zang);
+inline XYZ DoRotationRadian(XYZ thePoint, float xang, float yang, float zang);
+inline float findDistance(XYZ *point1, XYZ *point2);
+inline float findLength(XYZ *point1);
+inline float findLengthfast(XYZ *point1);
+inline float findDistancefast(XYZ *point1, XYZ *point2);
+inline float findDistancefast(XYZ point1, XYZ point2);
+inline float findDistancefastflat(XYZ *point1, XYZ *point2);
+inline float dotproduct(XYZ *point1, XYZ *point2);
+bool sphere_line_intersection (
+                                                          float x1, float y1 , float z1,
+                                                          float x2, float y2 , float z2,
+                                                          float x3, float y3 , float z3, float r );
+bool sphere_line_intersection (
+                                                          XYZ *p1, XYZ *p2, XYZ *p3, float *r );
+inline bool DistancePointLine( XYZ *Point, XYZ *LineStart, XYZ *LineEnd, float *Distance, XYZ *Intersection );
+
+
+inline void Normalise(XYZ *vectory) {
+       static float d;
+       d = fast_sqrt(vectory->x*vectory->x+vectory->y*vectory->y+vectory->z*vectory->z);
+       if(d==0){return;}
+       vectory->x /= d;
+       vectory->y /= d;
+       vectory->z /= d;
+}
+
+inline XYZ XYZ::operator+(XYZ add){
+       static XYZ ne;
+       ne=add;
+       ne.x+=x;
+       ne.y+=y;
+       ne.z+=z;
+       return ne;
+}
+
+inline XYZ XYZ::operator-(XYZ add){
+       static XYZ ne;
+       ne=add;
+       ne.x=x-ne.x;
+       ne.y=y-ne.y;
+       ne.z=z-ne.z;
+       return ne;
+}
+
+inline XYZ XYZ::operator*(float add){
+       static XYZ ne;
+       ne.x=x*add;
+       ne.y=y*add;
+       ne.z=z*add;
+       return ne;
+}
+
+inline XYZ XYZ::operator*(XYZ add){
+       static XYZ ne;
+       ne.x=x*add.x;
+       ne.y=y*add.y;
+       ne.z=z*add.z;
+       return ne;
+}
+
+inline XYZ XYZ::operator/(float add){
+       static XYZ ne;
+       ne.x=x/add;
+       ne.y=y/add;
+       ne.z=z/add;
+       return ne;
+}
+
+inline void XYZ::operator+=(XYZ add){
+       x+=add.x;
+       y+=add.y;
+       z+=add.z;
+}
+
+inline void XYZ::operator-=(XYZ add){
+       x=x-add.x;
+       y=y-add.y;
+       z=z-add.z;
+}
+
+inline void XYZ::operator*=(float add){
+       x=x*add;
+       y=y*add;
+       z=z*add;
+}
+
+inline void XYZ::operator*=(XYZ add){
+       x=x*add.x;
+       y=y*add.y;
+       z=z*add.z;
+}
+
+inline void XYZ::operator/=(float add){
+       x=x/add;
+       y=y/add;
+       z=z/add;
+}
+
+inline void XYZ::operator=(float add){
+       x=add;
+       y=add;
+       z=add;
+}
+
+inline void XYZ::vec(Vector add){
+       x=add.x;
+       y=add.y;
+       z=add.z;
+}
+
+inline bool XYZ::operator==(XYZ add){
+       if(x==add.x&&y==add.y&&z==add.z)return 1;
+       return 0;
+}
+
+inline void CrossProduct(XYZ *P, XYZ *Q, XYZ *V){
+       V->x = P->y * Q->z - P->z * Q->y;
+       V->y = P->z * Q->x - P->x * Q->z;
+       V->z = P->x * Q->y - P->y * Q->x;
+}
+
+inline void CrossProduct(XYZ P, XYZ Q, XYZ *V){
+       V->x = P.y * Q.z - P.z * Q.y;
+       V->y = P.z * Q.x - P.x * Q.z;
+       V->z = P.x * Q.y - P.y * Q.x;
+}
+
+inline float fast_sqrt (register float arg)
+{      
+#ifdef WIN32
+       return sqrtf( arg);
+#else
+       // Can replace with slower return std::sqrt(arg);
+       register float result;
+
+       if (arg == 0.0) return 0.0;
+
+       asm {
+               frsqrte         result,arg                      // Calculate Square root
+       }       
+
+       // Newton Rhapson iterations.
+       result = result + 0.5 * result * (1.0 - arg * result * result);
+       result = result + 0.5 * result * (1.0 - arg * result * result);
+
+       return result * arg;
+#endif
+}
+
+inline float normaldotproduct(XYZ point1, XYZ point2){
+       static GLfloat returnvalue;
+       Normalise(&point1);
+       Normalise(&point2);
+       returnvalue=(point1.x*point2.x+point1.y*point2.y+point1.z*point2.z);
+       return returnvalue;
+}
+
+inline void ReflectVector(XYZ *vel, XYZ *n)
+{
+       static XYZ vn;
+       static XYZ vt;
+       static float dotprod;
+
+       dotprod=dotproduct(n,vel);
+       vn.x=n->x*dotprod;
+       vn.y=n->y*dotprod;
+       vn.z=n->z*dotprod;
+
+       vt.x=vel->x-vn.x;
+       vt.y=vel->y-vn.y;
+       vt.z=vel->z-vn.z;
+
+       vel->x = vt.x - vn.x;
+       vel->y = vt.y - vn.y;
+       vel->z = vt.z - vn.z;
+}
+
+inline float dotproduct(XYZ *point1, XYZ *point2){
+       static GLfloat returnvalue;
+       returnvalue=(point1->x*point2->x+point1->y*point2->y+point1->z*point2->z);
+       return returnvalue;
+}
+
+inline float findDistance(XYZ *point1, XYZ *point2){
+       return(fast_sqrt((point1->x-point2->x)*(point1->x-point2->x)+(point1->y-point2->y)*(point1->y-point2->y)+(point1->z-point2->z)*(point1->z-point2->z)));
+}
+
+inline float findLength(XYZ *point1){
+       return(fast_sqrt((point1->x)*(point1->x)+(point1->y)*(point1->y)+(point1->z)*(point1->z)));
+}
+
+
+inline float findLengthfast(XYZ *point1){
+       return((point1->x)*(point1->x)+(point1->y)*(point1->y)+(point1->z)*(point1->z));
+}
+
+inline float findDistancefast(XYZ *point1, XYZ *point2){
+       return((point1->x-point2->x)*(point1->x-point2->x)+(point1->y-point2->y)*(point1->y-point2->y)+(point1->z-point2->z)*(point1->z-point2->z));
+}
+
+inline float findDistancefast(XYZ point1, XYZ point2){
+       return((point1.x-point2.x)*(point1.x-point2.x)+(point1.y-point2.y)*(point1.y-point2.y)+(point1.z-point2.z)*(point1.z-point2.z));
+}
+
+inline float findDistancefastflat(XYZ *point1, XYZ *point2){
+       return((point1->x-point2->x)*(point1->x-point2->x)+(point1->z-point2->z)*(point1->z-point2->z));
+}
+
+inline XYZ DoRotation(XYZ thePoint, float xang, float yang, float zang){
+       static XYZ newpoint;
+       if(xang){
+               xang*=6.283185f;
+               xang/=360;
+       }
+       if(yang){
+               yang*=6.283185f;
+               yang/=360;
+       }
+       if(zang){
+               zang*=6.283185f;
+               zang/=360;
+       }
+
+
+       if(yang){
+               newpoint.z=thePoint.z*cosf(yang)-thePoint.x*sinf(yang);
+               newpoint.x=thePoint.z*sinf(yang)+thePoint.x*cosf(yang);
+               thePoint.z=newpoint.z;
+               thePoint.x=newpoint.x;
+       }
+
+       if(zang){
+               newpoint.x=thePoint.x*cosf(zang)-thePoint.y*sinf(zang);
+               newpoint.y=thePoint.y*cosf(zang)+thePoint.x*sinf(zang);
+               thePoint.x=newpoint.x;
+               thePoint.y=newpoint.y;
+       }
+
+       if(xang){
+               newpoint.y=thePoint.y*cosf(xang)-thePoint.z*sinf(xang);
+               newpoint.z=thePoint.y*sinf(xang)+thePoint.z*cosf(xang);
+               thePoint.z=newpoint.z;
+               thePoint.y=newpoint.y;  
+       }
+
+       return thePoint;
+}
+
+inline float square( float f ) { return (f*f) ;}
+
+inline bool sphere_line_intersection (
+                                                                         float x1, float y1 , float z1,
+                                                                         float x2, float y2 , float z2,
+                                                                         float x3, float y3 , float z3, float r )
+{
+
+       // x1,y1,z1  P1 coordinates (point of line)
+       // x2,y2,z2  P2 coordinates (point of line)
+       // x3,y3,z3, r  P3 coordinates and radius (sphere)
+       // x,y,z   intersection coordinates
+       //
+       // This function returns a pointer array which first index indicates
+       // the number of intersection point, followed by coordinate pairs.
+
+       static float x , y , z;
+       static float a, b, c, mu, i ;
+
+       if(x1>x3+r&&x2>x3+r)return(0);
+       if(x1<x3-r&&x2<x3-r)return(0);
+       if(y1>y3+r&&y2>y3+r)return(0);
+       if(y1<y3-r&&y2<y3-r)return(0);
+       if(z1>z3+r&&z2>z3+r)return(0);
+       if(z1<z3-r&&z2<z3-r)return(0);
+       a =  square(x2 - x1) + square(y2 - y1) + square(z2 - z1);
+       b =  2* ( (x2 - x1)*(x1 - x3)
+               + (y2 - y1)*(y1 - y3)
+               + (z2 - z1)*(z1 - z3) ) ;
+       c =  square(x3) + square(y3) +
+               square(z3) + square(x1) +
+               square(y1) + square(z1) -
+               2* ( x3*x1 + y3*y1 + z3*z1 ) - square(r) ;
+       i =   b * b - 4 * a * c ;
+
+       if ( i < 0.0 )
+       {
+               // no intersection
+               return(0);
+       }
+       return(1);
+}
+
+inline bool sphere_line_intersection (
+                                                                         XYZ *p1, XYZ *p2, XYZ *p3, float *r )
+{
+
+       // x1,p1->y,p1->z  P1 coordinates (point of line)
+       // p2->x,p2->y,p2->z  P2 coordinates (point of line)
+       // p3->x,p3->y,p3->z, r  P3 coordinates and radius (sphere)
+       // x,y,z   intersection coordinates
+       //
+       // This function returns a pointer array which first index indicates
+       // the number of intersection point, followed by coordinate pairs.
+
+       static float x , y , z;
+       static float a, b, c, mu, i ;
+
+       if(p1->x>p3->x+*r&&p2->x>p3->x+*r)return(0);
+       if(p1->x<p3->x-*r&&p2->x<p3->x-*r)return(0);
+       if(p1->y>p3->y+*r&&p2->y>p3->y+*r)return(0);
+       if(p1->y<p3->y-*r&&p2->y<p3->y-*r)return(0);
+       if(p1->z>p3->z+*r&&p2->z>p3->z+*r)return(0);
+       if(p1->z<p3->z-*r&&p2->z<p3->z-*r)return(0);
+       a =  square(p2->x - p1->x) + square(p2->y - p1->y) + square(p2->z - p1->z);
+       b =  2* ( (p2->x - p1->x)*(p1->x - p3->x)
+               + (p2->y - p1->y)*(p1->y - p3->y)
+               + (p2->z - p1->z)*(p1->z - p3->z) ) ;
+       c =  square(p3->x) + square(p3->y) +
+               square(p3->z) + square(p1->x) +
+               square(p1->y) + square(p1->z) -
+               2* ( p3->x*p1->x + p3->y*p1->y + p3->z*p1->z ) - square(*r) ;
+       i =   b * b - 4 * a * c ;
+
+       if ( i < 0.0 )
+       {
+               // no intersection
+               return(0);
+       }
+       return(1);
+}
+
+inline XYZ DoRotationRadian(XYZ thePoint, float xang, float yang, float zang){
+       static XYZ newpoint;
+       static XYZ oldpoint;
+
+       oldpoint=thePoint;
+
+       if(yang!=0){
+               newpoint.z=oldpoint.z*cosf(yang)-oldpoint.x*sinf(yang);
+               newpoint.x=oldpoint.z*sinf(yang)+oldpoint.x*cosf(yang);
+               oldpoint.z=newpoint.z;
+               oldpoint.x=newpoint.x;
+       }
+
+       if(zang!=0){
+               newpoint.x=oldpoint.x*cosf(zang)-oldpoint.y*sinf(zang);
+               newpoint.y=oldpoint.y*cosf(zang)+oldpoint.x*sinf(zang);
+               oldpoint.x=newpoint.x;
+               oldpoint.y=newpoint.y;
+       }
+
+       if(xang!=0){
+               newpoint.y=oldpoint.y*cosf(xang)-oldpoint.z*sinf(xang);
+               newpoint.z=oldpoint.y*sinf(xang)+oldpoint.z*cosf(xang);
+               oldpoint.z=newpoint.z;
+               oldpoint.y=newpoint.y;  
+       }
+
+       return oldpoint;
+
+}
+
+inline bool DistancePointLine( XYZ *Point, XYZ *LineStart, XYZ *LineEnd, float *Distance, XYZ *Intersection )
+{
+       float LineMag;
+       float U;
+
+       LineMag = findDistance( LineEnd, LineStart );
+
+       U = ( ( ( Point->x - LineStart->x ) * ( LineEnd->x - LineStart->x ) ) +
+               ( ( Point->y - LineStart->y ) * ( LineEnd->y - LineStart->y ) ) +
+               ( ( Point->z - LineStart->z ) * ( LineEnd->z - LineStart->z ) ) ) /
+               ( LineMag * LineMag );
+
+       if( U < 0.0f || U > 1.0f )
+               return 0;   // closest point does not fall within the line segment
+
+       Intersection->x = LineStart->x + U * ( LineEnd->x - LineStart->x );
+       Intersection->y = LineStart->y + U * ( LineEnd->y - LineStart->y );
+       Intersection->z = LineStart->z + U * ( LineEnd->z - LineStart->z );
+
+       *Distance = findDistance( Point, Intersection );
+
+       return 1;
+}
+
+#endif
\ No newline at end of file
diff --git a/Source/Random.c b/Source/Random.c
new file mode 100644 (file)
index 0000000..9927bb6
--- /dev/null
@@ -0,0 +1,40 @@
+
+#include "Random.h"
+#include "stdlib.h"
+
+
+int randSeed = 1;
+
+short Random()
+{
+       /*unsigned int value = (unsigned int)randSeed;
+       unsigned int out=0;
+       int i=31;
+
+       while (i > 0)
+       {
+       value ^= 0x81010000;
+       value ^= out;
+       if (value & 1)
+       {
+       value >>= 1;
+       value |= 0x80000000;
+       }
+       else
+       value >>= 1;
+       out <<= 1;
+       out |= (value&0x1);
+       i--;
+       }
+       if (value&0x80000000)
+       {
+       out <<= 1;
+       out |= 1;
+       }
+       else
+       out <<= 1;
+
+       randSeed += out;
+       */
+       return rand();
+}
diff --git a/Source/Random.h b/Source/Random.h
new file mode 100644 (file)
index 0000000..7ab4f71
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _RANDOM_H_
+#define _RANDOM_H_
+
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+extern int randSeed;
+short Random ();
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
\ No newline at end of file
diff --git a/Source/Skeleton.cpp b/Source/Skeleton.cpp
new file mode 100644 (file)
index 0000000..3d94b91
--- /dev/null
@@ -0,0 +1,1712 @@
+/**> HEADER FILES <**/
+#include "Skeleton.h"
+
+extern float multiplier;
+extern float gravity;
+extern Skeleton testskeleton;
+extern Terrain terrain;
+extern FSOUND_SAMPLE   *samp[100];
+extern int channels[100];
+extern Objects objects;
+extern Sprites sprites;
+extern int environment;
+extern float terraindetail;
+extern float camerashake;
+extern bool freeze;
+extern int detail;
+extern XYZ envsound[30];
+extern float envsoundvol[30];
+extern int numenvsounds;
+extern float envsoundlife[30];
+extern int bonus;
+extern float bonustime;
+extern int tutoriallevel;
+
+extern int whichjointstartarray[26];
+extern int whichjointendarray[26];
+
+#include "Game.h"
+extern Game * pgame;
+extern bool visibleloading;
+extern "C"     void PlaySoundEx(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused);
+
+void dealloc2(void* param){
+       free(param);
+       param=0;
+}
+
+void Muscle::DoConstraint(bool spinny)
+{
+       static XYZ vel;
+       static XYZ midp;
+       static XYZ newpoint1,newpoint2;
+
+       static float oldlength;
+       static float relaxlength;
+
+       oldlength=length;
+
+       if(type!=boneconnect)relaxlength=findDistance(&parent1->position,&parent2->position);
+
+       if(type==boneconnect)strength=1;
+       if(type==constraint)strength=0;
+
+       if(strength<0)strength=0;
+       if(strength>1)strength=1;
+
+       length-=(length-relaxlength)*(1-strength)*multiplier*10000;
+       length-=(length-targetlength)*(strength)*multiplier*10000;
+       if(strength==0)length=relaxlength;
+
+       if((relaxlength-length>0&&relaxlength-oldlength<0)||(relaxlength-length<0&&relaxlength-oldlength>0))length=relaxlength;
+
+       //if(!broken){
+       if(length<minlength)length=minlength;
+       if(length>maxlength)length=maxlength;
+       //}
+       /*
+       if(broken){
+       if(length<minlength*.6)length=minlength*.6;
+       if(length>maxlength*1.4)length=maxlength*1.4;
+       }
+       */
+       if(length==relaxlength)return;
+
+       //Find midpoint
+       midp=(parent1->position*parent1->mass+parent2->position*parent2->mass)/(parent1->mass+parent2->mass);
+       //Find vector from midpoint to second vector
+       vel=parent2->position-midp;
+       //Change to unit vector
+       Normalise(&vel);
+       //Apply velocity change
+       newpoint1=midp-vel*length*(parent2->mass/(parent1->mass+parent2->mass));
+       newpoint2=midp+vel*length*(parent1->mass/(parent1->mass+parent2->mass));
+       if(!freeze&&spinny){
+               parent1->velocity=parent1->velocity+(newpoint1-parent1->position)/multiplier/4;
+               parent2->velocity=parent2->velocity+(newpoint2-parent2->position)/multiplier/4;
+       }
+       else
+       {
+               parent1->velocity=parent1->velocity+(newpoint1-parent1->position);
+               parent2->velocity=parent2->velocity+(newpoint2-parent2->position);
+       }
+       //Move child point to within certain distance of parent point
+       parent1->position=newpoint1;
+       parent2->position=newpoint2;
+}
+
+void Skeleton::FindForwardsfirst()
+{
+       //Find forward vectors
+       CrossProduct(joints[forwardjoints[1]].position-joints[forwardjoints[0]].position,joints[forwardjoints[2]].position-joints[forwardjoints[0]].position,&forward);
+       Normalise(&forward);
+
+       CrossProduct(joints[lowforwardjoints[1]].position-joints[lowforwardjoints[0]].position,joints[lowforwardjoints[2]].position-joints[lowforwardjoints[0]].position,&lowforward);
+       Normalise(&lowforward);
+
+       //Special forwards
+       specialforward[0]=forward;
+       specialforward[1]=forward;
+       specialforward[2]=forward;
+       specialforward[3]=forward;
+       specialforward[4]=forward;
+
+}
+void Skeleton::FindForwards()
+{
+       //Find forward vectors
+       CrossProduct(joints[forwardjoints[1]].position-joints[forwardjoints[0]].position,joints[forwardjoints[2]].position-joints[forwardjoints[0]].position,&forward);
+       Normalise(&forward);
+
+       CrossProduct(joints[lowforwardjoints[1]].position-joints[lowforwardjoints[0]].position,joints[lowforwardjoints[2]].position-joints[lowforwardjoints[0]].position,&lowforward);
+       Normalise(&lowforward);
+
+       //Special forwards
+       specialforward[0]=forward;
+
+       specialforward[1]=joints[jointlabels[rightshoulder]].position+joints[jointlabels[rightwrist]].position;
+       specialforward[1]=joints[jointlabels[rightelbow]].position-specialforward[1]/2;
+       specialforward[1]+=forward*.4;
+       Normalise(&specialforward[1]);
+       specialforward[2]=joints[jointlabels[leftshoulder]].position+joints[jointlabels[leftwrist]].position;
+       specialforward[2]=joints[jointlabels[leftelbow]].position-specialforward[2]/2;
+       specialforward[2]+=forward*.4;
+       Normalise(&specialforward[2]);
+
+       specialforward[3]=joints[jointlabels[righthip]].position+joints[jointlabels[rightankle]].position;
+       specialforward[3]=specialforward[3]/2-joints[jointlabels[rightknee]].position;
+       specialforward[3]+=lowforward*.4;
+       Normalise(&specialforward[3]);
+       specialforward[4]=joints[jointlabels[lefthip]].position+joints[jointlabels[leftankle]].position;
+       specialforward[4]=specialforward[4]/2-joints[jointlabels[leftknee]].position;
+       specialforward[4]+=lowforward*.4;
+       Normalise(&specialforward[4]);
+}
+
+float Skeleton::DoConstraints(XYZ *coords,float *scale)
+{
+       static float friction=1.5;
+       static float elasticity=.3;
+       static XYZ bounceness;
+       static XYZ oldpos[100];
+       static int numrepeats=3;
+       static float groundlevel=.15;
+       static float soundvolume;
+       static int i,j,k,l,m;
+       static XYZ temp,start,end;
+       static XYZ terrainnormal;
+       static float r=.05;
+       static float r2=.08;
+       static int whichhit;
+       //static int whichjointstart,whichjointend;
+       static float distance;
+       static float frictionness;
+       static XYZ terrainlight;
+       static int whichpatchx;
+       static int whichpatchz;
+       static float damage;
+       static bool freely;
+       static float tempmult;
+       static bool breaking;
+       breaking=0;
+
+       damage=0;
+
+       if(free){
+               freetime+=multiplier;
+
+               whichpatchx=coords->x/(terrain.size/subdivision*terrain.scale*terraindetail);
+               whichpatchz=coords->z/(terrain.size/subdivision*terrain.scale*terraindetail);
+
+               terrainlight=*coords;
+               objects.SphereCheckPossible(&terrainlight, 1);
+               /*
+               for(i=0; i<num_joints; i++){
+               oldpos[i]=joints[i].position;           
+               }*/
+
+               //Add velocity
+               for(i=0; i<num_joints; i++){
+                       //if(!isnormal(joints[i].velocity.x)||!isnormal(joints[i].velocity.y)||!isnormal(joints[i].velocity.z))joints[i].velocity=0;
+                       joints[i].position=joints[i].position+joints[i].velocity*multiplier;
+                       groundlevel=.15;
+                       if(joints[i].label==head)groundlevel=.8;        
+                       if(joints[i].label==righthand||joints[i].label==rightwrist||joints[i].label==rightelbow)groundlevel=.2; 
+                       if(joints[i].label==lefthand||joints[i].label==leftwrist||joints[i].label==leftelbow)groundlevel=.2;                    
+                       joints[i].position.y-=groundlevel;
+                       //if(!joints[i].locked&&!broken)joints[i].velocity+=joints[i].velchange*multiplier*10*(500-longdead)/500;
+                       joints[i].oldvelocity=joints[i].velocity;
+               }
+               tempmult=multiplier;
+               //multiplier/=numrepeats;
+               for(j=0; j<numrepeats; j++){
+                       if(!joints[jointlabels[rightknee]].locked&&!joints[jointlabels[righthip]].locked){
+                               temp=joints[jointlabels[rightknee]].position-(joints[jointlabels[righthip]].position+joints[jointlabels[rightankle]].position)/2;
+                               while(normaldotproduct(temp,lowforward)>-.1&&!sphere_line_intersection(&joints[jointlabels[righthip]].position,&joints[jointlabels[rightankle]].position,&joints[jointlabels[rightknee]].position,&r)){
+                                       joints[jointlabels[rightknee]].position-=lowforward*.05;
+                                       if(spinny)joints[jointlabels[rightknee]].velocity-=lowforward*.05/multiplier/4;
+                                       else joints[jointlabels[rightknee]].velocity-=lowforward*.05;
+                                       joints[jointlabels[rightankle]].position+=lowforward*.025;
+                                       if(spinny)joints[jointlabels[rightankle]].velocity+=lowforward*.025/multiplier/4;
+                                       else joints[jointlabels[rightankle]].velocity+=lowforward*.25;
+                                       joints[jointlabels[righthip]].position+=lowforward*.025;
+                                       if(spinny)joints[jointlabels[righthip]].velocity+=lowforward*.025/multiplier/4;
+                                       else joints[jointlabels[righthip]].velocity+=lowforward*.025;
+                                       temp=joints[jointlabels[rightknee]].position-(joints[jointlabels[righthip]].position+joints[jointlabels[rightankle]].position)/2;
+                               }
+                       }
+                       if(!joints[jointlabels[leftknee]].locked&&!joints[jointlabels[righthip]].locked){
+                               temp=joints[jointlabels[leftknee]].position-(joints[jointlabels[lefthip]].position+joints[jointlabels[leftankle]].position)/2;
+                               while(normaldotproduct(temp,lowforward)>-.1&&!sphere_line_intersection(&joints[jointlabels[lefthip]].position,&joints[jointlabels[leftankle]].position,&joints[jointlabels[leftknee]].position,&r)){
+                                       joints[jointlabels[leftknee]].position-=lowforward*.05;
+                                       if(spinny)joints[jointlabels[leftknee]].velocity-=lowforward*.05/multiplier/4;
+                                       else joints[jointlabels[leftknee]].velocity-=lowforward*.05;
+                                       joints[jointlabels[leftankle]].position+=lowforward*.025;
+                                       if(spinny)joints[jointlabels[leftankle]].velocity+=lowforward*.025/multiplier/4;
+                                       else joints[jointlabels[leftankle]].velocity+=lowforward*.25;
+                                       joints[jointlabels[lefthip]].position+=lowforward*.025;
+                                       if(spinny)joints[jointlabels[lefthip]].velocity+=lowforward*.025/multiplier/4;
+                                       else joints[jointlabels[lefthip]].velocity+=lowforward*.025;
+                                       temp=joints[jointlabels[leftknee]].position-(joints[jointlabels[lefthip]].position+joints[jointlabels[leftankle]].position)/2;
+                               }
+                       }
+                       /*
+                       if(terrain.patchobjectnum[whichpatchx][whichpatchz])
+                       for(m=0;m<terrain.patchobjectnum[whichpatchx][whichpatchz];m++){
+                       k=terrain.patchobjects[whichpatchx][whichpatchz][m];
+                       if(k<objects.numobjects&&k>=0)
+                       if(objects.possible[k]){
+                       temp=joints[jointlabels[head]].position*(*scale)+*coords;
+                       if(objects.model[k].SphereCheck(&temp, 0.06, &start, &objects.position[k], &objects.rotation[k])!=-1){
+                       //temp=(joints[jointlabels[head]].position*(*scale)+*coords)-start;
+                       //Normalise(&temp);
+                       //joints[jointlabels[head]].position=((temp*.2+start)-*coords)/(*scale);
+                       joints[jointlabels[head]].position=(temp-*coords)/(*scale);
+                       }
+                       }
+                       }       */
+
+
+                       //Ears check
+                       /*XYZ startheadpos;
+                       startheadpos=joints[jointlabels[head]].position;
+                       XYZ headpos;
+                       headpos=joints[jointlabels[head]].position+(joints[jointlabels[head]].position-joints[jointlabels[neck]].position);
+                       if(terrain.patchobjectnum[whichpatchx][whichpatchz])
+                       for(m=0;m<terrain.patchobjectnum[whichpatchx][whichpatchz];m++){
+                       k=terrain.patchobjects[whichpatchx][whichpatchz][m];
+                       if(k<objects.numobjects&&k>=0)
+                       if(objects.possible[k]){
+                       friction=objects.friction[k];
+                       start=joints[jointlabels[head]].position*(*scale)+*coords;
+                       end=(headpos)*(*scale)+*coords;
+                       whichhit=objects.model[k].LineCheckPossible(&start,&end,&temp,&objects.position[k],&objects.rotation[k]);
+                       if(whichhit!=-1){
+                       if(joints[jointlabels[head]].label==groin&&!joints[jointlabels[head]].locked&&joints[jointlabels[head]].delay<=0){
+                       joints[jointlabels[head]].locked=1;
+                       joints[jointlabels[head]].delay=1;
+                       static float gLoc[3];
+                       static float vel[3];
+                       gLoc[0]=headpos.x*(*scale)+coords->x;
+                       gLoc[1]=headpos.y*(*scale)+coords->y;
+                       gLoc[2]=headpos.z*(*scale)+coords->z;
+                       vel[0]=joints[jointlabels[head]].velocity.x;
+                       vel[1]=joints[jointlabels[head]].velocity.y;
+                       vel[2]=joints[jointlabels[head]].velocity.z;
+                       PlaySoundEx( landsound1, samp[landsound1], NULL, TRUE);
+                       FSOUND_3D_SetAttributes(channels[landsound1], gLoc, vel);
+                       FSOUND_SetVolume(channels[landsound1], 128);
+                       FSOUND_SetPaused(channels[landsound1], FALSE);
+
+                       breaking=1;
+                       }
+
+                       if(joints[jointlabels[head]].label==head&&!joints[jointlabels[head]].locked&&joints[jointlabels[head]].delay<=0){
+                       joints[jointlabels[head]].locked=1;
+                       joints[jointlabels[head]].delay=1;
+                       static float gLoc[3];
+                       static float vel[3];
+                       gLoc[0]=headpos.x*(*scale)+coords->x;
+                       gLoc[1]=headpos.y*(*scale)+coords->y;
+                       gLoc[2]=headpos.z*(*scale)+coords->z;
+                       vel[0]=joints[jointlabels[head]].velocity.x;
+                       vel[1]=joints[jointlabels[head]].velocity.y;
+                       vel[2]=joints[jointlabels[head]].velocity.z;
+                       PlaySoundEx( landsound2, samp[landsound2], NULL, TRUE);
+                       FSOUND_3D_SetAttributes(channels[landsound2], gLoc, vel);
+                       FSOUND_SetVolume(channels[landsound2], 128);
+                       FSOUND_SetPaused(channels[landsound2], FALSE);
+                       }
+
+                       terrainnormal=DoRotation(objects.model[k].facenormals[whichhit],0,objects.rotation[k],0)*-1;
+                       if(terrainnormal.y>.8)freefall=0;
+                       bounceness=terrainnormal*findLength(&joints[jointlabels[head]].velocity)*(abs(normaldotproduct(joints[jointlabels[head]].velocity,terrainnormal)));
+                       if(findLengthfast(&joints[jointlabels[head]].velocity)>findLengthfast(&joints[jointlabels[head]].oldvelocity)){
+                       bounceness=0;
+                       joints[jointlabels[head]].velocity=joints[jointlabels[head]].oldvelocity;
+                       }
+                       if(findLengthfast(&bounceness)>4000&&breaking){
+                       objects.model[k].MakeDecal(breakdecal,DoRotation(temp-objects.position[k],0,-objects.rotation[k],0),.4,.5,Random()%360);
+                       sprites.MakeSprite(cloudsprite, headpos*(*scale)+*coords,joints[jointlabels[head]].velocity*.06, 1,1,1, 4, .2);
+                       breaking=0;
+                       camerashake+=.6;
+
+                       static float gLoc[3];
+                       static float vel[3];
+                       gLoc[0]=headpos.x*(*scale)+coords->x;
+                       gLoc[1]=headpos.y*(*scale)+coords->y;
+                       gLoc[2]=headpos.z*(*scale)+coords->z;
+                       vel[0]=joints[jointlabels[head]].velocity.x;
+                       vel[1]=joints[jointlabels[head]].velocity.y;
+                       vel[2]=joints[jointlabels[head]].velocity.z;
+                       PlaySoundEx( breaksound2, samp[breaksound2], NULL, TRUE);
+                       FSOUND_3D_SetAttributes(channels[breaksound2], gLoc, vel);
+                       FSOUND_SetVolume(channels[breaksound2], 300);
+                       FSOUND_SetPaused(channels[breaksound2], FALSE);
+
+                       envsound[numenvsounds]=*coords;
+                       envsoundvol[numenvsounds]=64;
+                       envsoundlife[numenvsounds]=.4;
+                       numenvsounds++;
+                       }
+                       if(objects.type[k]==treetrunktype){
+                       objects.rotx[k]+=joints[jointlabels[head]].velocity.x*multiplier*.4;
+                       objects.roty[k]+=joints[jointlabels[head]].velocity.z*multiplier*.4;
+                       objects.rotx[k+1]+=joints[jointlabels[head]].velocity.x*multiplier*.4;
+                       objects.roty[k+1]+=joints[jointlabels[head]].velocity.z*multiplier*.4;
+                       }
+                       if(!joints[jointlabels[head]].locked)damage+=findLengthfast(&bounceness)/2500;
+                       ReflectVector(&joints[jointlabels[head]].velocity,&terrainnormal);
+                       frictionness=abs(normaldotproduct(joints[jointlabels[head]].velocity,terrainnormal));//findLength(&bounceness)/findLength(&joints[jointlabels[head]].velocity);
+                       joints[jointlabels[head]].velocity-=bounceness;
+                       if(1-friction*frictionness>0)joints[jointlabels[head]].velocity*=1-friction*frictionness;
+                       else joints[jointlabels[head]].velocity=0;
+                       if(findLengthfast(&bounceness)>2500){
+                       Normalise(&bounceness);
+                       bounceness=bounceness*50;
+                       }
+                       joints[jointlabels[head]].velocity+=bounceness*elasticity;
+
+
+                       if(!joints[jointlabels[head]].locked)
+                       if(findLengthfast(&joints[jointlabels[head]].velocity)<1){
+                       joints[jointlabels[head]].locked=1;
+                       //joints[jointlabels[head]].velocity*=3;
+                       }
+                       if(findLengthfast(&bounceness)>500)sprites.MakeSprite(cloudsprite, headpos*(*scale)+*coords,joints[jointlabels[head]].velocity*.06, 1,1,1, .5, .2);
+                       joints[jointlabels[head]].position=(temp-*coords)/(*scale)+(startheadpos-headpos)+terrainnormal*.005;
+                       if(longdead>100)broken=1;
+                       }
+                       }
+                       }
+                       */
+
+                       for(i=0; i<num_joints; i++){
+                               //joints[i].delay-=multiplier/1.5;
+                               if(joints[i].locked)
+                                       if(!spinny)if(findLengthfast(&joints[i].velocity)>320)joints[i].locked=0;
+                               if(spinny)if(findLengthfast(&joints[i].velocity)>600)joints[i].locked=0;
+                               if(joints[i].delay>0){
+                                       freely=1;
+                                       for(j=0;j<num_joints;j++){
+                                               if(joints[j].locked)freely=0;
+                                       }
+                                       if(freely)joints[i].delay-=multiplier*3;
+                               }
+                               //if(joints[i].delay>0)
+                               //if(findLengthfast(&joints[i].velocity)>700&&joints[i].label!=head)joints[i].delay-=multiplier;
+                       }
+
+                       if(num_muscles)
+                               for(i=0; i<num_muscles; i++){
+                                       //Length constraints
+                                       //muscles[i].DoConstraint(broken);
+                                       muscles[i].DoConstraint(spinny);
+                               }
+
+                               for(i=0; i<num_joints; i++){
+                                       //joints[i].delay-=multiplier/1.5;
+                                       //Length constraints
+                                       //Ground constraint
+                                       groundlevel=0;
+                                       if(joints[i].position.y*(*scale)+coords->y<terrain.getHeight(joints[i].position.x*(*scale)+coords->x,joints[i].position.z*(*scale)+coords->z)+groundlevel){
+                                               freefall=0;
+                                               friction=1.5;
+                                               if(joints[i].label==groin&&!joints[i].locked&&joints[i].delay<=0){
+                                                       joints[i].locked=1;
+                                                       joints[i].delay=1;
+                                                       static float gLoc[3];
+                                                       static float vel[3];
+                                                       gLoc[0]=joints[i].position.x*(*scale)+coords->x;
+                                                       gLoc[1]=joints[i].position.y*(*scale)+coords->y;
+                                                       gLoc[2]=joints[i].position.z*(*scale)+coords->z;
+                                                       vel[0]=joints[i].velocity.x;
+                                                       vel[1]=joints[i].velocity.y;
+                                                       vel[2]=joints[i].velocity.z;
+                                                       if(tutoriallevel!=1||id==0){
+                                                               PlaySoundEx( landsound1, samp[landsound1], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[landsound1], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[landsound1], 128);
+                                                               FSOUND_SetPaused(channels[landsound1], FALSE);
+                                                       }
+                                                       breaking=1;
+                                               }
+
+                                               if(joints[i].label==head&&!joints[i].locked&&joints[i].delay<=0){
+                                                       joints[i].locked=1;
+                                                       joints[i].delay=1;
+                                                       static float gLoc[3];
+                                                       static float vel[3];
+                                                       gLoc[0]=joints[i].position.x*(*scale)+coords->x;
+                                                       gLoc[1]=joints[i].position.y*(*scale)+coords->y;
+                                                       gLoc[2]=joints[i].position.z*(*scale)+coords->z;
+                                                       vel[0]=joints[i].velocity.x;
+                                                       vel[1]=joints[i].velocity.y;
+                                                       vel[2]=joints[i].velocity.z;
+                                                       if(tutoriallevel!=1||id==0){
+                                                               PlaySoundEx( landsound2, samp[landsound2], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[landsound2], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[landsound2], 128);
+                                                               FSOUND_SetPaused(channels[landsound2], FALSE);
+                                                       }
+                                               }
+
+                                               terrainnormal=terrain.getNormal(joints[i].position.x*(*scale)+coords->x,joints[i].position.z*(*scale)+coords->z);
+                                               ReflectVector(&joints[i].velocity,&terrainnormal);
+                                               bounceness=terrainnormal*findLength(&joints[i].velocity)*(abs(normaldotproduct(joints[i].velocity,terrainnormal)));
+                                               if(!joints[i].locked)damage+=findLengthfast(&bounceness)/4000;
+                                               if(findLengthfast(&joints[i].velocity)<findLengthfast(&bounceness))bounceness=0;
+                                               frictionness=abs(normaldotproduct(joints[i].velocity,terrainnormal));//findLength(&bounceness)/findLength(&joints[i].velocity);
+                                               joints[i].velocity-=bounceness;
+                                               if(1-friction*frictionness>0)joints[i].velocity*=1-friction*frictionness;
+                                               else joints[i].velocity=0;
+
+                                               if(tutoriallevel!=1||id==0)
+                                                       if(findLengthfast(&bounceness)>8000&&breaking){
+                                                               objects.model[k].MakeDecal(breakdecal,DoRotation(temp-objects.position[k],0,-objects.rotation[k],0),.4,.5,Random()%360);
+                                                               sprites.MakeSprite(cloudsprite, joints[i].position*(*scale)+*coords,joints[i].velocity*.06, 1,1,1, 4, .2);
+                                                               //sprites.MakeSprite(cloudsprite, joints[i].position*(*scale)+*coords,joints[i].velocity*.06, 1,1,1, 1, .2);
+                                                               breaking=0;
+                                                               camerashake+=.6;
+
+                                                               static float gLoc[3];
+                                                               static float vel[3];
+                                                               gLoc[0]=joints[i].position.x*(*scale)+coords->x;
+                                                               gLoc[1]=joints[i].position.y*(*scale)+coords->y;
+                                                               gLoc[2]=joints[i].position.z*(*scale)+coords->z;
+                                                               vel[0]=joints[i].velocity.x;
+                                                               vel[1]=joints[i].velocity.y;
+                                                               vel[2]=joints[i].velocity.z;
+                                                               PlaySoundEx( breaksound2, samp[breaksound2], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[breaksound2], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[breaksound2], 300);
+                                                               FSOUND_SetPaused(channels[breaksound2], FALSE);
+
+                                                               envsound[numenvsounds]=*coords;
+                                                               envsoundvol[numenvsounds]=64;
+                                                               envsoundlife[numenvsounds]=.4;
+                                                               numenvsounds++;
+                                                       }
+
+                                                       if(findLengthfast(&bounceness)>2500){
+                                                               Normalise(&bounceness);
+                                                               bounceness=bounceness*50;
+                                                       }       
+
+                                                       joints[i].velocity+=bounceness*elasticity;
+
+                                                       if(findLengthfast(&joints[i].velocity)>findLengthfast(&joints[i].oldvelocity)){
+                                                               bounceness=0;
+                                                               joints[i].velocity=joints[i].oldvelocity;
+                                                       }
+
+
+                                                       if(joints[i].locked==0)
+                                                               if(findLengthfast(&joints[i].velocity)<1)joints[i].locked=1;
+
+                                                       if(environment==snowyenvironment&&findLengthfast(&bounceness)>500&&terrain.getOpacity(joints[i].position.x*(*scale)+coords->x,joints[i].position.z*(*scale)+coords->z)<.2){
+                                                               terrainlight=terrain.getLighting(joints[i].position.x*(*scale)+coords->x,joints[i].position.z*(*scale)+coords->z);
+                                                               sprites.MakeSprite(cloudsprite, joints[i].position*(*scale)+*coords,joints[i].velocity*.06, terrainlight.x,terrainlight.y,terrainlight.z, .5, .7);
+                                                               if(detail==2)terrain.MakeDecal(bodyprintdecal, joints[i].position*(*scale)+*coords,.4,.4,0);
+                                                       }
+                                                       else if(environment==desertenvironment&&findLengthfast(&bounceness)>500&&terrain.getOpacity(joints[i].position.x*(*scale)+coords->x,joints[i].position.z*(*scale)+coords->z)<.2){
+                                                               terrainlight=terrain.getLighting(joints[i].position.x*(*scale)+coords->x,joints[i].position.z*(*scale)+coords->z);
+                                                               sprites.MakeSprite(cloudsprite, joints[i].position*(*scale)+*coords,joints[i].velocity*.06, terrainlight.x*190/255,terrainlight.y*170/255,terrainlight.z*108/255, .5, .7);
+                                                       }
+
+                                                       else if(environment==grassyenvironment&&findLengthfast(&bounceness)>500&&terrain.getOpacity(joints[i].position.x*(*scale)+coords->x,joints[i].position.z*(*scale)+coords->z)<.2){
+                                                               terrainlight=terrain.getLighting(joints[i].position.x*(*scale)+coords->x,joints[i].position.z*(*scale)+coords->z);
+                                                               sprites.MakeSprite(cloudsprite, joints[i].position*(*scale)+*coords,joints[i].velocity*.06, terrainlight.x*90/255,terrainlight.y*70/255,terrainlight.z*8/255, .5, .5);
+                                                       }
+                                                       else if(findLengthfast(&bounceness)>500)sprites.MakeSprite(cloudsprite, joints[i].position*(*scale)+*coords,joints[i].velocity*.06, terrainlight.x,terrainlight.y,terrainlight.z, .5, .2);
+
+
+                                                       joints[i].position.y=(terrain.getHeight(joints[i].position.x*(*scale)+coords->x,joints[i].position.z*(*scale)+coords->z)+groundlevel-coords->y)/(*scale);
+                                                       if(longdead>100)broken=1;
+                                       }
+                                       if(terrain.patchobjectnum[whichpatchx][whichpatchz])
+                                               for(m=0;m<terrain.patchobjectnum[whichpatchx][whichpatchz];m++){
+                                                       k=terrain.patchobjects[whichpatchx][whichpatchz][m];
+                                                       if(k<objects.numobjects&&k>=0)
+                                                               if(objects.possible[k]){
+                                                                       friction=objects.friction[k];
+                                                                       start=joints[i].realoldposition;
+                                                                       end=joints[i].position*(*scale)+*coords;
+                                                                       whichhit=objects.model[k].LineCheckPossible(&start,&end,&temp,&objects.position[k],&objects.rotation[k]);
+                                                                       if(whichhit!=-1){
+                                                                               if(joints[i].label==groin&&!joints[i].locked&&joints[i].delay<=0){
+                                                                                       joints[i].locked=1;
+                                                                                       joints[i].delay=1;
+                                                                                       static float gLoc[3];
+                                                                                       static float vel[3];
+                                                                                       gLoc[0]=joints[i].position.x*(*scale)+coords->x;
+                                                                                       gLoc[1]=joints[i].position.y*(*scale)+coords->y;
+                                                                                       gLoc[2]=joints[i].position.z*(*scale)+coords->z;
+                                                                                       vel[0]=joints[i].velocity.x;
+                                                                                       vel[1]=joints[i].velocity.y;
+                                                                                       vel[2]=joints[i].velocity.z;
+                                                                                       if(tutoriallevel!=1||id==0){
+                                                                                               PlaySoundEx( landsound1, samp[landsound1], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[landsound1], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[landsound1], 128);
+                                                                                               FSOUND_SetPaused(channels[landsound1], FALSE);
+                                                                                       }
+                                                                                       breaking=1;
+                                                                               }
+
+                                                                               if(joints[i].label==head&&!joints[i].locked&&joints[i].delay<=0){
+                                                                                       joints[i].locked=1;
+                                                                                       joints[i].delay=1;
+                                                                                       static float gLoc[3];
+                                                                                       static float vel[3];
+                                                                                       gLoc[0]=joints[i].position.x*(*scale)+coords->x;
+                                                                                       gLoc[1]=joints[i].position.y*(*scale)+coords->y;
+                                                                                       gLoc[2]=joints[i].position.z*(*scale)+coords->z;
+                                                                                       vel[0]=joints[i].velocity.x;
+                                                                                       vel[1]=joints[i].velocity.y;
+                                                                                       vel[2]=joints[i].velocity.z;
+                                                                                       if(tutoriallevel!=1||id==0){
+                                                                                               PlaySoundEx( landsound2, samp[landsound2], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[landsound2], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[landsound2], 128);
+                                                                                               FSOUND_SetPaused(channels[landsound2], FALSE);
+                                                                                       }
+                                                                               }
+
+                                                                               terrainnormal=DoRotation(objects.model[k].facenormals[whichhit],0,objects.rotation[k],0)*-1;
+                                                                               if(terrainnormal.y>.8)freefall=0;
+                                                                               bounceness=terrainnormal*findLength(&joints[i].velocity)*(abs(normaldotproduct(joints[i].velocity,terrainnormal)));
+                                                                               if(findLengthfast(&joints[i].velocity)>findLengthfast(&joints[i].oldvelocity)){
+                                                                                       bounceness=0;
+                                                                                       joints[i].velocity=joints[i].oldvelocity;
+                                                                               }
+                                                                               if(tutoriallevel!=1||id==0)
+                                                                                       if(findLengthfast(&bounceness)>4000&&breaking){
+                                                                                               objects.model[k].MakeDecal(breakdecal,DoRotation(temp-objects.position[k],0,-objects.rotation[k],0),.4,.5,Random()%360);
+                                                                                               sprites.MakeSprite(cloudsprite, joints[i].position*(*scale)+*coords,joints[i].velocity*.06, 1,1,1, 4, .2);
+                                                                                               breaking=0;
+                                                                                               camerashake+=.6;
+
+                                                                                               static float gLoc[3];
+                                                                                               static float vel[3];
+                                                                                               gLoc[0]=joints[i].position.x*(*scale)+coords->x;
+                                                                                               gLoc[1]=joints[i].position.y*(*scale)+coords->y;
+                                                                                               gLoc[2]=joints[i].position.z*(*scale)+coords->z;
+                                                                                               vel[0]=joints[i].velocity.x;
+                                                                                               vel[1]=joints[i].velocity.y;
+                                                                                               vel[2]=joints[i].velocity.z;
+                                                                                               PlaySoundEx( breaksound2, samp[breaksound2], NULL, TRUE);
+                                                                                               FSOUND_3D_SetAttributes(channels[breaksound2], gLoc, vel);
+                                                                                               FSOUND_SetVolume(channels[breaksound2], 300);
+                                                                                               FSOUND_SetPaused(channels[breaksound2], FALSE);
+
+                                                                                               envsound[numenvsounds]=*coords;
+                                                                                               envsoundvol[numenvsounds]=64;
+                                                                                               envsoundlife[numenvsounds]=.4;
+                                                                                               numenvsounds++;
+                                                                                       }
+                                                                                       if(objects.type[k]==treetrunktype){
+                                                                                               //if(objects.rotx[k]==0||objects.roty[k]==0){
+                                                                                               /*int howmany;
+                                                                                               XYZ tempvel;
+                                                                                               XYZ pos;
+                                                                                               if(environment==grassyenvironment)howmany=findLength(&joints[i].velocity)*4/10;
+                                                                                               if(environment==snowyenvironment)howmany=findLength(&joints[i].velocity)*1/10;
+                                                                                               if(environment!=desertenvironment)
+                                                                                               for(j=0;j<howmany;j++){
+                                                                                               tempvel.x=float(abs(Random()%100)-50)/20;
+                                                                                               tempvel.y=float(abs(Random()%100)-50)/20;
+                                                                                               tempvel.z=float(abs(Random()%100)-50)/20;
+                                                                                               pos=objects.position[k];
+                                                                                               pos.y+=objects.scale[k]*15;
+                                                                                               pos.x+=float(abs(Random()%100)-50)/100*objects.scale[k]*5;
+                                                                                               pos.y+=float(abs(Random()%100)-50)/100*objects.scale[k]*15;
+                                                                                               pos.z+=float(abs(Random()%100)-50)/100*objects.scale[k]*5;
+                                                                                               sprites.MakeSprite(splintersprite, pos,tempvel*.5, 165/255+float(abs(Random()%100)-50)/400,0,0, .2+float(abs(Random()%100)-50)/1300, 1);
+                                                                                               sprites.special[sprites.numsprites-1]=1;
+                                                                                               }*/
+                                                                                               objects.rotx[k]+=joints[i].velocity.x*multiplier*.4;
+                                                                                               objects.roty[k]+=joints[i].velocity.z*multiplier*.4;
+                                                                                               objects.rotx[k+1]+=joints[i].velocity.x*multiplier*.4;
+                                                                                               objects.roty[k+1]+=joints[i].velocity.z*multiplier*.4;
+                                                                                       }
+                                                                                       if(!joints[i].locked)damage+=findLengthfast(&bounceness)/2500;
+                                                                                       ReflectVector(&joints[i].velocity,&terrainnormal);
+                                                                                       frictionness=abs(normaldotproduct(joints[i].velocity,terrainnormal));//findLength(&bounceness)/findLength(&joints[i].velocity);
+                                                                                       joints[i].velocity-=bounceness;
+                                                                                       if(1-friction*frictionness>0)joints[i].velocity*=1-friction*frictionness;
+                                                                                       else joints[i].velocity=0;
+                                                                                       if(findLengthfast(&bounceness)>2500){
+                                                                                               Normalise(&bounceness);
+                                                                                               bounceness=bounceness*50;
+                                                                                       }
+                                                                                       joints[i].velocity+=bounceness*elasticity;
+
+
+                                                                                       if(!joints[i].locked)
+                                                                                               if(findLengthfast(&joints[i].velocity)<1){
+                                                                                                       joints[i].locked=1;
+                                                                                                       //joints[i].velocity*=3;
+                                                                                               }
+                                                                                               if(findLengthfast(&bounceness)>500)sprites.MakeSprite(cloudsprite, joints[i].position*(*scale)+*coords,joints[i].velocity*.06, 1,1,1, .5, .2);
+                                                                                               joints[i].position=(temp-*coords)/(*scale)+terrainnormal*.005;
+                                                                                               if(longdead>100)broken=1;
+                                                                       }
+                                                               }
+                                               }
+                                               joints[i].realoldposition=joints[i].position*(*scale)+*coords;
+                               }
+               }
+               multiplier=tempmult;
+
+
+               if(terrain.patchobjectnum[whichpatchx][whichpatchz])
+                       for(m=0;m<terrain.patchobjectnum[whichpatchx][whichpatchz];m++){
+                               k=terrain.patchobjects[whichpatchx][whichpatchz][m];
+                               if(objects.possible[k]){
+                                       for(i=0;i<26;i++){
+                                               //Make this less stupid
+                                               start=joints[jointlabels[whichjointstartarray[i]]].position*(*scale)+*coords;
+                                               end=joints[jointlabels[whichjointendarray[i]]].position*(*scale)+*coords;
+                                               whichhit=objects.model[k].LineCheckSlidePossible(&start,&end,&temp,&objects.position[k],&objects.rotation[k]);
+                                               if(whichhit!=-1){
+                                                       joints[jointlabels[whichjointendarray[i]]].position=(end-*coords)/(*scale);
+                                                       for(j=0; j<num_muscles; j++){
+                                                               if((muscles[j].parent1->label==whichjointstartarray[i]&&muscles[j].parent2->label==whichjointendarray[i])||(muscles[j].parent2->label==whichjointstartarray[i]&&muscles[j].parent1->label==whichjointendarray[i]))
+                                                                       muscles[j].DoConstraint(spinny);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       for(i=0; i<num_joints; i++){
+                               groundlevel=.15;
+                               if(joints[i].label==head)groundlevel=.8;        
+                               if(joints[i].label==righthand||joints[i].label==rightwrist||joints[i].label==rightelbow)groundlevel=.2; 
+                               if(joints[i].label==lefthand||joints[i].label==leftwrist||joints[i].label==leftelbow)groundlevel=.2;                    
+                               joints[i].position.y+=groundlevel;
+                               joints[i].mass=1;
+                               if(joints[i].label==lefthip||joints[i].label==leftknee||joints[i].label==leftankle||joints[i].label==righthip||joints[i].label==rightknee||joints[i].label==rightankle)joints[i].mass=2;
+                               if(joints[i].locked){
+                                       joints[i].mass=4;
+                               }
+                       }
+
+                       return damage;
+       }
+       if(!free){
+               for(i=0; i<num_muscles; i++){
+                       if(muscles[i].type==boneconnect)
+                               muscles[i].DoConstraint(0);
+               }
+       }
+       return 0;
+}
+
+void Skeleton::DoGravity(float *scale)
+{
+       static int i;
+       for(i=0; i<num_joints; i++){
+               if(((joints[i].label!=leftknee&&joints[i].label!=rightknee)||lowforward.y>-.1||joints[i].mass<5)&&((joints[i].label!=rightelbow&&joints[i].label!=rightelbow)||forward.y<.3))joints[i].velocity.y+=gravity*multiplier/(*scale);
+       }
+}
+
+void Skeleton::Draw(int  muscleview)
+{
+       static float jointcolor[4];
+
+       if(muscleview!=2){
+               jointcolor[0]=0;
+               jointcolor[1]=0;
+               jointcolor[2]=.5;
+               jointcolor[3]=1;
+       }
+
+       if(muscleview==2){
+               jointcolor[0]=0;
+               jointcolor[1]=0;
+               jointcolor[2]=0;
+               jointcolor[3]=.5;
+       }
+       //Calc motionblur-ness
+       for(int i=0; i<num_joints; i++){
+               joints[i].oldposition=joints[i].position;
+               joints[i].blurred=findDistance(&joints[i].position,&joints[i].oldposition)*100;
+               if(joints[i].blurred<1)joints[i].blurred=1;
+       }
+
+       //Do Motionblur
+       glDepthMask(0);
+       glEnable(GL_BLEND);
+       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+       glBegin(GL_QUADS);
+       for(int i=0; i<num_joints; i++){
+               if(joints[i].hasparent){
+                       glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/joints[i].blurred);
+                       glVertex3f(joints[i].position.x,joints[i].position.y,joints[i].position.z);
+                       glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/joints[i].parent->blurred);
+                       glVertex3f(joints[i].parent->position.x,joints[i].parent->position.y,joints[i].parent->position.z);
+                       glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/joints[i].parent->blurred);
+                       glVertex3f(joints[i].parent->oldposition.x,joints[i].parent->oldposition.y,joints[i].parent->oldposition.z);
+                       glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/joints[i].blurred);
+                       glVertex3f(joints[i].oldposition.x,joints[i].oldposition.y,joints[i].oldposition.z);
+               }
+       }
+       for(int i=0; i<num_muscles; i++){
+               if(muscles[i].type==boneconnect){
+                       glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/muscles[i].parent2->blurred);
+                       glVertex3f(muscles[i].parent1->position.x,muscles[i].parent1->position.y,muscles[i].parent1->position.z);
+                       glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/muscles[i].parent2->blurred);
+                       glVertex3f(muscles[i].parent2->position.x,muscles[i].parent2->position.y,muscles[i].parent2->position.z);
+                       glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/muscles[i].parent2->blurred);
+                       glVertex3f(muscles[i].parent2->oldposition.x,muscles[i].parent2->oldposition.y,muscles[i].parent2->oldposition.z);
+                       glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/muscles[i].parent1->blurred);
+                       glVertex3f(muscles[i].parent1->oldposition.x,muscles[i].parent1->oldposition.y,muscles[i].parent1->oldposition.z);
+               }
+       }
+       glEnd();
+
+       glBegin(GL_LINES);
+       for(int i=0; i<num_joints; i++){
+               if(joints[i].hasparent){
+                       glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/joints[i].blurred);
+                       glVertex3f(joints[i].position.x,joints[i].position.y,joints[i].position.z);
+                       glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/joints[i].parent->blurred);
+                       glVertex3f(joints[i].parent->position.x,joints[i].parent->position.y,joints[i].parent->position.z);
+               }
+       }
+       /*for(int i=0; i<num_joints; i++){
+       if(joints[i].hasparent){
+       glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],1);
+       glVertex3f(joints[i].position.x,joints[i].position.y,joints[i].position.z);
+       glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],1);
+       glVertex3f(joints[i].position.x+forward.x,joints[i].position.y+forward.y,joints[i].position.z+forward.z);
+       }
+       }*/
+       for(int i=0; i<num_muscles; i++){
+               if(muscles[i].type==boneconnect){
+                       glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/muscles[i].parent1->blurred);
+                       glVertex3f(muscles[i].parent1->position.x,muscles[i].parent1->position.y,muscles[i].parent1->position.z);
+                       glColor4f(jointcolor[0],jointcolor[1],jointcolor[2],jointcolor[3]/muscles[i].parent2->blurred);
+                       glVertex3f(muscles[i].parent2->position.x,muscles[i].parent2->position.y,muscles[i].parent2->position.z);
+               }
+       }
+       glColor3f(.6,.6,0);
+       if(muscleview==1)
+               for(int i=0; i<num_muscles; i++){
+                       if(muscles[i].type!=boneconnect){
+                               glVertex3f(muscles[i].parent1->position.x,muscles[i].parent1->position.y,muscles[i].parent1->position.z);
+                               glVertex3f(muscles[i].parent2->position.x,muscles[i].parent2->position.y,muscles[i].parent2->position.z);
+                       }
+               }       
+               glEnd();
+
+               if(muscleview!=2){
+                       glPointSize(3);
+                       glBegin(GL_POINTS);
+                       for(int i=0; i<num_joints; i++){
+                               if(i!=selected)glColor4f(0,0,.5,1);
+                               if(i==selected)glColor4f(1,1,0,1);
+                               if(joints[i].locked&&i!=selected)glColor4f(1,0,0,1);
+                               glVertex3f(joints[i].position.x,joints[i].position.y,joints[i].position.z);
+                       }
+                       glEnd();
+               }
+
+               //Set old position to current position
+               if(muscleview==2)
+                       for(int i=0; i<num_joints; i++){
+                               joints[i].oldposition=joints[i].position;
+                       }
+                       glDepthMask(1);
+}
+
+void Skeleton::AddJoint(float x, float y, float z, int which)
+{
+       if(num_joints<max_joints-1){
+               joints[num_joints].velocity=0;
+               joints[num_joints].position.x=x;
+               joints[num_joints].position.y=y;
+               joints[num_joints].position.z=z;
+               joints[num_joints].mass=1;
+               joints[num_joints].locked=0;
+
+               /*if(which>=num_joints||which<0)*/joints[num_joints].hasparent=0;
+               /*if(which<num_joints&&which>=0){
+               joints[num_joints].parent=&joints[which];
+               joints[num_joints].hasparent=1;
+               joints[num_joints].length=findDistance(joints[num_joints].position,joints[num_joints].parent->position);
+               }*/
+               num_joints++;
+               if(which<num_joints&&which>=0)AddMuscle(num_joints-1,which,0,10,boneconnect);
+       }
+}
+
+void Skeleton::DeleteJoint(int whichjoint)
+{
+       if(whichjoint<num_joints&&whichjoint>=0){
+               joints[whichjoint].velocity=joints[num_joints-1].velocity;
+               joints[whichjoint].position=joints[num_joints-1].position;
+               joints[whichjoint].oldposition=joints[num_joints-1].oldposition;
+               joints[whichjoint].hasparent=joints[num_joints-1].hasparent;
+               joints[whichjoint].parent=joints[num_joints-1].parent;
+               joints[whichjoint].length=joints[num_joints-1].length;
+               joints[whichjoint].locked=joints[num_joints-1].locked;
+               joints[whichjoint].modelnum=joints[num_joints-1].modelnum;
+               joints[whichjoint].visible=joints[num_joints-1].visible;
+
+               for(int i=0;i<num_muscles;i++){
+                       while(muscles[i].parent1==&joints[whichjoint]&&i<num_muscles)DeleteMuscle(i);
+                       while(muscles[i].parent2==&joints[whichjoint]&&i<num_muscles)DeleteMuscle(i);
+               }
+               for(int i=0;i<num_muscles;i++){
+                       while(muscles[i].parent1==&joints[num_joints-1]&&i<num_muscles)muscles[i].parent1=&joints[whichjoint];
+                       while(muscles[i].parent2==&joints[num_joints-1]&&i<num_muscles)muscles[i].parent2=&joints[whichjoint];
+               }
+               for(int i=0;i<num_joints;i++){
+                       if(joints[i].parent==&joints[whichjoint])joints[i].hasparent=0;
+               }
+               for(int i=0;i<num_joints;i++){
+                       if(joints[i].parent==&joints[num_joints-1])joints[i].parent=&joints[whichjoint];
+               }
+
+               num_joints--;
+       }
+}
+
+void Skeleton::DeleteMuscle(int whichmuscle)
+{
+       if(whichmuscle<num_muscles){
+               muscles[whichmuscle].minlength=muscles[num_muscles-1].minlength;
+               muscles[whichmuscle].maxlength=muscles[num_muscles-1].maxlength;
+               muscles[whichmuscle].strength=muscles[num_muscles-1].strength;
+               muscles[whichmuscle].parent1=muscles[num_muscles-1].parent1;
+               muscles[whichmuscle].parent2=muscles[num_muscles-1].parent2;
+               muscles[whichmuscle].length=muscles[num_muscles-1].length;
+               muscles[whichmuscle].visible=muscles[num_muscles-1].visible;
+               muscles[whichmuscle].type=muscles[num_muscles-1].type;
+               muscles[whichmuscle].targetlength=muscles[num_muscles-1].targetlength;
+
+               num_muscles--;
+       }
+}
+
+void Skeleton::SetJoint(float x, float y, float z, int which, int whichjoint)
+{
+       if(whichjoint<num_joints){
+               joints[whichjoint].velocity=0;
+               joints[whichjoint].position.x=x;
+               joints[whichjoint].position.y=y;
+               joints[whichjoint].position.z=z;
+
+               if(which>=num_joints||which<0)joints[whichjoint].hasparent=0;
+               if(which<num_joints&&which>=0){
+                       joints[whichjoint].parent=&joints[which];
+                       joints[whichjoint].hasparent=1;
+                       joints[whichjoint].length=findDistance(&joints[whichjoint].position,&joints[whichjoint].parent->position);
+               }       
+       }
+}
+
+void Skeleton::AddMuscle(int attach1,int attach2,float minlength,float maxlength,int type)
+{
+       if(num_muscles<max_muscles-1&&attach1<num_joints&&attach1>=0&&attach2<num_joints&&attach2>=0&&attach1!=attach2){
+               muscles[num_muscles].parent1=&joints[attach1];
+               muscles[num_muscles].parent2=&joints[attach2];
+               muscles[num_muscles].length=findDistance(&muscles[num_muscles].parent1->position,&muscles[num_muscles].parent2->position);
+               muscles[num_muscles].targetlength=findDistance(&muscles[num_muscles].parent1->position,&muscles[num_muscles].parent2->position);
+               muscles[num_muscles].strength=.7;
+               muscles[num_muscles].type=type;
+               muscles[num_muscles].minlength=minlength;
+               muscles[num_muscles].maxlength=maxlength;
+
+               num_muscles++;
+       }
+}
+
+void Skeleton::MusclesSet()
+{
+       for(int i=0;i<num_muscles;i++){
+               muscles[i].length=findDistance(&muscles[i].parent1->position,&muscles[i].parent2->position);
+       }
+}
+
+void Skeleton::DoBalance()
+{
+       /*XYZ newpoint;
+       newpoint=joints[0].position;
+       newpoint.x=(joints[2].position.x+joints[4].position.x)/2;
+       newpoint.z=(joints[2].position.z+joints[4].position.z)/2;
+       joints[0].velocity=joints[0].velocity+(newpoint-joints[0].position);
+       //Move child point to within certain distance of parent point
+       joints[0].position=newpoint;
+
+       MusclesSet();*/
+}
+
+void Skeleton::FindRotationMuscle(int which, int animation)
+{
+       static XYZ temppoint1,temppoint2,tempforward;
+       static float distance;
+
+       temppoint1=muscles[which].parent1->position;
+       temppoint2=muscles[which].parent2->position;
+       distance=sqrt((temppoint1.x-temppoint2.x)*(temppoint1.x-temppoint2.x)+(temppoint1.y-temppoint2.y)*(temppoint1.y-temppoint2.y)+(temppoint1.z-temppoint2.z)*(temppoint1.z-temppoint2.z));
+       if((temppoint1.y-temppoint2.y)<=distance)muscles[which].rotate2=asin((temppoint1.y-temppoint2.y)/distance);
+       if((temppoint1.y-temppoint2.y)>distance)muscles[which].rotate2=asin(1.f);
+       muscles[which].rotate2*=360/6.28;
+       temppoint1.y=0;
+       temppoint2.y=0;
+       distance=sqrt((temppoint1.x-temppoint2.x)*(temppoint1.x-temppoint2.x)+(temppoint1.y-temppoint2.y)*(temppoint1.y-temppoint2.y)+(temppoint1.z-temppoint2.z)*(temppoint1.z-temppoint2.z));
+       if((temppoint1.z-temppoint2.z)<=distance)muscles[which].rotate1=acos((temppoint1.z-temppoint2.z)/distance);
+       if((temppoint1.z-temppoint2.z)>distance)muscles[which].rotate1=acos(1.f);
+       muscles[which].rotate1*=360/6.28;
+       if(temppoint1.x>temppoint2.x)muscles[which].rotate1=360-muscles[which].rotate1;
+       if(!isnormal(muscles[which].rotate1))muscles[which].rotate1=0;
+       if(!isnormal(muscles[which].rotate2))muscles[which].rotate2=0;
+
+       if(muscles[which].parent1->label==head)tempforward=specialforward[0];
+       else if(muscles[which].parent1->label==rightshoulder||muscles[which].parent1->label==rightelbow||muscles[which].parent1->label==rightwrist||muscles[which].parent1->label==righthand)tempforward=specialforward[1];
+       else if(muscles[which].parent1->label==leftshoulder||muscles[which].parent1->label==leftelbow||muscles[which].parent1->label==leftwrist||muscles[which].parent1->label==lefthand)tempforward=specialforward[2];
+       else if(muscles[which].parent1->label==righthip||muscles[which].parent1->label==rightknee||muscles[which].parent1->label==rightankle||muscles[which].parent1->label==rightfoot)tempforward=specialforward[3];
+       else if(muscles[which].parent1->label==lefthip||muscles[which].parent1->label==leftknee||muscles[which].parent1->label==leftankle||muscles[which].parent1->label==leftfoot)tempforward=specialforward[4];
+       else if(!muscles[which].parent1->lower)tempforward=forward;
+       else if(muscles[which].parent1->lower)tempforward=lowforward;
+
+       if(animation==hanganim){
+               if(muscles[which].parent1->label==righthand||muscles[which].parent2->label==righthand){
+                       tempforward=0;
+                       tempforward.x=-1;
+               }
+               if(muscles[which].parent1->label==lefthand||muscles[which].parent2->label==lefthand){
+                       tempforward=0;
+                       tempforward.x=1;
+               }
+       }
+
+       if(free==0){
+               if(muscles[which].parent1->label==rightfoot||muscles[which].parent2->label==rightfoot){
+                       tempforward.y-=.3;
+               }
+               if(muscles[which].parent1->label==leftfoot||muscles[which].parent2->label==leftfoot){
+                       tempforward.y-=.3;
+               }
+       }
+
+
+       tempforward=DoRotation(tempforward,0,muscles[which].rotate1-90,0);
+       tempforward=DoRotation(tempforward,0,0,muscles[which].rotate2-90);
+       tempforward.y=0;
+       tempforward/=sqrt(tempforward.x*tempforward.x+tempforward.y*tempforward.y+tempforward.z*tempforward.z);
+       if(tempforward.z<=1&&tempforward.z>=-1)muscles[which].rotate3=acos(0-tempforward.z);
+       else muscles[which].rotate3=acos(-1.f);
+       muscles[which].rotate3*=360/6.28;
+       if(0>tempforward.x)muscles[which].rotate3=360-muscles[which].rotate3;
+       if(!isnormal(muscles[which].rotate3))muscles[which].rotate3=0;
+}
+
+void Animation::Load(char *filename, int aheight, int aattack)
+{
+       static FILE *tfile;
+       static int i,j;
+       static XYZ startoffset,endoffset;
+       static int howmany;
+
+       LOGFUNC;
+
+       LOG(std::string("Loading animation...") + filename);
+
+       deallocate();
+
+       height=aheight;
+       attack=aattack;
+
+       if(visibleloading)pgame->LoadingScreen();
+
+       tfile=fopen( filename, "rb" );
+       if(tfile){
+               funpackf(tfile, "Bi Bi", &numframes, &joints);
+               /*
+               for(i = 0; i < joints; i++){
+               if(position[i])dealloc2(position[i]);
+               if(twist[i])dealloc2(twist[i]);
+               if(twist2[i])dealloc2(twist2[i]);
+               if(onground[i])dealloc2(onground[i]);
+               }*/
+               /*
+               if(position)dealloc2(position);
+               if(twist)dealloc2(twist);
+               if(twist2)dealloc2(twist2);
+               if(speed)dealloc2(speed);
+               if(onground)dealloc2(onground);
+               if(forward)dealloc2(forward);
+               if(weapontarget)dealloc2(weapontarget);
+               if(label)dealloc2(label);*/
+
+               position=(XYZ**)malloc(sizeof(XYZ*)*joints);
+               for(i = 0; i < joints; i++)
+                       position[i] = (XYZ*)malloc(sizeof(XYZ)*numframes);
+
+               twist=(float**)malloc(sizeof(float*)*joints);
+               for(i = 0; i < joints; i++)
+                       twist[i] = (float*)malloc(sizeof(float)*numframes);
+
+               twist2=(float**)malloc(sizeof(float*)*joints);
+               for(i = 0; i < joints; i++)
+                       twist2[i] = (float*)malloc(sizeof(float)*numframes);
+
+               speed = (float*)malloc(sizeof(float)*numframes);
+
+               onground=(bool**)malloc(sizeof(bool*)*joints);
+               for(i = 0; i < joints; i++)
+                       onground[i] =(bool*)malloc(sizeof(bool)*numframes);
+
+               forward = (XYZ*)malloc(sizeof(XYZ)*numframes);
+               weapontarget = (XYZ*)malloc(sizeof(XYZ)*numframes);
+               label = (int*)malloc(sizeof(int)*numframes);
+
+               /*position = new XYZ[joints][numframes];
+               twist = new float[joints][numframes];
+               twist2 = new float[joints][numframes];
+               speed = new float[numframes];
+               onground = new bool[joints][numframes];
+               forward = new XYZ[numframes];
+               label = new int[numframes];*/
+
+               for(i=0;i<numframes;i++){
+                       for(j=0;j<joints;j++){
+                               funpackf(tfile, "Bf Bf Bf", &position[j][i].x,&position[j][i].y,&position[j][i].z);
+                       }
+                       for(j=0;j<joints;j++){
+                               funpackf(tfile, "Bf", &twist[j][i]);
+                       }
+                       for(j=0;j<joints;j++){
+                               funpackf(tfile, "Bb", &onground[j][i]);
+                       }
+                       funpackf(tfile, "Bf", &speed[i]);
+               }
+               for(i=0;i<numframes;i++){
+                       for(j=0;j<joints;j++){
+                               funpackf(tfile, "Bf", &twist2[j][i]);
+                       }
+               }
+               for(i=0;i<numframes;i++){
+                       funpackf(tfile, "Bf", &label[i]);
+               }
+               funpackf(tfile, "Bi", &weapontargetnum);
+               for(i=0;i<numframes;i++){
+                       funpackf(tfile, "Bf Bf Bf", &weapontarget[i].x,&weapontarget[i].y,&weapontarget[i].z);
+               }
+
+               fclose(tfile);  
+       }
+
+       startoffset=0;
+       endoffset=0;
+       howmany=0;
+       for(j=0;j<joints;j++){
+               if(position[j][0].y<1)
+                       startoffset+=position[j][0];
+               if(position[j][numframes-1].y<1)
+                       endoffset+=position[j][numframes-1];
+               howmany++;
+       }
+       startoffset/=howmany;
+       endoffset/=howmany;
+       offset=endoffset;
+       offset.y=0;
+}
+
+
+void Animation::Move(XYZ how)
+{
+       static int i,j,joints;
+       for(i=0;i<numframes;i++){
+               for(j=0;j<joints;j++){
+                       position[j][i]=0;
+               }
+       }
+}
+
+void Skeleton::Load(char *filename,char *lowfilename,char *clothesfilename, char *modelfilename, char *model2filename, char *model3filename, char *model4filename, char *model5filename, char *model6filename, char *model7filename, char *modellowfilename, char *modelclothesfilename, bool aclothes)
+{
+       static GLfloat M[16];
+       static int parentID;
+       static FILE *tfile;
+       static float lSize;
+       static int i,j,tempmuscle;
+       int newload;
+       int edit;
+
+       LOGFUNC;
+
+       newload=0;
+
+       num_models=7;
+
+       clothes=aclothes;
+
+       for(i=0;i<num_models;i++){
+               if(i==0)model[i].loadnotex(modelfilename);
+               if(i==1)model[i].loadnotex(model2filename);
+               if(i==2)model[i].loadnotex(model3filename);
+               if(i==3)model[i].loadnotex(model4filename);
+               if(i==4)model[i].loadnotex(model5filename);
+               if(i==5)model[i].loadnotex(model6filename);
+               if(i==6)model[i].loadnotex(model7filename);
+               model[i].Rotate(180,0,0);
+               model[i].Scale(.04,.04,.04);
+               model[i].CalculateNormals(0);
+       }
+
+       drawmodel.load(modelfilename,0);
+       drawmodel.Rotate(180,0,0);
+       drawmodel.Scale(.04,.04,.04);
+       drawmodel.FlipTexCoords();
+       if(tutoriallevel==1&&id!=0)drawmodel.UniformTexCoords();
+       if(tutoriallevel==1&&id!=0)drawmodel.ScaleTexCoords(0.1);
+       drawmodel.CalculateNormals(0);
+
+       modellow.loadnotex(modellowfilename);
+       modellow.Rotate(180,0,0);
+       modellow.Scale(.04,.04,.04);
+       modellow.CalculateNormals(0);
+
+       drawmodellow.load(modellowfilename,0);
+       drawmodellow.Rotate(180,0,0);
+       drawmodellow.Scale(.04,.04,.04);
+       drawmodellow.FlipTexCoords();
+       if(tutoriallevel==1&&id!=0)drawmodellow.UniformTexCoords();
+       if(tutoriallevel==1&&id!=0)drawmodellow.ScaleTexCoords(0.1);
+       drawmodellow.CalculateNormals(0);
+
+       if(clothes){
+               modelclothes.loadnotex(modelclothesfilename);
+               modelclothes.Rotate(180,0,0);
+               modelclothes.Scale(.041,.04,.041);
+               modelclothes.CalculateNormals(0);
+
+               drawmodelclothes.load(modelclothesfilename,0);
+               drawmodelclothes.Rotate(180,0,0);
+               drawmodelclothes.Scale(.04,.04,.04);
+               drawmodelclothes.FlipTexCoords();
+               drawmodelclothes.CalculateNormals(0);
+       }
+
+       tfile=fopen( filename, "rb" );
+       if(1){
+               funpackf(tfile, "Bi", &num_joints);
+               //joints.resize(num_joints);
+               if(joints) delete [] joints; //dealloc2(joints);
+               joints=(Joint*)new Joint[num_joints]; //malloc(sizeof(Joint)*num_joints);
+
+               for(i=0;i<num_joints;i++){
+                       funpackf(tfile, "Bf Bf Bf Bf Bf", &joints[i].position.x, &joints[i].position.y, &joints[i].position.z, &joints[i].length,&joints[i].mass);
+                       funpackf(tfile, "Bb Bb", &joints[i].hasparent,&joints[i].locked);
+                       funpackf(tfile, "Bi", &joints[i].modelnum);
+                       funpackf(tfile, "Bb Bb", &joints[i].visible,&joints[i].sametwist);
+                       funpackf(tfile, "Bi Bi", &joints[i].label,&joints[i].hasgun);
+                       funpackf(tfile, "Bb", &joints[i].lower);
+                       funpackf(tfile, "Bi", &parentID);
+                       if(joints[i].hasparent)joints[i].parent=&joints[parentID];
+                       joints[i].velocity=0;
+                       joints[i].oldposition=joints[i].position;
+               }
+               tempmuscle=num_muscles;
+               funpackf(tfile, "Bi", &num_muscles);
+               //muscles.clear();
+               if(muscles) delete [] muscles; //dealloc2(muscles);
+               muscles=(Muscle*)new Muscle[num_muscles]; //malloc(sizeof(Muscle)*num_muscles);
+               newload=1;
+               for(i=0;i<num_muscles;i++){
+                       tempmuscle=muscles[i].numvertices;
+                       funpackf(tfile, "Bf Bf Bf Bf Bf Bi Bi", &muscles[i].length, &muscles[i].targetlength,&muscles[i].minlength, &muscles[i].maxlength,&muscles[i].strength,&muscles[i].type,&muscles[i].numvertices);
+                       //muscles[i].vertices.clear();
+                       //muscles[i].vertices.resize(muscles[i].numvertices);
+                       //if(muscles[i].vertices)dealloc2(muscles[i].vertices);
+                       muscles[i].vertices=(int*)malloc(sizeof(int)*muscles[i].numvertices);
+
+                       edit=0;
+                       for(j=0;j<muscles[i].numvertices-edit;j++){
+                               funpackf(tfile, "Bi", &muscles[i].vertices[j+edit]);
+                               if(muscles[i].vertices[j+edit]>=model[0].vertexNum){
+                                       muscles[i].numvertices--;
+                                       edit--;
+                               }
+                       }
+                       funpackf(tfile, "Bb Bi", &muscles[i].visible, &parentID);
+                       muscles[i].parent1=&joints[parentID];
+                       funpackf(tfile, "Bi", &parentID);
+                       muscles[i].parent2=&joints[parentID];
+               }
+               for(j=0;j<3;j++){
+                       funpackf(tfile, "Bi", &forwardjoints[j]);
+               }
+               for(j=0;j<3;j++){
+                       funpackf(tfile, "Bi", &lowforwardjoints[j]);
+               }
+               for(j=0;j<num_muscles;j++){
+                       for(i=0;i<muscles[j].numvertices;i++){  
+                               for(int k=0;k<num_models;k++){                                          
+                                       if(muscles[j].numvertices&&muscles[j].vertices[i]<model[k].vertexNum)model[k].owner[muscles[j].vertices[i]]=j;
+                               }
+                       }
+               }
+               FindForwards();
+               for(i=0;i<num_joints;i++){
+                       joints[i].startpos=joints[i].position;
+               }
+               for(i=0;i<num_muscles;i++){
+                       FindRotationMuscle(i,-1);
+               }
+               for(int k=0;k<num_models;k++){
+                       for(i=0;i<model[k].vertexNum;i++){
+                               model[k].vertex[i]=model[k].vertex[i]-(muscles[model[k].owner[i]].parent1->position+muscles[model[k].owner[i]].parent2->position)/2;
+                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                               glPushMatrix();
+                                       glLoadIdentity();
+                                       glRotatef(muscles[model[k].owner[i]].rotate3,0,1,0);
+                                       glRotatef(muscles[model[k].owner[i]].rotate2-90,0,0,1);
+                                       glRotatef(muscles[model[k].owner[i]].rotate1-90,0,1,0);
+                                       glTranslatef(model[k].vertex[i].x,model[k].vertex[i].y,model[k].vertex[i].z);
+                                       glGetFloatv(GL_MODELVIEW_MATRIX,M);
+                                       model[k].vertex[i].x=M[12]*1;
+                                       model[k].vertex[i].y=M[13]*1;
+                                       model[k].vertex[i].z=M[14]*1;
+                               glPopMatrix();
+                       }
+                       model[k].CalculateNormals(0);
+               }
+       }
+       fclose(tfile);          
+
+       tfile=fopen( lowfilename, "rb" );
+       if(1){
+               lSize=sizeof(num_joints);
+               fseek ( tfile, lSize, SEEK_CUR);
+               //joints = new Joint[num_joints];
+               //jointlabels = new int[num_joints];
+               for(i=0;i<num_joints;i++){
+                       lSize=sizeof(XYZ);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(float);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(float);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(bool);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(bool);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(int);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(bool);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(bool);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(int);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(int);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(bool);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(int);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       if(joints[i].hasparent)joints[i].parent=&joints[parentID];
+                       joints[i].velocity=0;
+                       joints[i].oldposition=joints[i].position;
+               }
+               funpackf(tfile, "Bi", &num_muscles);
+               //muscles = new Muscle[num_muscles];
+               for(i=0;i<num_muscles;i++){
+                       lSize=sizeof(float);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(float);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(float);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(float);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(float);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(int);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       tempmuscle=muscles[i].numverticeslow;
+                       funpackf(tfile, "Bi", &muscles[i].numverticeslow);
+                       if(muscles[i].numverticeslow){
+                               //muscles[i].verticeslow.clear();
+                               //muscles[i].verticeslow.resize(muscles[i].numverticeslow);
+                               //if(muscles[i].verticeslow)dealloc2(muscles[i].verticeslow);
+                               muscles[i].verticeslow=(int*)malloc(sizeof(int)*muscles[i].numverticeslow);
+                               edit=0;
+                               for(j=0;j<muscles[i].numverticeslow-edit;j++){
+                                       funpackf(tfile, "Bi", &muscles[i].verticeslow[j+edit]);
+                                       if(muscles[i].verticeslow[j+edit]>=modellow.vertexNum){
+                                               muscles[i].numverticeslow--;
+                                               edit--;
+                                       }
+                               }
+
+
+                       }
+                       lSize=sizeof(bool);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(int);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       fseek ( tfile, lSize, SEEK_CUR);
+               }
+               lSize=sizeof(int);
+               for(j=0;j<num_muscles;j++){
+                       for(i=0;i<muscles[j].numverticeslow;i++){       
+                               if(muscles[j].numverticeslow&&muscles[j].verticeslow[i]<modellow.vertexNum)modellow.owner[muscles[j].verticeslow[i]]=j;
+                       }
+               }
+               /*FindForwards();
+               for(i=0;i<num_joints;i++){
+               joints[i].startpos=joints[i].position;
+               }
+               for(i=0;i<num_muscles;i++){
+               FindRotationMuscle(i,-1);
+               }*/
+               for(i=0;i<modellow.vertexNum;i++){
+                       modellow.vertex[i]=modellow.vertex[i]-(muscles[modellow.owner[i]].parent1->position+muscles[modellow.owner[i]].parent2->position)/2;
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPushMatrix();
+                               glLoadIdentity();
+                               glRotatef(muscles[modellow.owner[i]].rotate3,0,1,0);
+                               glRotatef(muscles[modellow.owner[i]].rotate2-90,0,0,1);
+                               glRotatef(muscles[modellow.owner[i]].rotate1-90,0,1,0);
+                               glTranslatef(modellow.vertex[i].x,modellow.vertex[i].y,modellow.vertex[i].z);
+                               glGetFloatv(GL_MODELVIEW_MATRIX,M);
+                               modellow.vertex[i].x=M[12];
+                               modellow.vertex[i].y=M[13];
+                               modellow.vertex[i].z=M[14];
+                       glPopMatrix();
+               }
+               modellow.CalculateNormals(0);
+       }
+
+       if(clothes){
+               tfile=fopen( clothesfilename, "rb" );
+               lSize=sizeof(num_joints);
+               fseek ( tfile, lSize, SEEK_CUR);
+               //joints = new Joint[num_joints];
+               //jointlabels = new int[num_joints];
+               for(i=0;i<num_joints;i++){
+                       lSize=sizeof(XYZ);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(float);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(float);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(bool);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(bool);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(int);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(bool);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(bool);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(int);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(int);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(bool);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(int);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       if(joints[i].hasparent)joints[i].parent=&joints[parentID];
+                       joints[i].velocity=0;
+                       joints[i].oldposition=joints[i].position;
+               }
+               funpackf(tfile, "Bi", &num_muscles);
+               //muscles = new Muscle[num_muscles];
+               for(i=0;i<num_muscles;i++){
+                       lSize=sizeof(float);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(float);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(float);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(float);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(float);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(int);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       tempmuscle=muscles[i].numverticesclothes;
+                       funpackf(tfile, "Bi", &muscles[i].numverticesclothes);
+                       if(muscles[i].numverticesclothes){
+                               //muscles[i].verticesclothes.clear();
+                               //muscles[i].verticesclothes.resize(muscles[i].numverticesclothes);
+                               //if(muscles[i].verticesclothes)dealloc2(muscles[i].verticesclothes);
+                               muscles[i].verticesclothes=(int*)malloc(sizeof(int)*muscles[i].numverticesclothes);
+                               edit=0;
+                               for(j=0;j<muscles[i].numverticesclothes-edit;j++){
+                                       funpackf(tfile, "Bi", &muscles[i].verticesclothes[j+edit]);
+                                       if(muscles[i].verticesclothes[j+edit]>=modelclothes.vertexNum){
+                                               muscles[i].numverticesclothes--;
+                                               edit--;
+                                       }
+                               }
+                       }
+                       lSize=sizeof(bool);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       lSize=sizeof(int);
+                       fseek ( tfile, lSize, SEEK_CUR);
+                       fseek ( tfile, lSize, SEEK_CUR);
+               }
+               lSize=sizeof(int);
+               for(j=0;j<num_muscles;j++){
+                       for(i=0;i<muscles[j].numverticesclothes;i++){   
+                               if(muscles[j].numverticesclothes&&muscles[j].verticesclothes[i]<modelclothes.vertexNum)modelclothes.owner[muscles[j].verticesclothes[i]]=j;
+                       }
+               }
+               /*FindForwards();
+               for(i=0;i<num_joints;i++){
+               joints[i].startpos=joints[i].position;
+               }
+               for(i=0;i<num_muscles;i++){
+               FindRotationMuscle(i,-1);
+               }*/
+               for(i=0;i<modelclothes.vertexNum;i++){
+                       modelclothes.vertex[i]=modelclothes.vertex[i]-(muscles[modelclothes.owner[i]].parent1->position+muscles[modelclothes.owner[i]].parent2->position)/2;
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPushMatrix();
+                               glLoadIdentity();
+                               glRotatef(muscles[modelclothes.owner[i]].rotate3,0,1,0);
+                               glRotatef(muscles[modelclothes.owner[i]].rotate2-90,0,0,1);
+                               glRotatef(muscles[modelclothes.owner[i]].rotate1-90,0,1,0);
+                               glTranslatef(modelclothes.vertex[i].x,modelclothes.vertex[i].y,modelclothes.vertex[i].z);
+                               glGetFloatv(GL_MODELVIEW_MATRIX,M);
+                               modelclothes.vertex[i].x=M[12];
+                               modelclothes.vertex[i].y=M[13];
+                               modelclothes.vertex[i].z=M[14];
+                       glPopMatrix();
+               }
+               modelclothes.CalculateNormals(0);
+       }
+       fclose(tfile);          
+
+       for(i=0;i<num_joints;i++){
+               for(j=0;j<num_joints;j++){
+                       if(joints[i].label==j)jointlabels[j]=i;
+               }
+       }
+
+       free=0;
+}
+
+Animation::Animation()
+{
+       numframes = 0;
+       height = 0;
+       attack = 0;
+       joints = 0;
+       weapontargetnum = 0;
+
+       position=0;
+       twist=0;
+       twist2=0;
+       speed=0;
+       onground=0;
+       forward=0;
+       label=0;
+       weapontarget=0;
+}
+
+Animation::~Animation()
+{
+       deallocate();
+}
+
+void Animation::deallocate()
+{
+       int i = 0;
+
+       if(position)
+       {
+               for(i = 0; i < joints; i++)
+                       dealloc2(position[i]);
+
+               dealloc2(position);
+       }
+       position = 0;
+
+       if(twist)
+       {
+               for(i = 0; i < joints; i++)
+                       dealloc2(twist[i]);
+
+               dealloc2(twist);
+       }
+       twist = 0;
+
+       if(twist2)
+       {
+               for(i = 0; i < joints; i++)
+                       dealloc2(twist2[i]);
+
+               dealloc2(twist2);
+       }
+       twist2 = 0;
+
+       if(onground)
+       {
+               for(i = 0; i < joints; i++)
+                       dealloc2(onground[i]);
+
+               dealloc2(onground);
+       }
+       onground = 0;
+
+       if(speed)dealloc2(speed);
+       speed = 0;
+
+       if(forward)dealloc2(forward);
+       forward = 0;
+
+       if(weapontarget)dealloc2(weapontarget);
+       weapontarget = 0;
+
+       if(label)dealloc2(label);
+       label = 0;
+
+       joints = 0;
+}
+
+Skeleton::Skeleton()
+{
+       num_joints = 0;
+
+       num_muscles = 0;
+
+       selected = 0;
+
+       memset(forwardjoints, 0, sizeof(forwardjoints));
+       //              XYZ forward;
+
+       id = 0;
+
+       memset(lowforwardjoints, 0, sizeof(lowforwardjoints));
+       //              XYZ lowforward;
+
+       //              XYZ specialforward[5];
+       memset(jointlabels, 0, sizeof(jointlabels));
+
+       //              Model model[7];
+       //              Model modellow;
+       //              Model modelclothes;
+       num_models = 0;
+
+       //              Model drawmodel;
+       //              Model drawmodellow;
+       //              Model drawmodelclothes;
+
+       clothes = 0;
+       spinny = 0;
+
+       memset(skinText, 0, sizeof(skinText));
+       skinsize = 0;
+
+       checkdelay = 0;
+
+       longdead = 0;
+       broken = 0;
+
+       free = 0;
+       oldfree = 0;
+       freetime = 0;
+       freefall = 0;
+
+       joints=0;
+       muscles=0;
+}
+
+Skeleton::~Skeleton()
+{
+       if (muscles)
+       {
+               delete [] muscles;
+       }
+       muscles = 0;
+
+       if (joints)
+       {
+               delete [] joints;
+       }
+       joints = 0;
+}
+
+Muscle::Muscle()
+{
+       vertices=0;
+       verticeslow=0;
+       verticesclothes=0;
+
+       numvertices = 0;
+       numverticeslow = 0;
+       numverticesclothes = 0;
+       length = 0;
+       targetlength = 0;
+       parent1 = 0;
+       parent2 = 0;
+       maxlength = 0;
+       minlength = 0;
+       type = 0;
+       visible = 0;
+       rotate1 = 0,rotate2 = 0,rotate3 = 0;
+       lastrotate1 = 0,lastrotate2 = 0,lastrotate3 = 0;
+       oldrotate1 = 0,oldrotate2 = 0,oldrotate3 = 0;
+       newrotate1 = 0,newrotate2 = 0,newrotate3 = 0;
+
+       strength = 0;
+}
+
+Muscle::~Muscle()
+{
+       dealloc2(vertices);
+       dealloc2(verticeslow);
+       dealloc2(verticesclothes);
+}
+
+Animation & Animation::operator = (const Animation & ani)
+{
+       int i = 0;
+
+       bool allocate = true;
+
+       allocate = ((ani.numframes != numframes) || (ani.joints != joints));
+
+       if (allocate) deallocate();
+
+       numframes = ani.numframes;
+       height = ani.height;
+       attack = ani.attack;
+       joints = ani.joints;
+       weapontargetnum = ani.weapontargetnum;
+
+       if (allocate) position=(XYZ**)malloc(sizeof(XYZ*)*ani.joints);
+       for(i = 0; i < ani.joints; i++)
+       {
+               if (allocate) position[i] = (XYZ*)malloc(sizeof(XYZ)*ani.numframes);
+               memcpy(position[i], ani.position[i], sizeof(XYZ)*ani.numframes);
+       }
+
+       if (allocate) twist=(float**)malloc(sizeof(float*)*ani.joints);
+       for(i = 0; i < ani.joints; i++)
+       {
+               if (allocate) twist[i] = (float*)malloc(sizeof(float)*ani.numframes);
+               memcpy(twist[i], ani.twist[i], sizeof(float)*ani.numframes);
+       }
+
+       if (allocate) twist2=(float**)malloc(sizeof(float*)*ani.joints);
+       for(i = 0; i < ani.joints; i++)
+       {
+               if (allocate) twist2[i] = (float*)malloc(sizeof(float)*ani.numframes);
+               memcpy(twist2[i], ani.twist2[i], sizeof(float)*ani.numframes);
+       }
+
+       if (allocate) speed = (float*)malloc(sizeof(float)*ani.numframes);
+       memcpy(speed, ani.speed, sizeof(float)*ani.numframes);
+
+       if (allocate) onground=(bool**)malloc(sizeof(bool*)*ani.joints);
+       for(i = 0; i < ani.joints; i++)
+       {
+               if (allocate) onground[i] =(bool*)malloc(sizeof(bool)*ani.numframes);
+               memcpy(onground[i], ani.onground[i], sizeof(bool)*ani.numframes);
+       }
+
+       if (allocate) forward = (XYZ*)malloc(sizeof(XYZ)*ani.numframes);
+       memcpy(forward, ani.forward, sizeof(XYZ)*ani.numframes);
+
+       if (allocate) weapontarget = (XYZ*)malloc(sizeof(XYZ)*ani.numframes);
+       memcpy(weapontarget, ani.weapontarget, sizeof(XYZ)*ani.numframes);
+
+       if (allocate) label = (int*)malloc(sizeof(int)*ani.numframes);
+       memcpy(label, ani.label, sizeof(int)*ani.numframes);
+
+       return (*this);
+}
diff --git a/Source/Skeleton.h b/Source/Skeleton.h
new file mode 100644 (file)
index 0000000..30a9f75
--- /dev/null
@@ -0,0 +1,206 @@
+#ifndef _SKELETON_H_
+#define _SKELETON_H_
+
+#include "Models.h"
+#include "Quaternions.h"
+#include "Constants.h"
+
+
+/**> HEADER FILES <**/
+#include "gl.h"
+#include "Quaternions.h"
+#include "fmod.h"
+#include "objects.h"
+#include "Sprites.h"
+#include "binio.h"
+
+#define neutral 0
+#define normalattack 1
+#define reversed 2
+#define reversal 3
+#define lowheight 0
+#define middleheight 1
+#define highheight 2
+
+class Joint
+{
+public:
+       XYZ position;
+       XYZ oldposition;
+       XYZ realoldposition;
+       XYZ velocity;
+       XYZ oldvelocity;
+       XYZ startpos;
+       float blurred;
+       float length;
+       float mass;
+       bool lower;
+       bool hasparent;
+       bool locked;
+       int modelnum;
+       bool visible;
+       Joint* parent;
+       bool sametwist;
+       int label;
+       int hasgun;
+       float delay;
+       XYZ velchange;
+
+       Joint()
+       {
+               blurred = 0;
+               length = 0;
+               mass = 0;
+               lower = 0;
+               hasparent = 0;
+               locked = 0;
+               modelnum = 0;
+               visible = 0;
+               parent = 0;
+               sametwist = 0;
+               label = 0;
+               hasgun = 0;
+               delay = 0;
+       }
+
+       void DoConstraint();
+};
+
+class Muscle
+{
+public:
+       int numvertices;
+       int* vertices;
+       int numverticeslow;
+       int* verticeslow;
+       int numverticesclothes;
+       int* verticesclothes;
+       float length;
+       float targetlength;
+       Joint* parent1;
+       Joint* parent2;
+       float maxlength;
+       float minlength;
+       int type;
+       bool visible;
+       void DoConstraint(bool spinny);
+       float rotate1,rotate2,rotate3;
+       float lastrotate1,lastrotate2,lastrotate3;
+       float oldrotate1,oldrotate2,oldrotate3;
+       float newrotate1,newrotate2,newrotate3;
+
+       float strength;
+
+       ~Muscle();
+       Muscle();
+};
+
+class Animation
+{
+public:
+       int numframes;
+       int height;
+       int attack;
+       int joints;
+       int weapontargetnum;
+
+       XYZ**  position;
+       float** twist;
+       float** twist2;
+       float* speed;
+       bool** onground;
+       XYZ* forward;
+       int* label;
+       XYZ* weapontarget;
+
+
+       XYZ offset;
+
+       Animation();
+
+       ~Animation();
+
+       Animation & operator = (const Animation & ani);
+
+       void Load(char *fileName, int aheight, int aattack);
+       void Move(XYZ how);
+
+protected:
+       void deallocate();
+};
+
+
+class Skeleton
+{
+public:
+       int num_joints;
+       //Joint joints[max_joints];
+       //Joint *joints;
+       Joint* joints;
+
+       int num_muscles;
+       //Muscle muscles[max_muscles];
+       //Muscle *muscles;
+       Muscle* muscles;
+
+       int selected;
+
+       int forwardjoints[3];
+       XYZ forward;
+
+       int id;
+
+       int lowforwardjoints[3];
+       XYZ lowforward;
+
+       XYZ specialforward[5];
+       int jointlabels[max_joints];
+
+       Model model[7];
+       Model modellow;
+       Model modelclothes;
+       int num_models;
+
+       Model drawmodel;
+       Model drawmodellow;
+       Model drawmodelclothes;
+
+       bool clothes;
+       bool spinny;
+
+       GLubyte skinText[512*512*3];
+       int skinsize;
+
+       float checkdelay;
+
+       float longdead;
+       bool broken;
+
+       int free;
+       int oldfree;
+       float freetime;
+       bool freefall;
+
+       void FindForwards();
+       void FindForwardsfirst();
+       float DoConstraints(XYZ *coords,float *scale);
+       void DoGravity(float *scale);
+       void DoBalance();
+       void MusclesSet();
+       void Draw(int muscleview);
+       void AddJoint(float x, float y, float z, int which);
+       void SetJoint(float x, float y, float z, int which, int whichjoint);
+       void DeleteJoint(int whichjoint);
+       void AddMuscle(int attach1,int attach2,float maxlength,float minlength,int type);
+       void DeleteMuscle(int whichmuscle);
+       void FindRotationJoint(int which);
+       void FindRotationJointSameTwist(int which);
+       void FindRotationMuscle(int which, int animation);
+       void Load(char *fileName,char *lowfileName,char *clothesfileName,char *modelfileName,char *model2fileName,char *model3fileName,char *model4fileName,char *model5fileNamee,char *model6fileName,char *model7fileName,char *modellowfileName,char *modelclothesfileName, bool aclothes);
+
+       Skeleton();
+
+       ~Skeleton();
+};
+
+#endif
\ No newline at end of file
diff --git a/Source/Skybox.cpp b/Source/Skybox.cpp
new file mode 100644 (file)
index 0000000..6d074ce
--- /dev/null
@@ -0,0 +1,358 @@
+#include "skybox.h"
+#include "Game.h"
+
+extern float viewdistance;
+extern int detail;
+extern bool trilinear;
+extern float blurness;
+extern int environment;
+extern TGAImageRec texture;
+extern bool skyboxtexture;
+extern float skyboxr;
+extern float skyboxg;
+extern float skyboxb;
+extern int tutoriallevel;
+
+bool   SkyBox::load( char *ffront,char *fleft,char *fback,char *fright,char *fup,char *fdown,char *fcloud,char *freflect)
+{
+/*     static GLuint           type;
+       unsigned char fileNamep[256];
+*/
+       LOGFUNC;
+
+       //front
+       Game::LoadTexture(ffront, &front, true, false);
+       //left
+       Game::LoadTexture(fleft, &left, true, false);
+       //back
+       Game::LoadTexture(fback, &back, true, false);
+       //right
+       Game::LoadTexture(fright, &right, true, false);
+       //up
+       Game::LoadTexture(fup, &up, true, false);
+       //down
+       Game::LoadTexture(fdown, &down, true, false);
+       //cloud
+       Game::LoadTexture(fcloud, &cloud, true, false);
+       //reflect
+       Game::LoadTexture(freflect, &reflect, true, false);
+/*
+       //front
+       CopyCStringToPascal(ffront,fileNamep);
+       upload_image( fileNamep ,0); 
+       if(1==1){
+               if ( texture.bpp == 24 )
+                       type = GL_RGB;
+               else
+                       type = GL_RGBA;
+
+               glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+               if(!front)glGenTextures( 1, &front );
+               glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+               glBindTexture( GL_TEXTURE_2D, front);
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+               //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+               if(trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
+               if(!trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
+
+               gluBuild2DMipmaps( GL_TEXTURE_2D, type, texture.sizeX, texture.sizeY, type, GL_UNSIGNED_BYTE, texture.data );
+
+       }
+
+       //left
+       CopyCStringToPascal(fleft,fileNamep);
+       upload_image( fileNamep ,0); 
+       if(1==1){
+               if ( texture.bpp == 24 )
+                       type = GL_RGB;
+               else
+                       type = GL_RGBA;
+
+               glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+               if(!left)glGenTextures( 1, &left );
+               glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+               glBindTexture( GL_TEXTURE_2D, left);
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+               //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+               if(trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
+               if(!trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
+
+               gluBuild2DMipmaps( GL_TEXTURE_2D, type, texture.sizeX, texture.sizeY, type, GL_UNSIGNED_BYTE, texture.data );
+
+       }
+
+       //back
+       CopyCStringToPascal(fback,fileNamep);
+       upload_image( fileNamep ,0); 
+       if(1==1){
+               if ( texture.bpp == 24 )
+                       type = GL_RGB;
+               else
+                       type = GL_RGBA;
+
+               glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+               if(!back)glGenTextures( 1, &back );
+               glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+               glBindTexture( GL_TEXTURE_2D, back);
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+               //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+               if(trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
+               if(!trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
+
+               gluBuild2DMipmaps( GL_TEXTURE_2D, type, texture.sizeX, texture.sizeY, type, GL_UNSIGNED_BYTE, texture.data );
+
+       }
+
+       //right
+       CopyCStringToPascal(fright,fileNamep);
+       upload_image( fileNamep ,0); 
+       if(1==1){
+               if ( texture.bpp == 24 )
+                       type = GL_RGB;
+               else
+                       type = GL_RGBA;
+
+               glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+               if(!right)glGenTextures( 1, &right );
+               glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+               glBindTexture( GL_TEXTURE_2D, right);
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+               //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+               if(trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
+               if(!trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
+
+               gluBuild2DMipmaps( GL_TEXTURE_2D, type, texture.sizeX, texture.sizeY, type, GL_UNSIGNED_BYTE, texture.data );
+
+       }
+
+       //up
+       CopyCStringToPascal(fup,fileNamep);
+       upload_image( fileNamep ,0); 
+       if(1==1){
+               if ( texture.bpp == 24 )
+                       type = GL_RGB;
+               else
+                       type = GL_RGBA;
+
+               glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+               if(!up)glGenTextures( 1, &up );
+               glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+               glBindTexture( GL_TEXTURE_2D, up);
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+               //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+               if(trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
+               if(!trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
+
+               gluBuild2DMipmaps( GL_TEXTURE_2D, type, texture.sizeX, texture.sizeY, type, GL_UNSIGNED_BYTE, texture.data );
+
+       }
+
+       //down
+       CopyCStringToPascal(fdown,fileNamep);
+       upload_image( fileNamep ,0); 
+       if(1==1){
+               if ( texture.bpp == 24 )
+                       type = GL_RGB;
+               else
+                       type = GL_RGBA;
+
+               glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+               if(!down)glGenTextures( 1, &down );
+               glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+               glBindTexture( GL_TEXTURE_2D, down);
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+               //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+               if(trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
+               if(!trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
+
+               gluBuild2DMipmaps( GL_TEXTURE_2D, type, texture.sizeX, texture.sizeY, type, GL_UNSIGNED_BYTE, texture.data );
+
+       }
+
+       //cloud
+       CopyCStringToPascal(fcloud,fileNamep);
+       upload_image( fileNamep ,0); 
+       if(1==1){
+               if ( texture.bpp == 24 )
+                       type = GL_RGB;
+               else
+                       type = GL_RGBA;
+
+               glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+               if(!cloud)glGenTextures( 1, &cloud );
+               glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+               glBindTexture( GL_TEXTURE_2D, cloud);
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+               //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+               if(trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
+               if(!trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
+
+               gluBuild2DMipmaps( GL_TEXTURE_2D, type, texture.sizeX, texture.sizeY, type, GL_UNSIGNED_BYTE, texture.data );
+
+       }
+
+       //up
+       CopyCStringToPascal(freflect,fileNamep);
+       upload_image( fileNamep ,0); 
+       if(1==1){
+               if ( texture.bpp == 24 )
+                       type = GL_RGB;
+               else
+                       type = GL_RGBA;
+
+               glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+               if(!reflect)glGenTextures( 1, &reflect );
+               glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+               glBindTexture( GL_TEXTURE_2D, reflect);
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+               //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+               if(trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
+               if(!trilinear)glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
+
+               gluBuild2DMipmaps( GL_TEXTURE_2D, type, texture.sizeX, texture.sizeY, type, GL_UNSIGNED_BYTE, texture.data );
+
+       }
+*/
+       return true;
+}
+
+void   SkyBox::draw()
+{
+       static float size=viewdistance/4;
+       glPushMatrix();
+       static GLfloat M[16];
+       glGetFloatv(GL_MODELVIEW_MATRIX,M);
+       M[12]=0;
+       M[13]=0;
+       M[14]=0;
+       glLoadMatrixf(M);
+       //if(environment==2)glTranslatef(0,blurness*viewdistance/1000,0);
+       if(environment==2)glScalef(1+blurness/1000,1,1+blurness/1000);
+       if(environment!=2)glColor3f(.85*skyboxr,.85*skyboxg,.95*skyboxb);
+       else glColor3f(1*skyboxr,.95*skyboxg,.95*skyboxb);
+
+       if(!skyboxtexture){
+               glDisable(GL_TEXTURE_2D); 
+               glColor3f(skyboxr*.8,skyboxg*.8,skyboxb*.8);
+       }
+       glDepthMask(0);
+       glDisable(GL_CULL_FACE);
+       glEnable(GL_BLEND);
+       glDisable(GL_LIGHTING);
+       //              glActiveTextureARB(GL_TEXTURE0_ARB);
+       if(skyboxtexture)glEnable(GL_TEXTURE_2D);
+       glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+       glBindTexture(GL_TEXTURE_2D, front); 
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+       glBegin(GL_QUADS);
+       glNormal3f( 0.0f, 0.0f, -1);
+       glTexCoord2f(0, 0); glVertex3f(-size, -size,  size);
+       glTexCoord2f(1, 0); glVertex3f( size, -size,  size);
+       glTexCoord2f(1, 1); glVertex3f( size,  size,  size);
+       glTexCoord2f(0, 1); glVertex3f(-size,  size,  size);
+       glEnd();
+       glBindTexture(GL_TEXTURE_2D, back);
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+       glBegin(GL_QUADS);
+       glNormal3f( 0.0f, 0.0f, 1);
+       glTexCoord2f(1, 0); glVertex3f(-size, -size, -size);
+       glTexCoord2f(1, 1); glVertex3f(-size,  size, -size);
+       glTexCoord2f(0, 1); glVertex3f( size,  size, -size);
+       glTexCoord2f(0, 0); glVertex3f( size, -size, -size);
+       glEnd();
+       glBindTexture(GL_TEXTURE_2D, up);
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+       glBegin(GL_QUADS);
+       glNormal3f( 0.0f, -1.0f, 0);
+       glTexCoord2f(0, 1); glVertex3f(-size,  size, -size);
+       glTexCoord2f(0, 0); glVertex3f(-size,  size,  size);
+       glTexCoord2f(1, 0); glVertex3f( size,  size,  size);
+       glTexCoord2f(1, 1); glVertex3f( size,  size, -size);
+       glEnd();
+       //if(detail!=0){
+       glBindTexture(GL_TEXTURE_2D, down);
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+       glBegin(GL_QUADS);
+       glNormal3f( 0.0f, 1.0f, 0);
+
+       glTexCoord2f(0, 0); glVertex3f(-size, -size, -size);
+       glTexCoord2f(1, 0); glVertex3f( size, -size, -size);
+       glTexCoord2f(1, 1); glVertex3f( size, -size,  size);
+       glTexCoord2f(0, 1); glVertex3f(-size, -size,  size);
+       glEnd();
+       //}
+       glBindTexture(GL_TEXTURE_2D, right);
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+       glBegin(GL_QUADS);
+       glNormal3f( -1.0f, 0.0f, 0);
+       glTexCoord2f(1, 0); glVertex3f( size, -size, -size);
+       glTexCoord2f(1, 1); glVertex3f( size,  size, -size);
+       glTexCoord2f(0, 1); glVertex3f( size,  size,  size);
+       glTexCoord2f(0, 0); glVertex3f( size, -size,  size);
+       glEnd();
+       glBindTexture(GL_TEXTURE_2D, left);
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+       glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+       glBegin(GL_QUADS);
+       glNormal3f( 1.0f, 0.0f, 0);
+       glTexCoord2f(0, 0); glVertex3f(-size, -size, -size);
+       glTexCoord2f(1, 0); glVertex3f(-size, -size,  size);
+       glTexCoord2f(1, 1); glVertex3f(-size,  size,  size);
+       glTexCoord2f(0, 1); glVertex3f(-size,  size, -size);
+       glEnd();
+       /*
+       glEnable(GL_BLEND);
+       glColor4f(1,1,1,1);
+       glBindTexture(GL_TEXTURE_2D, cloud);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
+       glBegin(GL_QUADS);
+       glNormal3f( 0.0f, -1.0f, 0);
+       glTexCoord2f(0,                                 (1+cloudmove)*30);      glVertex3f(-size,       size/200, -size);
+       glTexCoord2f(0,                                 0);                             glVertex3f(-size,       size/200,  size);
+       glTexCoord2f((1+cloudmove)*30,  0);                             glVertex3f( size,       size/200,  size);
+       glTexCoord2f((1+cloudmove)*30,  (1+cloudmove)*30);      glVertex3f( size,       size/200, -size);
+       glEnd();
+       glDisable(GL_BLEND);*/
+       glEnable(GL_CULL_FACE);
+       glDepthMask(1);
+       glPopMatrix();
+}
+
+SkyBox::SkyBox()
+{
+       front = 0,left = 0,back = 0,right = 0,up = 0,down = 0,cloud = 0,reflect = 0;
+       cloudmove = 0;
+}
+SkyBox::~SkyBox()
+{
+       if (front) glDeleteTextures( 1, (const unsigned long *)&front );
+       if (left) glDeleteTextures( 1, (const unsigned long *)&left );
+       if (back) glDeleteTextures( 1, (const unsigned long *)&back );
+       if (right) glDeleteTextures( 1, (const unsigned long *)&right );
+       if (up) glDeleteTextures( 1, (const unsigned long *)&up );
+       if (down) glDeleteTextures( 1, (const unsigned long *)&down );
+       if (cloud) glDeleteTextures( 1, (const unsigned long *)&cloud );
+       if (reflect) glDeleteTextures( 1, (const unsigned long *)&reflect );
+};
diff --git a/Source/Skybox.h b/Source/Skybox.h
new file mode 100644 (file)
index 0000000..2eae596
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef _SKYBOX_H_
+#define _SKYBOX_H_
+
+#include "Quaternions.h"
+#include "TGALoader.h"
+#include "Quaternions.h"
+#include "gl.h"                
+
+class SkyBox{
+public:
+       GLuint                          front,left,back,right,up,down,cloud,reflect;
+       float cloudmove;
+
+       bool load(char *ffront,char *fleft,char *fback,char *fright,char *fup,char *fdown,char *fcloud,char *freflect);
+       void draw();
+
+       SkyBox();
+       ~SkyBox();
+};
+
+#endif
\ No newline at end of file
diff --git a/Source/Sprites.cpp b/Source/Sprites.cpp
new file mode 100644 (file)
index 0000000..aba6f8d
--- /dev/null
@@ -0,0 +1,443 @@
+#include "Sprites.h"
+#include "Person.h"
+extern XYZ viewer;
+extern float viewdistance;
+extern float fadestart;
+extern int environment;
+extern float texscale;
+extern Light light;
+extern float multiplier;
+extern float gravity;
+extern Terrain terrain;
+extern Objects objects;
+extern int detail;
+extern XYZ viewerfacing;
+extern float terraindetail;
+extern int bloodtoggle;
+extern XYZ windvector;
+extern int numplayers;
+extern Person player[maxplayers];
+//Functions
+
+void Sprites::Draw()
+{
+       static int i,j,k;
+       static float M[16];
+       static XYZ point;
+       static float distancemult;
+       static int lasttype;
+       static int lastspecial;
+       static int whichpatchx,whichpatchz;
+       static XYZ start,end,colpoint;
+       static bool check;
+       static bool blend;
+       static float tempmult;
+       static XYZ difference;
+       static float lightcolor[3];
+       static float viewdistsquared=viewdistance*viewdistance;
+       static XYZ tempviewer;
+
+       tempviewer=viewer+viewerfacing*6;
+       check=0;
+
+       lightcolor[0]=light.color[0]*.5+light.ambient[0];
+       lightcolor[1]=light.color[1]*.5+light.ambient[1];
+       lightcolor[2]=light.color[2]*.5+light.ambient[2];
+
+       checkdelay-=multiplier*10;
+
+       if(checkdelay<=0){
+               check=1;
+               checkdelay=1;
+       }
+
+       lasttype=-1;
+       lastspecial=-1;
+       glEnable(GL_BLEND);
+       glDisable(GL_LIGHTING);
+       glDisable(GL_CULL_FACE);
+       glEnable(GL_TEXTURE_2D);
+       blend = 1;
+       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+       glDepthMask(0);
+       glAlphaFunc(GL_GREATER, 0.0001);
+       for(i=0;i<numsprites;i++){
+               if(type[i]==cloudsprite&&lasttype!=type[i]){
+                       glBindTexture( GL_TEXTURE_2D, cloudtexture);
+                       if(!blend){
+                               blend=1;
+                               glAlphaFunc(GL_GREATER, 0.0001);
+                               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       }
+               }
+               if(type[i]==cloudimpactsprite&&lasttype!=type[i]){
+                       glBindTexture( GL_TEXTURE_2D, cloudimpacttexture);
+                       if(!blend){
+                               blend=1;
+                               glAlphaFunc(GL_GREATER, 0.0001);
+                               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       }
+               }
+               if(type[i]==breathsprite&&lasttype!=type[i]){
+                       glBindTexture( GL_TEXTURE_2D, cloudimpacttexture);
+                       if(!blend){
+                               blend=1;
+                               glAlphaFunc(GL_GREATER, 0.0001);
+                               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       }
+               }
+               if(type[i]==smoketype&&lasttype!=type[i]){
+                       glBindTexture( GL_TEXTURE_2D, smoketexture);
+                       if(!blend){
+                               blend=1;
+                               glAlphaFunc(GL_GREATER, 0.0001);
+                               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       }
+               }
+               if(type[i]==bloodsprite&&lasttype!=type[i]){
+                       glBindTexture( GL_TEXTURE_2D, bloodtexture);
+                       if(!blend){
+                               blend=1;
+                               glAlphaFunc(GL_GREATER, 0.0001);
+                               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       }
+               }
+               if(type[i]==splintersprite&&(lasttype!=type[i]||lastspecial!=special[i])){
+                       if(special[i]==0)glBindTexture( GL_TEXTURE_2D, splintertexture);
+                       if(special[i]==1)glBindTexture( GL_TEXTURE_2D, leaftexture);
+                       if(special[i]==2)glBindTexture( GL_TEXTURE_2D, snowflaketexture);
+                       if(special[i]==3)glBindTexture( GL_TEXTURE_2D, toothtexture);
+                       if(!blend){
+                               blend=1;
+                               glAlphaFunc(GL_GREATER, 0.0001);
+                               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       }
+               }
+               if(type[i]==snowsprite&&lasttype!=type[i]){
+                       glBindTexture( GL_TEXTURE_2D, snowflaketexture);
+                       if(!blend){
+                               blend=1;
+                               glAlphaFunc(GL_GREATER, 0.0001);
+                               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       }
+               }
+               if(type[i]==weaponshinesprite&&lasttype!=type[i]){
+                       glBindTexture( GL_TEXTURE_2D, shinetexture);
+                       if(blend){
+                               blend=0;
+                               glAlphaFunc(GL_GREATER, 0.001);
+                               glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+                       }
+               }
+               if((type[i]==flamesprite||type[i]==weaponflamesprite)&&lasttype!=type[i]){
+                       glBindTexture( GL_TEXTURE_2D, flametexture);
+                       if(blend||lasttype==bloodflamesprite){
+                               blend=0;
+                               glAlphaFunc(GL_GREATER, 0.3);
+                               glBlendFunc(GL_SRC_ALPHA,GL_ONE);
+                       }
+               }
+               if((type[i]==bloodflamesprite)&&lasttype!=type[i]){
+                       glBindTexture( GL_TEXTURE_2D, bloodflametexture);
+                       if(blend){
+                               blend=0;
+                               glAlphaFunc(GL_GREATER, 0.3);
+                               glBlendFunc(GL_ONE,GL_ZERO);
+                               //glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                       }
+               }
+               if(type[i]!=snowsprite)distancemult=(viewdistsquared-(findDistancefast(&viewer,&position[i])-(viewdistsquared*fadestart))*(1/(1-fadestart)))/viewdistsquared;
+               if(type[i]==snowsprite)distancemult=(144-(findDistancefast(&tempviewer,&position[i])-(144*fadestart))*(1/(1-fadestart)))/144;
+               if(type[i]!=flamesprite){
+                       if(distancemult>=1)glColor4f(color[i][0]*lightcolor[0],color[i][1]*lightcolor[1],color[i][2]*lightcolor[2],opacity[i]);
+                       if(distancemult<1)glColor4f(color[i][0]*lightcolor[0],color[i][1]*lightcolor[1],color[i][2]*lightcolor[2],opacity[i]*distancemult);
+               }
+               if(type[i]==flamesprite){
+                       if(distancemult>=1)glColor4f(color[i][0],color[i][1],color[i][2],opacity[i]);
+                       if(distancemult<1)glColor4f(color[i][0],color[i][1],color[i][2],opacity[i]*distancemult);
+               }
+               lasttype=type[i];
+               lastspecial=special[i];
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+               glPushMatrix();
+                       glTranslatef(position[i].x,position[i].y,position[i].z);
+                       if((type[i]==flamesprite||type[i]==weaponflamesprite||type[i]==weaponshinesprite)){
+                               difference=viewer-position[i];
+                               Normalise(&difference);
+                               glTranslatef(difference.x*size[i]/4, difference.y*size[i]/4, difference.z*size[i]/4);
+                       }
+                       if(type[i]==snowsprite){
+                               glRotatef(rotation[i]*.2,0,.3,1);
+                               glTranslatef(1,0,0);
+                       }
+                       glGetFloatv(GL_MODELVIEW_MATRIX,M);
+                       point.x=M[12];
+                       point.y=M[13];
+                       point.z=M[14];
+                       glLoadIdentity();
+                       glTranslatef(point.x, point.y, point.z);
+
+                       glRotatef(rotation[i],0,0,1);
+
+                       if((type[i]==flamesprite||type[i]==weaponflamesprite||type[i]==weaponshinesprite||type[i]==bloodflamesprite)){
+                               if(alivetime[i]<.14)glScalef(alivetime[i]/.14,alivetime[i]/.14,alivetime[i]/.14);
+                       }
+                       if(type[i]==smoketype||type[i]==snowsprite||type[i]==weaponshinesprite||type[i]==breathsprite){
+                               if(alivetime[i]<.3){
+                                       if(distancemult>=1)glColor4f(color[i][0]*lightcolor[0],color[i][1]*lightcolor[1],color[i][2]*lightcolor[2],opacity[i]*alivetime[i]/.3);
+                                       if(distancemult<1)glColor4f(color[i][0]*lightcolor[0],color[i][1]*lightcolor[1],color[i][2]*lightcolor[2],opacity[i]*distancemult*alivetime[i]/.3);
+                               }
+                       }
+                       if(type[i]==splintersprite&&special[i]>0&&special[i]!=3){
+                               if(alivetime[i]<.2){
+                                       if(distancemult>=1)glColor4f(color[i][0]*lightcolor[0],color[i][1]*lightcolor[1],color[i][2]*lightcolor[2],alivetime[i]/.2);
+                                       if(distancemult<1)glColor4f(color[i][0]*lightcolor[0],color[i][1]*lightcolor[1],color[i][2]*lightcolor[2],distancemult*alivetime[i]/.2);
+                               }
+                               else{
+                                       if(distancemult>=1)glColor4f(color[i][0]*lightcolor[0],color[i][1]*lightcolor[1],color[i][2]*lightcolor[2],1);
+                                       if(distancemult<1)glColor4f(color[i][0]*lightcolor[0],color[i][1]*lightcolor[1],color[i][2]*lightcolor[2],1);
+                               }
+                       }
+                       if(type[i]==splintersprite&&(special[i]==0||special[i]==3)){
+                               if(distancemult>=1)glColor4f(color[i][0]*lightcolor[0],color[i][1]*lightcolor[1],color[i][2]*lightcolor[2],1);
+                               if(distancemult<1)glColor4f(color[i][0]*lightcolor[0],color[i][1]*lightcolor[1],color[i][2]*lightcolor[2],1);
+                       }
+                       /*
+                       if(type[i]==snowsprite){
+                       glRotatef(rotation[i],0,0,1);
+                       glTranslatef(1,0,0);
+                       }*/
+
+                       glBegin(GL_TRIANGLES);
+                       glTexCoord2f(1.0f, 1.0f); glVertex3f( .5*size[i], .5*size[i], 0.0f);
+                       glTexCoord2f(0.0f, 1.0f); glVertex3f(-.5*size[i], .5*size[i], 0.0f);
+                       glTexCoord2f(1.0f, 0.0f); glVertex3f( .5*size[i],-.5*size[i], 0.0f);
+                       glTexCoord2f(0.0f, 0.0f); glVertex3f(-.5*size[i],-.5*size[i], 0.0f);
+                       glTexCoord2f(1.0f, 0.0f); glVertex3f( .5*size[i], -.5*size[i], 0.0f);
+                       glTexCoord2f(0.0f, 1.0f); glVertex3f(-.5*size[i], .5*size[i], 0.0f);
+                       glEnd();
+               glPopMatrix();
+       }
+       tempmult=multiplier;
+       for(i=numsprites-1;i>=0;i--){
+               multiplier=tempmult;
+               if(type[i]!=snowsprite)position[i]+=velocity[i]*multiplier;
+               if(type[i]!=snowsprite)velocity[i]+=windvector*multiplier;
+               if(type[i]==flamesprite||type[i]==smoketype)position[i]+=windvector*multiplier/2;
+               if((type[i]==flamesprite||type[i]==weaponflamesprite||type[i]==weaponshinesprite||type[i]==bloodflamesprite))multiplier*=speed[i]*.7;
+               alivetime[i]+=multiplier;
+
+               if(type[i]==cloudsprite||type[i]==cloudimpactsprite){
+                       opacity[i]-=multiplier/2;
+                       size[i]+=multiplier/2;
+                       velocity[i].y+=gravity*multiplier*.25;
+               }
+               if(type[i]==breathsprite){
+                       opacity[i]-=multiplier/2;
+                       size[i]+=multiplier/2;
+                       if(findLength(&velocity[i])<=multiplier)velocity[i]=0;
+                       else{
+                               XYZ slowdown;
+                               slowdown=velocity[i]*-1;
+                               Normalise(&slowdown);
+                               slowdown*=multiplier;
+                               velocity[i]+=slowdown;
+                       }
+               }
+               if(type[i]==snowsprite){
+                       size[i]-=multiplier/120;
+                       rotation[i]+=multiplier*360;
+                       position[i].y-=multiplier;
+                       position[i]+=windvector*multiplier;
+                       if(position[i].y<tempviewer.y-6)position[i].y+=12;
+                       if(position[i].y>tempviewer.y+6)position[i].y-=12;
+                       if(position[i].z<tempviewer.z-6)position[i].z+=12;
+                       if(position[i].z>tempviewer.z+6)position[i].z-=12;
+                       if(position[i].x<tempviewer.x-6)position[i].x+=12;
+                       if(position[i].x>tempviewer.x+6)position[i].x-=12;
+               }
+               if(type[i]==bloodsprite){
+                       bool spritehit=0;
+                       rotation[i]+=multiplier*100;
+                       velocity[i].y+=gravity*multiplier;
+                       if(check){
+                               XYZ where,startpoint,endpoint,movepoint,footpoint;
+                               float rotationpoint;
+                               int whichtri;
+
+                               for(j=0;j<numplayers;j++){
+                                       if(!spritehit&&player[j].dead&&alivetime[i]>.1){
+                                               where=oldposition[i];
+                                               where-=player[j].coords;
+                                               if(!player[j].skeleton.free)where=DoRotation(where,0,-player[j].rotation,0);
+                                               startpoint=where;
+                                               where=position[i];
+                                               where-=player[j].coords;
+                                               if(!player[j].skeleton.free)where=DoRotation(where,0,-player[j].rotation,0);
+                                               endpoint=where;
+
+                                               movepoint=0;
+                                               rotationpoint=0;
+                                               whichtri=player[j].skeleton.drawmodel.LineCheck(&startpoint,&endpoint, &footpoint, &movepoint, &rotationpoint);
+                                               if(whichtri!=-1){
+                                                       spritehit=1;
+                                                       player[j].DoBloodBigWhere(0,160,oldposition[i]);
+                                                       DeleteSprite(i);
+                                               }
+                                       }
+                               }
+
+                               whichpatchx=position[i].x/(terrain.size/subdivision*terrain.scale*terraindetail);
+                               whichpatchz=position[i].z/(terrain.size/subdivision*terrain.scale*terraindetail);
+                               if(whichpatchx>0&&whichpatchz>0&&whichpatchx<subdivision&&whichpatchz<subdivision)
+                                       if(terrain.patchobjectnum[whichpatchx][whichpatchz]){
+                                               if(!spritehit)
+                                                       for(j=0;j<terrain.patchobjectnum[whichpatchx][whichpatchz];j++){
+                                                               k=terrain.patchobjects[whichpatchx][whichpatchz][j];
+                                                               start=oldposition[i];
+                                                               end=position[i];
+                                                               if(!spritehit)
+                                                                       if(objects.model[k].LineCheck(&start,&end,&colpoint,&objects.position[k],&objects.rotation[k])!=-1){
+                                                                               if(detail==2||(detail==1&&abs(Random()%4)==0)||(detail==0&&abs(Random()%8)==0))objects.model[k].MakeDecal(blooddecalfast,DoRotation(colpoint-objects.position[k],0,-objects.rotation[k],0),size[i]*1.6/*+abs((float)(Random()%100))/2400*/,.5,Random()%360);
+                                                                               DeleteSprite(i);
+                                                                               spritehit=1;
+                                                                       }       
+                                                       }
+                                       }
+                                       if(!spritehit)
+                                               if(position[i].y<terrain.getHeight(position[i].x,position[i].z)){
+                                                       terrain.MakeDecal(blooddecalfast,position[i],size[i]*1.6/*+abs((float)(Random()%100))/2400*/,.6,Random()%360);
+                                                       DeleteSprite(i);
+                                               }
+                       }
+               }
+               if(type[i]==splintersprite){
+                       rotation[i]+=rotatespeed[i]*multiplier;
+                       opacity[i]-=multiplier/2;
+                       if(special[i]==0||special[i]==2||special[i]==3)velocity[i].y+=gravity*multiplier;
+                       if(special[i]==1)velocity[i].y+=gravity*multiplier*.5;
+               }
+               if(type[i]==flamesprite||type[i]==weaponflamesprite||type[i]==weaponshinesprite||type[i]==bloodflamesprite){
+                       rotation[i]+=multiplier*rotatespeed[i];
+                       opacity[i]-=multiplier*5/4;
+                       if(type[i]!=weaponshinesprite&&type[i]!=bloodflamesprite)
+                               if(opacity[i]<.5&&opacity[i]+multiplier*5/4>=.5&&(abs(Random()%4)==0||(initialsize[i]>2&&Random()%2==0)))MakeSprite(smoketype, position[i],velocity[i], .9,.9,.6, size[i]*1.2, .4);
+                       if(alivetime[i]>.14&&(type[i]==flamesprite)){
+                               velocity[i]=0;
+                               velocity[i].y=1.5;
+                       }
+               }
+               /*if(type[i]==smoketype){
+               opacity[i]-=multiplier/3/initialsize[i];
+               size[i]+=multiplier;
+               velocity[i]=0;
+               velocity[i].y=1.5;
+               rotation[i]+=multiplier*rotatespeed[i]/5;
+               }*/
+               if(type[i]==smoketype){
+                       opacity[i]-=multiplier/3/initialsize[i];
+                       color[i][0]-=multiplier;
+                       color[i][1]-=multiplier;
+                       color[i][2]-=multiplier;
+                       if(color[i][0]<.6)color[i][0]=.6;
+                       if(color[i][1]<.6)color[i][1]=.6;
+                       if(color[i][2]<.6)color[i][2]=.6;
+                       size[i]+=multiplier;
+                       velocity[i]=0;
+                       velocity[i].y=1.5;
+                       rotation[i]+=multiplier*rotatespeed[i]/5;
+               }
+               if(opacity[i]<=0||size[i]<=0)DeleteSprite(i);
+       }
+       if(check)
+               for(i=numsprites-1;i>=0;i--){
+                       oldposition[i]=position[i];
+               }
+               glAlphaFunc(GL_GREATER, 0.0001);
+               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+}
+
+void Sprites::DeleteSprite(int which)
+{
+       type[which]=type[numsprites-1];
+       rotation[which]=rotation[numsprites-1];
+       alivetime[which]=alivetime[numsprites-1];
+       opacity[which]=opacity[numsprites-1];
+       position[which]=position[numsprites-1];
+       velocity[which]=velocity[numsprites-1];
+       size[which]=size[numsprites-1];
+       speed[which]=speed[numsprites-1];
+       special[which]=special[numsprites-1];
+       color[which][0]=color[numsprites-1][0];
+       color[which][1]=color[numsprites-1][1];
+       color[which][2]=color[numsprites-1][2];
+       numsprites--;
+}
+
+void Sprites::MakeSprite(int atype, XYZ where, XYZ avelocity, float red, float green, float blue, float asize, float aopacity){
+       if(numsprites<max_sprites-1){
+               if((atype!=bloodsprite&&atype!=bloodflamesprite)||bloodtoggle){
+                       special[numsprites]=0;
+                       type[numsprites]=atype;
+                       position[numsprites]=where;
+                       oldposition[numsprites]=where;
+                       velocity[numsprites]=avelocity;
+                       alivetime[numsprites]=0;
+                       opacity[numsprites]=aopacity;
+                       size[numsprites]=asize;
+                       initialsize[numsprites]=asize;
+                       color[numsprites][0]=red;
+                       color[numsprites][1]=green;
+                       color[numsprites][2]=blue;
+                       rotatespeed[numsprites]=abs(Random()%720)-360;
+                       speed[numsprites]=float(abs(Random()%100))/200+1.5;
+               }               
+               numsprites++;
+       }
+}
+
+Sprites::Sprites()
+{
+       cloudtexture = 0;
+       cloudimpacttexture = 0;
+       bloodtexture = 0;
+       flametexture = 0;
+       bloodflametexture = 0;
+       smoketexture = 0;
+       snowflaketexture = 0;
+       shinetexture = 0;
+       splintertexture = 0;
+       leaftexture = 0;
+       toothtexture = 0;
+
+       memset(oldposition, 0, sizeof(oldposition));
+       memset(position, 0, sizeof(position));
+       memset(velocity, 0, sizeof(velocity));
+       memset(size, 0, sizeof(size));
+       memset(initialsize, 0, sizeof(initialsize));
+       memset(type, 0, sizeof(type));
+       memset(special, 0, sizeof(special));
+       memset(color, 0, sizeof(color));
+       memset(opacity, 0, sizeof(opacity));
+       memset(rotation, 0, sizeof(rotation));
+       memset(alivetime, 0, sizeof(alivetime));
+       memset(speed, 0, sizeof(speed));
+       memset(rotatespeed, 0, sizeof(rotatespeed));
+
+       checkdelay = 0;
+       numsprites = 0;
+}
+Sprites::~Sprites()
+{
+       if (toothtexture) glDeleteTextures( 1, (const unsigned long *)&toothtexture );
+       if (cloudtexture) glDeleteTextures( 1, (const unsigned long *)&cloudtexture );
+       if (cloudimpacttexture) glDeleteTextures( 1, (const unsigned long *)&cloudimpacttexture );
+       if (bloodtexture) glDeleteTextures( 1, (const unsigned long *)&bloodtexture );
+       if (flametexture) glDeleteTextures( 1, (const unsigned long *)&flametexture );
+       if (bloodflametexture) glDeleteTextures( 1, (const unsigned long *)&bloodflametexture );
+       if (smoketexture) glDeleteTextures( 1, (const unsigned long *)&smoketexture );
+       if (snowflaketexture) glDeleteTextures( 1, (const unsigned long *)&snowflaketexture );
+       if (shinetexture) glDeleteTextures( 1, (const unsigned long *)&shinetexture );
+       if (splintertexture) glDeleteTextures( 1, (const unsigned long *)&splintertexture );
+       if (leaftexture) glDeleteTextures( 1, (const unsigned long *)&leaftexture );
+}
diff --git a/Source/Sprites.h b/Source/Sprites.h
new file mode 100644 (file)
index 0000000..191075e
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef _SPRITES_H_
+#define _SPRITES_H_
+
+#include "Quaternions.h"
+#include "gl.h"
+#include "TGALoader.h"
+#include "Quaternions.h"
+#include "Frustum.h"
+#include "Lights.h"
+#include "Terrain.h"
+#include "Objects.h"
+//
+// Model Structures
+//
+
+#define max_sprites 20000
+
+#define cloudsprite 0
+#define bloodsprite 1
+#define flamesprite 2
+#define smoketype 3
+#define weaponflamesprite 4
+#define cloudimpactsprite 5
+#define snowsprite 6
+#define weaponshinesprite 7
+#define bloodflamesprite 8
+#define breathsprite 9
+#define splintersprite 10
+
+class Sprites{
+public:
+       GLuint cloudtexture;
+       GLuint cloudimpacttexture;
+       GLuint bloodtexture;
+       GLuint flametexture;
+       GLuint bloodflametexture;
+       GLuint smoketexture;
+       GLuint snowflaketexture;
+       GLuint shinetexture;
+       GLuint splintertexture;
+       GLuint leaftexture;
+       GLuint toothtexture;
+
+       XYZ oldposition[max_sprites];
+       XYZ position[max_sprites];
+       XYZ velocity[max_sprites];
+       float size[max_sprites];
+       float initialsize[max_sprites];
+       int type[max_sprites];
+       int special[max_sprites];
+       float color[max_sprites][3];
+       float opacity[max_sprites];
+       float rotation[max_sprites];
+       float alivetime[max_sprites];
+       float speed[max_sprites];
+       float rotatespeed[max_sprites];
+       float checkdelay;
+       int numsprites;
+
+       void DeleteSprite(int which);
+       void MakeSprite(int atype, XYZ where, XYZ avelocity, float red, float green, float blue, float asize, float aopacity);
+       void Draw();
+
+       Sprites();
+       ~Sprites();
+};
+
+#endif
\ No newline at end of file
diff --git a/Source/TGALoader.cpp b/Source/TGALoader.cpp
new file mode 100644 (file)
index 0000000..8908282
--- /dev/null
@@ -0,0 +1,267 @@
+/**> HEADER FILES <**/
+#include "TGALoader.h"
+#include "Game.h"
+
+extern float texdetail;
+extern TGAImageRec texture;
+extern short vRefNum;
+extern long dirID;
+extern bool visibleloading;
+extern Game * pgame;
+extern int loadscreencolor;
+
+extern bool LoadImage(const char * fname, TGAImageRec & tex);
+/********************> LoadTGA() <*****/
+bool upload_image(const unsigned char* filePath, bool hasalpha)
+{
+       if(visibleloading){
+               loadscreencolor=1;
+               pgame->LoadingScreen();
+       }
+
+#ifdef WIN32
+
+       // for Windows, just use TGA loader for now
+       char fileName[ 256];
+       CopyPascalStringToC( filePath, fileName);
+/*
+       // change extension to .TGA
+       int len = strlen( fileName);
+       if (len > 3)
+       {
+               fileName[ len - 3] = 't';
+               fileName[ len - 2] = 'g';
+               fileName[ len - 1] = 'a';
+       }
+*/
+//     return (LoadTGA( fileName) != NULL);
+       return (LoadImage(fileName, texture));
+
+#else
+
+       OSStatus err;
+       ComponentResult cr;
+
+       /*FSRef fsref;
+       Boolean isdir;
+       err = FSPathMakeRef((const UInt8*)filePath, &fsref, &isdir);
+       if(err)return;
+
+       FSSpec fsspec;
+       err = FSGetCatalogInfo(&fsref, kFSCatInfoNone, NULL, NULL, &fsspec, NULL);
+       if(err)return;
+       */
+
+       //Boolean isdir;
+       FSSpec fsspec;
+       //err = FSMakeFSSpec (0, 0, (const unsigned char*)filePath, &fsspec);
+       err = FSMakeFSSpec (0, 0, filePath, &fsspec);
+       //err=FSPathMakeFSSpec((const UInt8*)filePath,&fsspec,&isdir);*/
+       if(err)return;
+
+       GraphicsImportComponent gi;
+       err = GetGraphicsImporterForFile(&fsspec, &gi);
+       if(err)return;
+
+       Rect natbounds;
+       cr = GraphicsImportGetNaturalBounds(gi, &natbounds);
+
+       size_t buffersize = 4 * natbounds.bottom * natbounds.right;
+       //void* buf = malloc(buffersize);
+       texture.sizeX=natbounds.right;
+       texture.sizeY=natbounds.bottom;
+       /*if(hasalpha)*/texture.bpp = 32;
+       //if(!hasalpha)texture.bpp = 24;
+
+       GWorldPtr gw;
+       err = QTNewGWorldFromPtr(&gw, k32ARGBPixelFormat, &natbounds, NULL, NULL,
+               0, texture.data, 4 * natbounds.right);
+       if(err)return;
+
+       cr = GraphicsImportSetGWorld(gi, gw, NULL);
+
+       natbounds.top = natbounds.bottom;
+       natbounds.bottom = 0;
+
+       cr = GraphicsImportSetBoundsRect(gi, &natbounds);
+
+       cr = GraphicsImportDraw(gi);
+
+       err = CloseComponent(gi);
+       if(err)return;
+
+       /*glTexImage2D(textureTarget, 0, GL_RGBA, natbounds.right, natbounds.top, 0,
+       GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buf);
+       */
+
+       //free(buf);
+       DisposeGWorld(gw);
+
+       // Loop Through The Image Data
+       GLuint                  imageSize;                                                                      // Used To Store The Image Size When Setting Aside Ram
+       GLuint                  temp;                                                                           // Temporary Variable
+       GLuint                  bytesPerPixel;                                                                          // Temporary Variable
+       bytesPerPixel=texture.bpp/8;
+       imageSize = texture.sizeX * texture.sizeY * bytesPerPixel;
+       int alltrans=10;
+
+       for( GLuint i = 0; i < int( imageSize ); i += 4 )
+       {
+               // Swaps The 1st And 3rd Bytes ('R'ed and 'B'lue)
+               temp = texture.data[i];                                 // Temporarily Store The Value At Image Data 'i'
+               texture.data[i] = texture.data[i + 1];  // Set The 1st Byte To The Value Of The 3rd Byte
+               texture.data[i + 1] = texture.data[i + 2];                              // Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
+               texture.data[i + 2] = texture.data[i + 3];
+               texture.data[i + 3] = temp;
+       }
+
+       int tempplace;
+       tempplace=0;
+       if(!hasalpha){
+               for( GLuint i = 0; i < int( imageSize ); i += 4 )
+               {
+                       texture.data[i + 3] = 255;
+                       /*texture.data[tempplace] = texture.data[i];    // Set The 1st Byte To The Value Of The 3rd Byte
+                       texture.data[tempplace + 1] = texture.data[i + 1];                              // Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
+                       texture.data[tempplace + 2] = texture.data[i + 2];
+                       tempplace+=3;*/
+               }
+       }
+
+       if(texdetail>1){
+               int which=0;
+               float temp;
+               float howmany;
+               for( GLuint k = 0; k < int( imageSize); k += bytesPerPixel*texture.sizeX*texdetail )
+               {
+                       for( GLuint i = 0; i < int( imageSize/texture.sizeY ); i += bytesPerPixel*texdetail )
+                       {
+                               for( GLuint b = 0; b < bytesPerPixel ; b ++ ){  
+                                       temp=0;
+                                       howmany=0;
+                                       for( GLuint l = 0; l < texdetail*texture.sizeX ; l +=texture.sizeX ){
+                                               for( GLuint j = 0; j < texdetail ; j ++ )
+                                               {
+                                                       temp += (int)texture.data[k+i+j*bytesPerPixel+l*bytesPerPixel+b];       // Set The 1st Byte To The Value Of The 3rd Byte
+                                                       howmany++;
+                                               }
+                                       }
+                                       texture.data[which+b]=GLubyte(temp/howmany);
+                               }
+                               which+=bytesPerPixel;
+                       }
+               }
+               texture.sizeX/=texdetail;
+               texture.sizeY/=texdetail;
+       }
+
+       return true;
+
+#endif
+}
+
+
+TGAImageRec*   LoadTGA( char *filename )
+{    
+       GLubyte                 TGAheader[12]={0,0,2,0,0,0,0,0,0,0,0,0};        // Uncompressed TGA Header
+       GLubyte                 TGAcompare[12];                                                         // Used To Compare TGA Header
+       GLubyte                 header[6];                                                                      // First 6 Useful Bytes From The Header
+       GLuint                  bytesPerPixel;                                                          // Holds Number Of Bytes Per Pixel Used In The TGA File
+       GLuint                  imageSize;                                                                      // Used To Store The Image Size When Setting Aside Ram
+       GLuint                  temp;                                                                           // Temporary Variable
+       GLuint                  type = GL_RGBA;                                                         // Set The Default GL Mode To RBGA (32 BPP)
+       //TGAImageRec           *texture;
+       FILE                    *file;
+
+       // Open The TGA File
+       file = fopen( filename, "rb" );
+
+       if( ( file == NULL ) || // Does File Even Exist?
+               ( fread( TGAcompare, 1, sizeof( TGAcompare ), file ) != sizeof( TGAcompare ) ) ||       // Are There 12 Bytes To Read?
+               ( memcmp( TGAheader, TGAcompare, sizeof( TGAheader ) ) != 0 ) ||        // Does The Header Match What We Want?
+               ( fread( header, 1, sizeof( header ), file ) != sizeof( header ) ) )// If So Read Next 6 Header Bytes
+       {
+               // If anything failed then close the file and return false
+               if (file) fclose( file );
+               return NULL;
+       }
+
+       // Create a new RGBAImageRec
+       //texture = ( TGAImageRec* )malloc( sizeof( TGAImageRec ) );
+
+       // Determine the TGA width (highbyte*256+lowbyte) and height (highbyte*256+lowbyte)
+       texture.sizeX  = (header[1] * 256 + header[0]);
+       texture.sizeY = (header[3] * 256 + header[2]);
+
+       // Make sure the height, width, and bit depth are valid
+       if(     ( texture.sizeX <= 0 ) || ( texture.sizeY <= 0 ) || ( ( header[4] != 24 ) && ( header[4] != 32 ) ) )
+       {
+               // If anything failed then close the file, free up memory for the image, and return NULL
+               fclose( file );
+               //free( texture );
+               return NULL;
+       }
+
+       // Grab The TGA's Bits Per Pixel (24 or 32)
+       texture.bpp = header[4];                                                        
+       bytesPerPixel = texture.bpp/8;  // Divide By 8 To Get The Bytes Per Pixel
+
+       // Calculate The Memory Required For The TGA Data
+       imageSize = texture.sizeX * texture.sizeY * bytesPerPixel;
+
+       // Reserve Memory To Hold The TGA Data
+       //texture.data = ( GLubyte* )malloc( imageSize );               
+
+       // Make sure the right amount of memory was allocated
+       if(     ( texture.data == NULL ) || ( fread( texture.data, 1, imageSize, file ) != imageSize ) )
+       {
+               // Free up the image data if there was any
+               //              if( texture.data != NULL )
+               //                      free( texture.data );
+
+               // If anything failed then close the file, free up memory for the image, and return NULL
+               fclose( file );
+               //              free( texture );
+               return NULL;
+       }
+
+       // Loop Through The Image Data
+       for( GLuint i = 0; i < int( imageSize ); i += bytesPerPixel )
+       {
+               // Swaps The 1st And 3rd Bytes ('R'ed and 'B'lue)
+               temp = texture.data[i];                                 // Temporarily Store The Value At Image Data 'i'
+               texture.data[i] = texture.data[i + 2];  // Set The 1st Byte To The Value Of The 3rd Byte
+               texture.data[i + 2] = temp;                             // Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
+       }
+
+       if(texdetail>1){
+               int which=0;
+               float temp;
+               float howmany;
+               for( GLuint k = 0; k < int( imageSize); k += bytesPerPixel*texture.sizeX*texdetail )
+               {
+                       for( GLuint i = 0; i < int( imageSize/texture.sizeY ); i += bytesPerPixel*texdetail )
+                       {
+                               for( GLuint b = 0; b < bytesPerPixel ; b ++ ){  
+                                       temp=0;
+                                       howmany=0;
+                                       for( GLuint l = 0; l < texdetail*texture.sizeX ; l +=texture.sizeX ){
+                                               for( GLuint j = 0; j < texdetail ; j ++ )
+                                               {
+                                                       temp += (int)texture.data[k+i+j*bytesPerPixel+l*bytesPerPixel+b];       // Set The 1st Byte To The Value Of The 3rd Byte
+                                                       howmany++;
+                                               }
+                                       }
+                                       texture.data[which+b]=GLubyte(temp/howmany);
+                               }
+                               which+=bytesPerPixel;
+                       }
+               }
+               texture.sizeX/=texdetail;
+               texture.sizeY/=texdetail;
+       }
+
+       // Close The File
+       fclose( file );
+       return &texture;
+}
\ No newline at end of file
diff --git a/Source/TGALoader.h b/Source/TGALoader.h
new file mode 100644 (file)
index 0000000..98ea07b
--- /dev/null
@@ -0,0 +1,40 @@
+#pragma once
+
+#ifndef        _TGA_LOADER_H_
+#define        _TGA_LOADER_H_
+
+
+/**> HEADER FILES <**/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#define Polygon WinPolygon
+#include <windows.h>
+#undef Polygon
+#include <gl/gl.h>
+#else
+#include "gl.h"
+//     #include "MoreFilesX.h"
+#endif
+
+//#include <stdbool.h>
+//#include <QuickTime.h>
+
+/**> DATA STRUCTURES <**/
+typedef struct TGAImageRec
+{
+       GLubyte *data;          // Image Data (Up To 32 Bits)
+       GLuint  bpp;            // Image Color Depth In Bits Per Pixel.
+       GLuint  sizeX;
+       GLuint  sizeY;
+}      TGAImageRec;
+
+bool upload_image(const unsigned char* filePath, bool hasalpha);
+
+/**> FUNCTION PROTOTYPES <**/
+TGAImageRec*   LoadTGA( char *filename );
+
+
+#endif
diff --git a/Source/Terrain.cpp b/Source/Terrain.cpp
new file mode 100644 (file)
index 0000000..4ed120b
--- /dev/null
@@ -0,0 +1,1540 @@
+#include "Terrain.h"
+#include "Objects.h"
+#include "Game.h"
+extern XYZ viewer;
+extern float viewdistance;
+extern float lightambient[3],lightbrightness[3];
+extern float fadestart;
+extern int environment;
+extern float texscale;
+extern Light light;
+extern float multiplier;
+extern FRUSTUM frustum;
+extern float texdetail,terraindetail;
+extern int detail;
+extern bool decals;
+extern float blurness;
+extern float targetblurness;
+extern Objects objects;
+extern TGAImageRec texture;
+extern Game * pgame;
+extern bool visibleloading;
+extern bool skyboxtexture;
+extern int tutoriallevel;
+
+//Functions
+
+int Terrain::lineTerrain(XYZ p1,XYZ p2, XYZ *p)
+{
+       static int i,j,k;
+       static float distance;
+       static float olddistance;
+       static int intersecting;
+       static int firstintersecting;
+       static XYZ point;
+       static int startx,starty;
+       static float slope;
+       static int endx,endy;
+       static int numtris=(size-1)*(size-1)*2;
+       static float highest,lowest;
+
+       firstintersecting=-1;
+       olddistance=10000;
+       distance=1;
+
+       XYZ triangles[3];
+
+       p1/=scale;
+       p2/=scale;
+
+       startx=p1.x;
+       starty=p1.z;
+       endx=p2.x;
+       endy=p2.z;
+
+       if(startx>endx){i=endx;endx=startx;startx=i;}
+       if(starty>endy){i=endy;endy=starty;starty=i;}
+
+       if(startx<0)startx=0;
+       if(starty<0)starty=0;
+       if(endx>size-1)endx=size-1;
+       if(endy>size-1)endy=size-1;
+
+       for(i=startx;i<=endx;i++){
+               for(j=starty;j<=endy;j++){
+                       highest=-1000;
+                       lowest=1000;
+                       for(k=0;k<2;k++){
+                               if(heightmap[i+k][j]>highest)highest=heightmap[i+k][j];
+                               if(heightmap[i+k][j]<lowest)lowest=heightmap[i+k][j];
+                               if(heightmap[i+k][j+1]>highest)highest=heightmap[i+k][j+1];
+                               if(heightmap[i+k][j+1]<lowest)lowest=heightmap[i+k][j+1];
+                       }
+                       if((p1.y<=highest||p2.y<=highest)&&(p1.y>=lowest||p2.y>=lowest)){
+                               triangles[0].x=i;
+                               triangles[0].y=heightmap[i][j];
+                               triangles[0].z=j;
+
+                               triangles[1].x=i;
+                               triangles[1].y=heightmap[i][j+1];
+                               triangles[1].z=j+1;
+
+                               triangles[2].x=i+1;
+                               triangles[2].y=heightmap[i+1][j];
+                               triangles[2].z=j;
+
+                               intersecting=LineFacet(p1,p2,triangles[0],triangles[1],triangles[2],&point);
+                               distance=findDistancefast(&p1,&point);
+                               if((distance<olddistance||firstintersecting==-1)&&intersecting==1){olddistance=distance; firstintersecting=1; *p=point;}
+
+                               triangles[0].x=i+1;
+                               triangles[0].y=heightmap[i+1][j];
+                               triangles[0].z=j;
+
+                               triangles[1].x=i;
+                               triangles[1].y=heightmap[i][j+1];
+                               triangles[1].z=j+1;
+
+                               triangles[2].x=i+1;
+                               triangles[2].y=heightmap[i+1][j+1];
+                               triangles[2].z=j+1;
+
+                               intersecting=LineFacet(p1,p2,triangles[0],triangles[1],triangles[2],&point);
+                               distance=findDistancefast(&p1,&point);
+                               if((distance<olddistance||firstintersecting==-1)&&intersecting==1){olddistance=distance; firstintersecting=1; *p=point;}
+                       }
+               }
+       }
+       return firstintersecting;
+}
+
+void Terrain::UpdateTransparency(int whichx, int whichy){
+       static XYZ vertex;
+       static int i,j,a,b,c,d,patch_size,stepsize;
+       static float distance;
+
+       static float viewdistsquared;
+
+       viewdistsquared=viewdistance*viewdistance;
+       patch_size=size/subdivision;
+
+       stepsize=1;
+       c=whichx*patch_elements+whichy*patch_elements*subdivision;
+
+       for(i=patch_size*whichx;i<patch_size*(whichx+1)+1;i+=stepsize){
+               for(j=patch_size*whichy;j<patch_size*(whichy+1)+1;j+=stepsize){
+                       if(i<size&&j<size){
+                               vertex.x=i*scale;
+                               vertex.z=j*scale;
+                               vertex.y=heightmap[i][j]*scale;
+                               distance=findDistancefast(&viewer,&vertex);
+                               if(distance>viewdistsquared)distance=viewdistsquared;
+                               colors[i][j][3]=(viewdistsquared-(distance-(viewdistsquared*fadestart))*(1/(1-fadestart)))/viewdistsquared;
+                       }
+               }
+       }
+
+       for(i=patch_size*whichx;i<patch_size*(whichx+1);i+=stepsize){
+               for(j=patch_size*whichy;j<patch_size*(whichy+1);j+=stepsize){
+                       a=(i-(patch_size*whichx))/stepsize;
+                       b=(j-(patch_size*whichy))/stepsize;
+                       d=(a*54)+(b*54*patch_size/stepsize);
+                       vArray[d+c+6]=colors[i][j][3];
+
+                       vArray[d+c+15]=colors[i][j+stepsize][3];
+
+                       vArray[d+c+24]=colors[i+stepsize][j][3];
+
+                       vArray[d+c+33]=colors[i+stepsize][j][3];
+
+                       vArray[d+c+42]=colors[i][j+stepsize][3];
+
+                       vArray[d+c+51]=colors[i+stepsize][j+stepsize][3];
+               }
+       }
+}
+
+void Terrain::UpdateTransparencyother(int whichx, int whichy){
+       static XYZ vertex;
+       static int i,j,a,b,c,d,patch_size,stepsize;
+       static float distance;
+
+       patch_size=size/subdivision;
+
+       stepsize=1;
+       c=whichx*patch_elements+whichy*patch_elements*subdivision;
+
+       for(i=patch_size*whichx;i<patch_size*(whichx+1);i+=stepsize){
+               for(j=patch_size*whichy;j<patch_size*(whichy+1);j+=stepsize){
+                       a=(i-(patch_size*whichx))/stepsize;
+                       b=(j-(patch_size*whichy))/stepsize;
+                       d=(a*54)+(b*54*patch_size/stepsize);
+                       vArray[d+c+6]=colors[i][j][3]*opacityother[i][j];
+
+                       vArray[d+c+15]=colors[i][j+stepsize][3]*opacityother[i][j+stepsize];
+
+                       vArray[d+c+24]=colors[i+stepsize][j][3]*opacityother[i+stepsize][j];
+
+                       vArray[d+c+33]=colors[i+stepsize][j][3]*opacityother[i+stepsize][j];
+
+                       vArray[d+c+42]=colors[i][j+stepsize][3]*opacityother[i][j+stepsize];
+
+                       vArray[d+c+51]=colors[i+stepsize][j+stepsize][3]*opacityother[i+stepsize][j+stepsize];
+               }
+       }
+}
+
+void Terrain::UpdateTransparencyotherother(int whichx, int whichy){
+       static XYZ vertex;
+       static int i,j,a,b,c,d,patch_size,stepsize;
+       static float distance;
+
+       static float viewdistsquared;
+
+       viewdistsquared=viewdistance*viewdistance;
+       patch_size=size/subdivision;
+
+       stepsize=1;
+       c=whichx*patch_elements+whichy*patch_elements*subdivision;
+
+       for(i=patch_size*whichx;i<patch_size*(whichx+1)+1;i+=stepsize){
+               for(j=patch_size*whichy;j<patch_size*(whichy+1)+1;j+=stepsize){
+                       if(i<size&&j<size){
+                               vertex.x=i*scale;
+                               vertex.z=j*scale;
+                               vertex.y=heightmap[i][j]*scale;
+                               distance=findDistancefast(&viewer,&vertex);
+                               if(distance>viewdistsquared)distance=viewdistsquared;
+                               colors[i][j][3]=(viewdistsquared-(distance-(viewdistsquared*fadestart))*(1/(1-fadestart)))/viewdistsquared;
+                       }
+               }
+       }
+
+       for(i=patch_size*whichx;i<patch_size*(whichx+1);i+=stepsize){
+               for(j=patch_size*whichy;j<patch_size*(whichy+1);j+=stepsize){
+                       a=(i-(patch_size*whichx))/stepsize;
+                       b=(j-(patch_size*whichy))/stepsize;
+                       d=(a*54)+(b*54*patch_size/stepsize);
+                       vArray[d+c+6]=colors[i][j][3];
+
+                       vArray[d+c+15]=colors[i][j+stepsize][3];
+
+                       vArray[d+c+24]=colors[i+stepsize][j][3];
+
+                       vArray[d+c+33]=colors[i+stepsize][j][3];
+
+                       vArray[d+c+42]=colors[i][j+stepsize][3];
+
+                       vArray[d+c+51]=colors[i+stepsize][j+stepsize][3];
+               }
+       }
+}
+
+void Terrain::UpdateVertexArray(int whichx, int whichy){
+       static int i,j,a,b,c,patch_size,stepsize;
+
+
+       numtris[whichx][whichy]=0;
+
+       patch_size=size/subdivision;
+
+       stepsize=1;
+       c=whichx*patch_elements+whichy*patch_elements*subdivision;
+       for(i=patch_size*whichx;i<patch_size*(whichx+1);i+=stepsize){
+               for(j=patch_size*whichy;j<patch_size*(whichy+1);j+=stepsize){
+                       a=(i-((float)size/subdivision*(float)whichx))/stepsize;
+                       b=(j-((float)size/subdivision*(float)whichy))/stepsize;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+0]=i*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+1]=heightmap[i][j]*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+2]=j*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+3]=colors[i][j][0];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+4]=colors[i][j][1];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+5]=colors[i][j][2];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+6]=colors[i][j][3];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+7]=i*scale*texscale+texoffsetx[i][j];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+8]=j*scale*texscale+texoffsety[i][j];
+
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+9]=i*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+10]=heightmap[i][j+stepsize]*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+11]=j*scale+stepsize*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+12]=colors[i][j+stepsize][0];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+13]=colors[i][j+stepsize][1];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+14]=colors[i][j+stepsize][2];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+15]=colors[i][j+stepsize][3];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+16]=i*scale*texscale+texoffsetx[i][j+stepsize];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+17]=j*scale*texscale+stepsize*scale*texscale+texoffsety[i][j+stepsize];
+
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+18]=i*scale+stepsize*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+19]=heightmap[i+stepsize][j]*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+20]=j*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+21]=colors[i+stepsize][j][0];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+22]=colors[i+stepsize][j][1];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+23]=colors[i+stepsize][j][2];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+24]=colors[i+stepsize][j][3];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+25]=i*scale*texscale+stepsize*scale*texscale+texoffsetx[i+stepsize][j];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+26]=j*scale*texscale+texoffsety[i+stepsize][j];
+
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+27]=i*scale+stepsize*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+28]=heightmap[i+stepsize][j]*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+29]=j*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+30]=colors[i+stepsize][j][0];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+31]=colors[i+stepsize][j][1];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+32]=colors[i+stepsize][j][2];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+33]=colors[i+stepsize][j][3];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+34]=i*scale*texscale+stepsize*scale*texscale+texoffsetx[i+stepsize][j];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+35]=j*scale*texscale+texoffsety[i+stepsize][j];
+
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+36]=i*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+37]=heightmap[i][j+stepsize]*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+38]=j*scale+stepsize*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+39]=colors[i][j+stepsize][0];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+40]=colors[i][j+stepsize][1];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+41]=colors[i][j+stepsize][2];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+42]=colors[i][j+stepsize][3];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+43]=i*scale*texscale+texoffsetx[i][j+stepsize];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+44]=j*scale*texscale+stepsize*scale*texscale+texoffsety[i][j+stepsize];
+
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+45]=i*scale+stepsize*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+46]=heightmap[i+stepsize][j+stepsize]*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+47]=j*scale+stepsize*scale;
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+48]=colors[i+stepsize][j+stepsize][0];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+49]=colors[i+stepsize][j+stepsize][1];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+50]=colors[i+stepsize][j+stepsize][2];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+51]=colors[i+stepsize][j+stepsize][3];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+52]=i*scale*texscale+stepsize*scale*texscale+texoffsetx[i+stepsize][j+stepsize];
+                       vArray[(a*54)+(b*54*patch_size/stepsize)+c+53]=j*scale*texscale+stepsize*scale*texscale+texoffsety[i+stepsize][j+stepsize];
+                       numtris[whichx][whichy]+=2;
+               }
+       }
+
+       maxypatch[whichx][whichy]=-10000;
+       minypatch[whichx][whichy]=10000;
+       for(a=0;a<size/subdivision;a++){
+               for(b=0;b<size/subdivision;b++){
+                       if(heightmap[(size/subdivision)*whichx+a][(size/subdivision)*whichy+b]*scale>maxypatch[whichx][whichy]) maxypatch[whichx][whichy]=heightmap[(size/subdivision)*whichx+a][(size/subdivision)*whichy+b]*scale;
+                       if(heightmap[(size/subdivision)*whichx+a][(size/subdivision)*whichy+b]*scale<minypatch[whichx][whichy]) minypatch[whichx][whichy]=heightmap[(size/subdivision)*whichx+a][(size/subdivision)*whichy+b]*scale;
+               }
+       }
+       heightypatch[whichx][whichy]=(maxypatch[whichx][whichy]-minypatch[whichx][whichy]);
+       if(heightypatch[whichx][whichy]<size/subdivision*scale)heightypatch[whichx][whichy]=size/subdivision*scale;
+       avgypatch[whichx][whichy]=(minypatch[whichx][whichy]+maxypatch[whichx][whichy])/2;
+
+       for(i=whichx*size/subdivision;i<(whichx+1)*size/subdivision-1;i++){
+               for(j=whichy*size/subdivision;j<(whichy+1)*size/subdivision-1;j++){
+                       triangles[(i*(size-1)*2)+(j*2)][0].x=i*scale;
+                       triangles[(i*(size-1)*2)+(j*2)][0].y=heightmap[i][j]*scale;
+                       triangles[(i*(size-1)*2)+(j*2)][0].z=j*scale;
+
+                       triangles[(i*(size-1)*2)+(j*2)][1].x=i*scale;
+                       triangles[(i*(size-1)*2)+(j*2)][1].y=heightmap[i][j+1]*scale;
+                       triangles[(i*(size-1)*2)+(j*2)][1].z=j*scale+scale;
+
+                       triangles[(i*(size-1)*2)+(j*2)][2].x=i*scale+1*scale;
+                       triangles[(i*(size-1)*2)+(j*2)][2].y=heightmap[i+1][j]*scale;
+                       triangles[(i*(size-1)*2)+(j*2)][2].z=j*scale;
+
+                       triangles[(i*(size-1)*2)+(j*2)+1][0].x=i*scale+1*scale;
+                       triangles[(i*(size-1)*2)+(j*2)+1][0].y=heightmap[i+1][j]*scale;
+                       triangles[(i*(size-1)*2)+(j*2)+1][0].z=j*scale;
+
+                       triangles[(i*(size-1)*2)+(j*2)+1][1].x=i*scale;
+                       triangles[(i*(size-1)*2)+(j*2)+1][1].y=heightmap[i][j+1]*scale;
+                       triangles[(i*(size-1)*2)+(j*2)+1][1].z=j*scale+1*scale;
+
+                       triangles[(i*(size-1)*2)+(j*2)+1][2].x=i*scale+1*scale;
+                       triangles[(i*(size-1)*2)+(j*2)+1][2].y=heightmap[i+1][j+1]*scale;
+                       triangles[(i*(size-1)*2)+(j*2)+1][2].z=j*scale+1*scale;
+               }
+       }
+
+}
+
+
+bool Terrain::load(char *fileName)
+{
+       static long                             i,j;
+       static long x,y;
+       static float patch_size;
+
+       float temptexdetail=texdetail;
+       texdetail=terraindetail;
+       //LoadTGA( fileName );
+       unsigned char fileNamep[256];
+       CopyCStringToPascal(fileName,fileNamep);
+       //Load Image
+       upload_image( fileNamep ,0); 
+
+       //Is it valid?
+       if(texture.bpp>24){
+               int bytesPerPixel=texture.bpp/8;
+
+               int tempnum=0;
+               for(i=0;i<(long)(texture.sizeY*texture.sizeX*bytesPerPixel);i++){
+                       if((i+1)%4){
+                               texture.data[tempnum]=texture.data[i];
+                               tempnum++;
+                       }
+               }
+       }
+       texture.bpp=24;
+       if(visibleloading)pgame->LoadingScreen();
+
+       texdetail=temptexdetail;
+
+       size=128;
+       if(1==1){
+               /*if ( texture.bpp == 24 )
+               type = GL_RGB;
+               else
+               type = GL_RGBA;
+
+               glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+               if(!terraintexture)glGenTextures( 1, &terraintexture );
+               glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+               glBindTexture( GL_TEXTURE_2D, terraintexture);
+               //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+
+               gluBuild2DMipmaps( GL_TEXTURE_2D, type, texture.sizeX, texture.sizeY, type, GL_UNSIGNED_BYTE, texture.data );
+               */
+
+               size=texture.sizeX;
+
+               for(i=0;i<size;i++){
+                       for(j=0;j<size;j++){
+                               heightmap[size-1-i][j]=(float)((texture.data[(i+(j*size))*texture.bpp/8]))/5/terraindetail;
+                       }
+               }
+
+       }
+       if(visibleloading)pgame->LoadingScreen();
+
+       float slopeness;
+
+       for(i=0;i<subdivision;i++){
+               for(j=0;j<subdivision;j++){
+                       textureness[i][j]=-1;
+               }
+       }
+       if(visibleloading)pgame->LoadingScreen();
+
+
+       for(i=0;i<size;i++){
+               for(j=0;j<size;j++){
+                       heightmap[i][j]*=.5;
+
+                       texoffsetx[i][j]=(float)abs(Random()%100)/1200/scale*3;
+                       texoffsety[i][j]=(float)abs(Random()%100)/1200/scale*3;
+
+                       slopeness=0;
+                       if(environment==snowyenvironment){
+                               if(j!=0&&heightmap[i][j]-heightmap[i][j-1]>slopeness){          slopeness=heightmap[i][j]-heightmap[i][j-1];}
+                               opacityother[i][j]=slopeness*slopeness*2;
+                               if(opacityother[i][j]>1)opacityother[i][j]=1;
+                               opacityother[i][j]-=(float)abs(Random()%100)/300;
+                       }
+                       if(environment==desertenvironment){
+                               if(j!=0&&heightmap[i][j]-heightmap[i][j-1]>slopeness){          slopeness=heightmap[i][j]-heightmap[i][j-1];}
+                               opacityother[i][j]=slopeness*slopeness*2;
+                               if(opacityother[i][j]>1)opacityother[i][j]=1;
+                               opacityother[i][j]-=(float)abs(Random()%100)/300;
+                       }
+                       if(environment==grassyenvironment){
+                               if(i!=0&&heightmap[i][j]-heightmap[i-1][j]>slopeness){          slopeness=heightmap[i][j]-heightmap[i-1][j];}
+                               if(j!=0&&heightmap[i][j]-heightmap[i][j-1]>slopeness){          slopeness=heightmap[i][j]-heightmap[i][j-1];}
+                               if(i<size-1&&heightmap[i][j]-heightmap[i+1][j]>slopeness){              slopeness=heightmap[i][j]-heightmap[i+1][j];}
+                               if(j<size-1&&heightmap[i][j]-heightmap[i][j+1]>slopeness){              slopeness=heightmap[i][j]-heightmap[i][j+1];}
+                               opacityother[i][j]=slopeness*slopeness*10;
+                               if(opacityother[i][j]>1)opacityother[i][j]=1;
+                               opacityother[i][j]-=(float)abs(Random()%100)/100;
+                       }
+               }
+       }
+       if(visibleloading)pgame->LoadingScreen();
+
+       for(i=0;i<size;i++){
+               for(j=0;j<size;j++){
+                       if(environment==snowyenvironment){
+                               heightmap[i][j]-=opacityother[i][j];
+                       }
+                       if(environment==desertenvironment){
+                               heightmap[i][j]-=opacityother[i][j];
+                       }
+               }
+       }
+       if(visibleloading)pgame->LoadingScreen();
+
+       /*float total;
+       int todivide;
+       //Smooth opacityother
+       for(i=0;i<size;i++){
+       for(j=0;j<size;j++){
+       total=0;
+       todivide=0;
+       if(i!=0){                               total+=opacityother[j][i-1]; todivide++;}
+       if(i!=size-1){                          total+=opacityother[j][i+1]; todivide++;}
+       if(j!=0){                               total+=opacityother[j-1][i]; todivide++;}
+       if(j!=size-1){                          total+=opacityother[j+1][i]; todivide++;}
+       if(i!=0&&j!=0){                 total+=opacityother[j-1][i-1]; todivide++;}
+       if(i!=size-1&&j!=0){            total+=opacityother[j-1][i+1]; todivide++;}
+       if(j!=size-1&&i!=size-1){               total+=opacityother[j+1][i+1]; todivide++;}
+       if(j!=size-1&&i!=0){            total+=opacityother[j+1][i-1]; todivide++;}
+       total+=opacityother[j][i]; todivide++;
+
+       opacityother[j][i]=total/(float)todivide;
+       }
+       }*/
+
+
+       for(i=0;i<size;i++){
+               for(j=0;j<size;j++){
+                       if(opacityother[i][j]<.1)opacityother[i][j]=0;
+                       if(textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==-1){
+                               if(!opacityother[i][j])textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=allfirst;
+                               if(opacityother[i][j]==1)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=allsecond;
+                       }
+                       if(opacityother[i][j]&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allfirst)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                       if(opacityother[i][j]!=1&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allsecond)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+
+                       x=i;
+                       y=j;
+                       if(i>0){
+                               i--;
+                               if(opacityother[x][y]&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allfirst)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                               if(opacityother[x][y]!=1&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allsecond)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                               if(opacityother[i][j]&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allfirst)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+                               if(opacityother[i][j]!=1&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allsecond)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+
+                               if(j>0){
+                                       j--;
+                                       if(opacityother[x][y]&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allfirst)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                                       if(opacityother[x][y]!=1&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allsecond)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                                       if(opacityother[i][j]&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allfirst)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+                                       if(opacityother[i][j]!=1&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allsecond)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+                                       j++;
+                               }
+
+                               if(j<size-1){
+                                       j++;
+                                       if(opacityother[x][y]&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allfirst)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                                       if(opacityother[x][y]!=1&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allsecond)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                                       if(opacityother[i][j]&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allfirst)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+                                       if(opacityother[i][j]!=1&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allsecond)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+                                       j--;
+                               }
+                               i++;
+                       }
+
+                       if(i<size-1){
+                               i++;
+                               if(opacityother[x][y]&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allfirst)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                               if(opacityother[x][y]!=1&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allsecond)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                               if(opacityother[i][j]&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allfirst)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+                               if(opacityother[i][j]!=1&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allsecond)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+
+                               if(j>0){
+                                       j--;
+                                       if(opacityother[x][y]&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allfirst)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                                       if(opacityother[x][y]!=1&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allsecond)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                                       if(opacityother[i][j]&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allfirst)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+                                       if(opacityother[i][j]!=1&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allsecond)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+                                       j++;
+                               }
+
+                               if(j<size-1){
+                                       j++;
+                                       if(opacityother[x][y]&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allfirst)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                                       if(opacityother[x][y]!=1&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allsecond)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                                       if(opacityother[i][j]&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allfirst)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+                                       if(opacityother[i][j]!=1&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allsecond)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+                                       j--;
+                               }
+                               i--;
+                       }
+
+                       if(j>0){
+                               j--;
+                               if(opacityother[x][y]&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allfirst)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                               if(opacityother[x][y]!=1&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allsecond)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                               if(opacityother[i][j]&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allfirst)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+                               if(opacityother[i][j]!=1&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allsecond)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+                               j++;
+                       }
+
+                       if(j<size-1){
+                               j++;
+                               if(opacityother[x][y]&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allfirst)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                               if(opacityother[x][y]!=1&&textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]==allsecond)textureness[(int)(i*subdivision/size)][(int)(j*subdivision/size)]=mixed;
+                               if(opacityother[i][j]&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allfirst)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+                               if(opacityother[i][j]!=1&&textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]==allsecond)textureness[(int)(x*subdivision/size)][(int)(y*subdivision/size)]=mixed;
+                               j--;
+
+                       }
+               }
+       }
+       if(visibleloading)pgame->LoadingScreen();
+
+       patch_size=size/subdivision;
+       patch_elements=(patch_size)*(patch_size)*54;
+       CalculateNormals();
+       /*DoShadows();
+
+       for(i=0;i<subdivision;i++){
+       for(j=0;j<subdivision;j++){
+       UpdateVertexArray(i,j);
+       }
+       }*/
+
+       return 1;
+}
+
+void Terrain::CalculateNormals()
+{
+       static int i,j;
+       static XYZ facenormal;
+       static XYZ p,q,a,b,c;
+
+       for(i=0; i<size; i++){
+               for(j=0; j<size; j++){
+                       normals[i][j].x=0;
+                       normals[i][j].y=0;
+                       normals[i][j].z=0;
+               }
+       }
+
+       for(i=0;i<size-1;i++){
+               for(j=0;j<size-1;j++){
+                       a.x=i;
+                       a.y=heightmap[i][j];
+                       a.z=j;
+                       b.x=i;
+                       b.y=heightmap[i][j+1];
+                       b.z=j+1;
+                       c.x=i+1;
+                       c.y=heightmap[i+1][j];
+                       c.z=j;
+
+                       p.x=b.x-a.x;
+                       p.y=b.y-a.y;
+                       p.z=b.z-a.z;
+                       q.x=c.x-a.x;
+                       q.y=c.y-a.y;
+                       q.z=c.z-a.z;
+
+                       CrossProduct(&p,&q,&facenormal);
+
+                       facenormals[i][j]=facenormal;
+
+                       normals[i][j]=normals[i][j]+facenormal;
+                       normals[i][j+1]=normals[i][j+1]+facenormal;
+                       normals[i+1][j]=normals[i+1][j]+facenormal;
+
+
+                       a.x=i+1;
+                       a.y=heightmap[i+1][j];
+                       a.z=j;
+                       b.x=i;
+                       b.y=heightmap[i][j+1];
+                       b.z=j+1;
+                       c.x=i+1;
+                       c.y=heightmap[i+1][j+1];
+                       c.z=j+1;
+
+                       p.x=b.x-a.x;
+                       p.y=b.y-a.y;
+                       p.z=b.z-a.z;
+                       q.x=c.x-a.x;
+                       q.y=c.y-a.y;
+                       q.z=c.z-a.z;
+
+                       CrossProduct(&p,&q,&facenormal);
+
+                       normals[i+1][j+1]=normals[i+1][j+1]+facenormal;
+                       normals[i][j+1]=normals[i][j+1]+facenormal;
+                       normals[i+1][j]=normals[i+1][j]+facenormal;
+
+                       Normalise(&facenormals[i][j]);
+               }
+       }
+
+       for(i=0; i<size; i++){
+               for(j=0; j<size; j++){
+                       Normalise(&normals[i][j]);
+                       normals[i][j]=normals[i][j];
+               }
+       }
+}
+
+void Terrain::drawpatch(int whichx, int whichy, float opacity){
+       if(opacity>=1)glDisable(GL_BLEND);
+       if(opacity<1){
+               glEnable(GL_BLEND);
+               UpdateTransparency(whichx,whichy);
+       }
+       glColor4f(1,1,1,1);
+       //Set up vertex array
+       glEnableClientState(GL_VERTEX_ARRAY);
+       glEnableClientState(GL_COLOR_ARRAY);
+       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+       glVertexPointer(3, GL_FLOAT, 9*sizeof(GLfloat),&vArray[0+whichx*patch_elements+whichy*patch_elements*subdivision]);
+       glColorPointer(4,GL_FLOAT, 9*sizeof(GLfloat),&vArray[3+whichx*patch_elements+whichy*patch_elements*subdivision]);
+       glTexCoordPointer(2, GL_FLOAT, 9*sizeof(GLfloat),&vArray[7+whichx*patch_elements+whichy*patch_elements*subdivision]);
+
+       //Draw
+       glDrawArrays(GL_TRIANGLES, 0, numtris[whichx][whichy]*3);
+
+       glDisableClientState(GL_VERTEX_ARRAY);
+       glDisableClientState(GL_COLOR_ARRAY);
+       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+void Terrain::drawpatchother(int whichx, int whichy, float opacity){
+       glEnable(GL_BLEND);
+       if(opacity<1){
+               UpdateTransparency(whichx,whichy);
+       }
+       UpdateTransparencyother(whichx,whichy);
+       glColor4f(1,1,1,1);
+       //Set up vertex array
+       glEnableClientState(GL_VERTEX_ARRAY);
+       glEnableClientState(GL_COLOR_ARRAY);
+       glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+       glVertexPointer(3, GL_FLOAT, 9*sizeof(GLfloat),&vArray[0+whichx*patch_elements+whichy*patch_elements*subdivision]);
+       glColorPointer(4,GL_FLOAT, 9*sizeof(GLfloat),&vArray[3+whichx*patch_elements+whichy*patch_elements*subdivision]);
+       glTexCoordPointer(2, GL_FLOAT, 9*sizeof(GLfloat),&vArray[7+whichx*patch_elements+whichy*patch_elements*subdivision]);
+
+       //Draw
+       glDrawArrays(GL_TRIANGLES, 0, numtris[whichx][whichy]*3);
+
+       glDisableClientState(GL_VERTEX_ARRAY);
+       glDisableClientState(GL_COLOR_ARRAY);
+       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+void Terrain::drawpatchotherother(int whichx, int whichy, float opacity){
+       glEnable(GL_BLEND);
+       UpdateTransparencyotherother(whichx,whichy);
+
+       glMatrixMode(GL_TEXTURE);
+       glPushMatrix();
+               glScalef(6, 6, 6);
+
+               glColor4f(1,1,1,1);
+
+               //Set up vertex array
+               glEnableClientState(GL_VERTEX_ARRAY);
+               glEnableClientState(GL_COLOR_ARRAY);
+               glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+               glVertexPointer(3, GL_FLOAT, 9*sizeof(GLfloat),&vArray[0+whichx*patch_elements+whichy*patch_elements*subdivision]);
+               glColorPointer(4,GL_FLOAT, 9*sizeof(GLfloat),&vArray[3+whichx*patch_elements+whichy*patch_elements*subdivision]);
+               glTexCoordPointer(2, GL_FLOAT, 9*sizeof(GLfloat),&vArray[7+whichx*patch_elements+whichy*patch_elements*subdivision]);
+
+               //Draw
+               glDrawArrays(GL_TRIANGLES, 0, numtris[whichx][whichy]*3);
+
+               glDisableClientState(GL_VERTEX_ARRAY);
+               glDisableClientState(GL_COLOR_ARRAY);
+               glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+
+       glPopMatrix();
+       glMatrixMode(GL_MODELVIEW);
+}
+
+
+float Terrain::getHeight(float pointx, float pointz)
+{
+       static float height1,height2;
+       static int tilex,tiley;
+       static XYZ startpoint,endpoint,intersect,triangle[3],average;
+
+       pointx/=scale;
+       pointz/=scale;
+
+       if(pointx>=size-1||pointz>=size-1||pointx<=0||pointz<=0)return 0;
+
+       startpoint.x=pointx;
+       startpoint.y=-1000;
+       startpoint.z=pointz;
+
+       endpoint=startpoint;
+       endpoint.y=1000;
+
+       tilex=pointx;
+       tiley=pointz;
+
+       triangle[0].x=tilex;
+       triangle[0].z=tiley;
+       triangle[0].y=heightmap[tilex][tiley];
+
+       triangle[1].x=tilex+1;
+       triangle[1].z=tiley;
+       triangle[1].y=heightmap[tilex+1][tiley];
+
+       triangle[2].x=tilex;
+       triangle[2].z=tiley+1;
+       triangle[2].y=heightmap[tilex][tiley+1];
+
+       if(!LineFacetd(&startpoint,&endpoint,&triangle[0],&triangle[1],&triangle[2],&intersect)){
+               triangle[0].x=tilex+1;
+               triangle[0].z=tiley;
+               triangle[0].y=heightmap[tilex+1][tiley];
+
+               triangle[1].x=tilex+1;
+               triangle[1].z=tiley+1;
+               triangle[1].y=heightmap[tilex+1][tiley+1];
+
+               triangle[2].x=tilex;
+               triangle[2].z=tiley+1;
+               triangle[2].y=heightmap[tilex][tiley+1];
+               LineFacetd(&startpoint,&endpoint,&triangle[0],&triangle[1],&triangle[2],&intersect);
+       }
+       return intersect.y*scale+getOpacity(pointx*scale,pointz*scale)/8;
+
+       //height1=heightmap[tilex][tiley]*(1-(pointx-tilex))+heightmap[tilex+1][tiley]*(pointx-tilex);
+       //height2=heightmap[tilex][tiley+1]*(1-(pointx-tilex))+heightmap[tilex+1][tiley+1]*(pointx-tilex);
+
+       //return height1*(1-(pointz-tiley))*scale+height2*(pointz-tiley)*scale;
+}
+
+float Terrain::getHeightExtrude(float pointx, float pointz,float point2x, float point2z)
+{
+       static float height1,height2;
+       static int tilex,tiley;
+       static XYZ startpoint,endpoint,intersect,triangle[3],average;
+
+       pointx/=scale;
+       pointz/=scale;
+       point2x/=scale;
+       point2z/=scale;
+
+       if(pointx>=size-1||pointz>=size-1||pointx<=0||pointz<=0)return 0;
+       if(point2x>=size-1||point2z>=size-1||point2x<=0||point2z<=0)return 0;
+
+       startpoint.x=point2x;
+       startpoint.y=-1000;
+       startpoint.z=point2z;
+
+       endpoint=startpoint;
+       endpoint.y=1000;
+
+       tilex=pointx;
+       tiley=pointz;
+
+       triangle[0].x=tilex;
+       triangle[0].z=tiley;
+       triangle[0].y=heightmap[tilex][tiley];
+
+       triangle[1].x=tilex+1;
+       triangle[1].z=tiley;
+       triangle[1].y=heightmap[tilex+1][tiley];
+
+       triangle[2].x=tilex;
+       triangle[2].z=tiley+1;
+       triangle[2].y=heightmap[tilex][tiley+1];
+
+       XYZ mid;
+
+       mid=(triangle[0]+triangle[1]+triangle[2])/2;
+
+       triangle[0]=mid+(triangle[0]-mid)*10;
+       triangle[1]=mid+(triangle[0]-mid)*10;
+       triangle[2]=mid+(triangle[0]-mid)*10;
+
+       /*
+       if(!LineFacetd(&startpoint,&endpoint,&triangle[0],&triangle[1],&triangle[2],&intersect)){
+       triangle[0].x=tilex+1;
+       triangle[0].z=tiley;
+       triangle[0].y=heightmap[tilex+1][tiley];
+
+       triangle[1].x=tilex+1;
+       triangle[1].z=tiley+1;
+       triangle[1].y=heightmap[tilex+1][tiley+1];
+
+       triangle[2].x=tilex;
+       triangle[2].z=tiley+1;
+       triangle[2].y=heightmap[tilex][tiley+1];
+       LineFacetd(&startpoint,&endpoint,&triangle[0],&triangle[1],&triangle[2],&intersect);
+       }*/
+       return intersect.y*scale+getOpacity(pointx*scale,pointz*scale)/8;
+
+       //height1=heightmap[tilex][tiley]*(1-(pointx-tilex))+heightmap[tilex+1][tiley]*(pointx-tilex);
+       //height2=heightmap[tilex][tiley+1]*(1-(pointx-tilex))+heightmap[tilex+1][tiley+1]*(pointx-tilex);
+
+       //return height1*(1-(pointz-tiley))*scale+height2*(pointz-tiley)*scale;
+}
+
+
+float Terrain::getOpacity(float pointx, float pointz)
+{
+       static float height1,height2;
+       static int tilex,tiley;
+
+       pointx/=scale;
+       pointz/=scale;
+
+       if(pointx>=size-1||pointz>=size-1||pointx<=0||pointz<=0)return 0;
+
+       tilex=pointx;
+       tiley=pointz;
+
+       height1=opacityother[tilex][tiley]*(1-(pointx-tilex))+opacityother[tilex+1][tiley]*(pointx-tilex);
+       height2=opacityother[tilex][tiley+1]*(1-(pointx-tilex))+opacityother[tilex+1][tiley+1]*(pointx-tilex);
+
+       return height1*(1-(pointz-tiley))+height2*(pointz-tiley);
+}
+
+XYZ Terrain::getNormal(float pointx, float pointz)
+{
+       static XYZ height1,height2,total;
+       static int tilex,tiley;
+
+       pointx/=scale;
+       pointz/=scale;
+
+       height1=0;
+       if(pointx>=size-1||pointz>=size-1||pointx<=0||pointz<=0)return height1;
+       tilex=pointx;
+       tiley=pointz;
+
+       height1=normals[tilex][tiley]*(1-(pointx-tilex))+normals[tilex+1][tiley]*(pointx-tilex);
+       height2=normals[tilex][tiley+1]*(1-(pointx-tilex))+normals[tilex+1][tiley+1]*(pointx-tilex);
+       total=height1*(1-(pointz-tiley))+height2*(pointz-tiley);
+       Normalise(&total);
+       return total;
+}
+
+XYZ Terrain::getLighting(float pointx, float pointz)
+{
+       static XYZ height1,height2;
+       static int tilex,tiley;
+
+       pointx/=scale;
+       pointz/=scale;
+
+       height1=0;
+       if(pointx>=size-1||pointz>=size-1||pointx<=0||pointz<=0)return height1;
+       tilex=pointx;
+       tiley=pointz;
+
+       height1.x=colors[tilex][tiley][0]*(1-(pointx-tilex))+colors[tilex+1][tiley][0]*(pointx-tilex);
+       height1.y=colors[tilex][tiley][1]*(1-(pointx-tilex))+colors[tilex+1][tiley][1]*(pointx-tilex);
+       height1.z=colors[tilex][tiley][2]*(1-(pointx-tilex))+colors[tilex+1][tiley][2]*(pointx-tilex);
+       height2.x=colors[tilex][tiley+1][0]*(1-(pointx-tilex))+colors[tilex+1][tiley+1][0]*(pointx-tilex);
+       height2.y=colors[tilex][tiley+1][1]*(1-(pointx-tilex))+colors[tilex+1][tiley+1][1]*(pointx-tilex);
+       height2.z=colors[tilex][tiley+1][2]*(1-(pointx-tilex))+colors[tilex+1][tiley+1][2]*(pointx-tilex);
+
+       return height1*(1-(pointz-tiley))+height2*(pointz-tiley);
+}
+
+void Terrain::draw(int layer)
+{
+       static int i,j;
+       static float opacity;
+       static XYZ terrainpoint;
+       static float distance[subdivision][subdivision];
+
+       static int beginx,endx;
+       static int beginz,endz;
+
+       static float patch_size=size/subdivision*scale;
+       static float viewdistsquared;
+
+       viewdistsquared=viewdistance*viewdistance;
+
+       //Only nearby blocks
+       beginx=(viewer.x-viewdistance)/(patch_size)-1;
+       if(beginx<0)beginx=0;
+       beginz=(viewer.z-viewdistance)/(patch_size)-1;
+       if(beginz<0)beginz=0;
+
+       endx=(viewer.x+viewdistance)/(patch_size)+1;
+       if(endx>subdivision)endx=subdivision;
+       endz=(viewer.z+viewdistance)/(patch_size)+1;
+       if(endz>subdivision)endz=subdivision;
+
+       if(!layer)
+               for(i=beginx;i<endx;i++){       
+                       for(j=beginz;j<endz;j++){       
+                               terrainpoint.x=i*patch_size+(patch_size)/2;
+                               terrainpoint.y=viewer.y;//heightmap[i][j]*scale;
+                               terrainpoint.z=j*patch_size+(patch_size)/2;
+                               distance[i][j]=findDistancefast(&viewer,&terrainpoint);
+                       }
+               }
+
+               for(i=beginx;i<endx;i++){       
+                       for(j=beginz;j<endz;j++){       
+                               if(distance[i][j]<(viewdistance+patch_size)*(viewdistance+patch_size)){
+                                       opacity=1;
+                                       if(distance[i][j]>viewdistsquared*fadestart-viewdistsquared)opacity=0;
+                                       if(opacity==1&&i!=subdivision)if(distance[i+1][j]>viewdistsquared*fadestart-viewdistsquared)opacity=0;
+                                       if(opacity==1&&j!=subdivision)if(distance[i][j+1]>viewdistsquared*fadestart-viewdistsquared)opacity=0;
+                                       if(opacity==1&&j!=subdivision&&i!=subdivision)if(distance[i+1][j+1]>viewdistsquared*fadestart-viewdistsquared)opacity=0;
+                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                       glPushMatrix();
+                                               if(frustum.CubeInFrustum(i*patch_size+patch_size*.5,avgypatch[i][j],j*patch_size+patch_size*.5,heightypatch[i][j]/2))
+                                               {   
+                                                       if(environment==desertenvironment&&distance[i][j]>viewdistsquared/4)glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, blurness);
+                                                       else if(environment==desertenvironment)glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
+                                                       if(!layer&&textureness[i][j]!=allsecond)drawpatch(i,j,opacity);
+                                                       if(layer==1&&textureness[i][j]!=allfirst)drawpatchother(i,j,opacity);
+                                                       if(layer==2&&textureness[i][j]!=allfirst)drawpatchotherother(i,j,opacity);
+                                               }
+                                       glPopMatrix();
+                               }
+                       }
+               }
+               if(environment==desertenvironment)glTexEnvf( GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0 );
+}
+
+void Terrain::drawdecals()
+{
+       if(decals){
+               static int i,j;
+               static float distancemult;
+               static int lasttype;
+
+               static float patch_size=size/subdivision*scale;
+               static float viewdistsquared;
+               static bool blend;
+
+               viewdistsquared=viewdistance*viewdistance;
+               blend=1;
+
+               lasttype=-1;
+               glEnable(GL_BLEND);
+               glDisable(GL_LIGHTING);
+               glDisable(GL_CULL_FACE);
+               glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+               glDepthMask(0);
+               for(i=0;i<numdecals;i++){
+                       if(decaltype[i]==blooddecalfast&&decalalivetime[i]<2)decalalivetime[i]=2;
+                       if((decaltype[i]==shadowdecal||decaltype[i]==shadowdecalpermanent)&&decaltype[i]!=lasttype){
+                               glBindTexture( GL_TEXTURE_2D, shadowtexture);
+                               if(!blend){
+                                       blend=1;
+                                       glAlphaFunc(GL_GREATER, 0.0001);
+                                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                               }
+                       }
+                       if(decaltype[i]==footprintdecal&&decaltype[i]!=lasttype){
+                               glBindTexture( GL_TEXTURE_2D, footprinttexture);
+                               if(!blend){
+                                       blend=1;
+                                       glAlphaFunc(GL_GREATER, 0.0001);
+                                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                               }
+                       }
+                       if(decaltype[i]==bodyprintdecal&&decaltype[i]!=lasttype){
+                               glBindTexture( GL_TEXTURE_2D, bodyprinttexture);
+                               if(!blend){
+                                       blend=1;
+                                       glAlphaFunc(GL_GREATER, 0.0001);
+                                       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+                               }
+                       }
+                       if((decaltype[i]==blooddecal||decaltype[i]==blooddecalslow)&&decaltype[i]!=lasttype){
+                               glBindTexture( GL_TEXTURE_2D, bloodtexture);
+                               if(blend){
+                                       blend=0;
+                                       glAlphaFunc(GL_GREATER, 0.15);
+                                       glBlendFunc(GL_ONE,GL_ZERO);
+                               }
+                       }
+                       if((decaltype[i]==blooddecalfast)&&decaltype[i]!=lasttype){
+                               glBindTexture( GL_TEXTURE_2D, bloodtexture2);
+                               if(blend){
+                                       blend=0;
+                                       glAlphaFunc(GL_GREATER, 0.15);
+                                       glBlendFunc(GL_ONE,GL_ZERO);
+                               }
+                       }
+                       if(decaltype[i]==shadowdecal||decaltype[i]==shadowdecalpermanent){
+                               distancemult=(viewdistsquared-(findDistancefast(&viewer,&decalposition[i])-(viewdistsquared*fadestart))*(1/(1-fadestart)))/viewdistsquared;
+                               if(distancemult>=1)glColor4f(1,1,1,decalopacity[i]);
+                               if(distancemult<1)glColor4f(1,1,1,decalopacity[i]*distancemult);
+                       }
+                       if(decaltype[i]==footprintdecal||decaltype[i]==bodyprintdecal){
+                               distancemult=(viewdistsquared-(findDistancefast(&viewer,&decalposition[i])-(viewdistsquared*fadestart))*(1/(1-fadestart)))/viewdistsquared;
+                               if(distancemult>=1){
+                                       glColor4f(1,1,1,decalopacity[i]);
+                                       if(decalalivetime[i]>3)glColor4f(1,1,1,decalopacity[i]*(5-decalalivetime[i])/2);
+                               }
+                               if(distancemult<1){
+                                       glColor4f(1,1,1,decalopacity[i]*distancemult);
+                                       if(decalalivetime[i]>3)glColor4f(1,1,1,decalopacity[i]*(5-decalalivetime[i])/2*distancemult);
+                               }
+                       }
+                       if((decaltype[i]==blooddecal||decaltype[i]==blooddecalfast||decaltype[i]==blooddecalslow)){
+                               distancemult=(viewdistsquared-(findDistancefast(&viewer,&decalposition[i])-(viewdistsquared*fadestart))*(1/(1-fadestart)))/viewdistsquared;
+                               if(distancemult>=1){
+                                       glColor4f(decalbrightness[i],decalbrightness[i],decalbrightness[i],decalopacity[i]);
+                                       if(decalalivetime[i]<4)glColor4f(decalbrightness[i],decalbrightness[i],decalbrightness[i],decalopacity[i]*decalalivetime[i]*.25);
+                                       if(decalalivetime[i]>58)glColor4f(decalbrightness[i],decalbrightness[i],decalbrightness[i],decalopacity[i]*(60-decalalivetime[i])/2);
+                               }
+                               if(distancemult<1){
+                                       glColor4f(decalbrightness[i],decalbrightness[i],decalbrightness[i],decalopacity[i]*distancemult);
+                                       if(decalalivetime[i]<4)glColor4f(decalbrightness[i],decalbrightness[i],decalbrightness[i],decalopacity[i]*decalalivetime[i]*distancemult*.25);
+                                       if(decalalivetime[i]>58)glColor4f(decalbrightness[i],decalbrightness[i],decalbrightness[i],decalopacity[i]*(60-decalalivetime[i])/2*distancemult);
+                               }
+                       }
+                       lasttype=decaltype[i];
+                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
+
+                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                       glPushMatrix();
+                               glBegin(GL_TRIANGLES);
+                               for(int j=0;j<3;j++)
+                               {
+                                       glTexCoord2f(decaltexcoords[i][j][0], decaltexcoords[i][j][1]); glVertex3f(decalvertex[i][j].x,decalvertex[i][j].y,decalvertex[i][j].z);
+                               }
+                               glEnd();
+                       glPopMatrix();
+               }
+               for(i=numdecals-1;i>=0;i--){
+                       decalalivetime[i]+=multiplier;
+                       if(decaltype[i]==blooddecalslow)decalalivetime[i]-=multiplier*2/3;
+                       if(decaltype[i]==blooddecalfast)decalalivetime[i]+=multiplier*4;
+                       if(decaltype[i]==shadowdecal)DeleteDecal(i);
+                       if(decaltype[i]==footprintdecal&&decalalivetime[i]>=5)DeleteDecal(i);
+                       if(decaltype[i]==bodyprintdecal&&decalalivetime[i]>=5)DeleteDecal(i);
+                       if((decaltype[i]==blooddecal||decaltype[i]==blooddecalfast||decaltype[i]==blooddecalslow)&&decalalivetime[i]>=60)DeleteDecal(i);
+               }
+               glAlphaFunc(GL_GREATER, 0.0001);
+       }
+}
+
+void Terrain::AddObject(XYZ where, float radius, int id)
+{
+       bool done;
+       int i,j;
+       XYZ points[4];
+       if(id>=0&&id<10000)
+               for(i=0;i<subdivision;i++){
+                       for(j=0;j<subdivision;j++){
+                               if(patchobjectnum[i][j]<300-1){
+                                       done=0;
+                                       points[0].x=(size/subdivision)*i;
+                                       points[0].z=(size/subdivision)*j;
+                                       points[0].y=heightmap[(int)points[0].x][(int)points[0].z];
+                                       points[1].x=(size/subdivision)*(i+1);
+                                       points[1].z=(size/subdivision)*j;
+                                       points[1].y=heightmap[(int)points[1].x][(int)points[1].z];
+                                       points[2].x=(size/subdivision)*(i+1);
+                                       points[2].z=(size/subdivision)*(j+1);
+                                       points[2].y=heightmap[(int)points[2].x][(int)points[2].z];
+                                       points[3].x=(size/subdivision)*i;
+                                       points[3].z=(size/subdivision)*(j+1);
+                                       points[3].y=heightmap[(int)points[3].x][(int)points[3].z];
+                                       points[0]*=scale*terraindetail;
+                                       points[1]*=scale*terraindetail;
+                                       points[2]*=scale*terraindetail;
+                                       points[3]*=scale*terraindetail;
+                                       if(!done&&where.x+radius>points[0].x&&where.x-radius<points[2].x&&where.z+radius>points[0].z&&where.z-radius<points[2].z){
+                                               patchobjects[i][j][patchobjectnum[i][j]]=id;
+                                               patchobjectnum[i][j]++;
+                                               done=1;
+                                       }
+                               }
+                       }
+               }
+}
+
+void Terrain::DeleteDecal(int which)
+{
+       if(decals){
+               decaltype[which]=decaltype[numdecals-1];
+               decalposition[which]=decalposition[numdecals-1];
+               for(int i=0;i<3;i++){
+                       decalvertex[which][i]=decalvertex[numdecals-1][i];
+                       decaltexcoords[which][i][0]=decaltexcoords[numdecals-1][i][0];
+                       decaltexcoords[which][i][1]=decaltexcoords[numdecals-1][i][1];
+               }
+               decalrotation[which]=decalrotation[numdecals-1];
+               decalalivetime[which]=decalalivetime[numdecals-1];
+               decalopacity[which]=decalopacity[numdecals-1];
+               decalbrightness[which]=decalbrightness[numdecals-1];
+               numdecals--;
+       }
+}
+
+void Terrain::MakeDecal(int type, XYZ where, float size, float opacity, float rotation){
+       if(decals){
+               if(opacity>0&&size>0){
+                       static int patchx[4];
+                       static int patchy[4];
+
+                       decaltexcoords[numdecals][0][0]=1;
+                       decaltexcoords[numdecals][0][1]=0;
+
+                       patchx[0]=(where.x+size)/scale;
+                       patchx[1]=(where.x-size)/scale;
+                       patchx[2]=(where.x-size)/scale;
+                       patchx[3]=(where.x+size)/scale;
+
+                       patchy[0]=(where.z-size)/scale;
+                       patchy[1]=(where.z-size)/scale;
+                       patchy[2]=(where.z+size)/scale;
+                       patchy[3]=(where.z+size)/scale;
+
+                       /*if(patchx[1]<subdivision-1&&patchy[1]<subdivision-1&&patchx[1]>0&&patchy[1]>0)
+                       if(patchx[2]<subdivision-1&&patchy[2]<subdivision-1&&patchx[2]>0&&patchy[2]>0)
+                       if(patchx[3]<subdivision-1&&patchy[3]<subdivision-1&&patchx[3]>0&&patchy[3]>0)
+                       if(patchx[0]<subdivision-1&&patchy[0]<subdivision-1&&patchx[0]>0&&patchy[0]>0){
+                       */
+                       if((patchx[0]!=patchx[1]||patchy[0]!=patchy[1])&&(patchx[0]!=patchx[2]||patchy[0]!=patchy[2])&&(patchx[0]!=patchx[3]||patchy[0]!=patchy[3])){
+                               MakeDecalLock(type,where,patchx[0],patchy[0],size,opacity,rotation);
+                       }
+
+                       if((patchx[1]!=patchx[2]||patchy[1]!=patchy[2])&&(patchx[1]!=patchx[3]||patchy[1]!=patchy[3])){
+                               MakeDecalLock(type,where,patchx[1],patchy[1],size,opacity,rotation);
+                       }
+
+                       if((patchx[2]!=patchx[3]||patchy[2]!=patchy[3])){
+                               MakeDecalLock(type,where,patchx[2],patchy[2],size,opacity,rotation);
+                       }
+                       MakeDecalLock(type,where,patchx[3],patchy[3],size,opacity,rotation);
+               }
+       }
+       //}
+}
+
+void Terrain::MakeDecalLock(int type, XYZ where,int whichx, int whichy, float size, float opacity, float rotation){
+       if(decals){
+               static float placex,placez;
+               static XYZ rot;
+
+               float decalbright;
+
+               rot=getLighting(where.x,where.z);
+               decalbrightness[numdecals]=(rot.x+rot.y+rot.z)/3;
+               if(decalbrightness[numdecals]<.4)decalbrightness[numdecals]=.4;
+
+               //if(type==blooddecal||type==blooddecalfast||type==blooddecalslow){
+               if(environment==grassyenvironment){
+                       decalbrightness[numdecals]*=.6;
+               }
+               //}
+
+               if(decalbrightness[numdecals]>1)decalbrightness[numdecals]=1;
+               decalbright=decalbrightness[numdecals];
+
+               decalposition[numdecals]=where;
+               decaltype[numdecals]=type;
+               decalopacity[numdecals]=opacity;
+               decalrotation[numdecals]=rotation;
+               decalalivetime[numdecals]=0;
+
+               placex=(float)whichx*scale+scale;
+               placez=(float)whichy*scale;
+
+               decaltexcoords[numdecals][0][0]=(placex-where.x)/size/2+.5;
+               decaltexcoords[numdecals][0][1]=(placez-where.z)/size/2+.5;
+
+               decalvertex[numdecals][0].x=placex;
+               decalvertex[numdecals][0].z=placez;
+               decalvertex[numdecals][0].y=heightmap[whichx+1][whichy]*scale+.01;
+
+
+               placex=(float)whichx*scale+scale;
+               placez=(float)whichy*scale+scale;
+
+               decaltexcoords[numdecals][1][0]=(placex-where.x)/size/2+.5;
+               decaltexcoords[numdecals][1][1]=(placez-where.z)/size/2+.5;
+
+               decalvertex[numdecals][1].x=placex;
+               decalvertex[numdecals][1].z=placez;
+               decalvertex[numdecals][1].y=heightmap[whichx+1][whichy+1]*scale+.01;
+
+
+               placex=(float)whichx*scale;
+               placez=(float)whichy*scale+scale;
+
+               decaltexcoords[numdecals][2][0]=(placex-where.x)/size/2+.5;
+               decaltexcoords[numdecals][2][1]=(placez-where.z)/size/2+.5;
+
+               decalvertex[numdecals][2].x=placex;
+               decalvertex[numdecals][2].z=placez;
+               decalvertex[numdecals][2].y=heightmap[whichx][whichy+1]*scale+.01;
+
+               if(decalrotation[numdecals]){
+                       for(int i=0;i<3;i++){                   
+                               rot.y=0;
+                               rot.x=decaltexcoords[numdecals][i][0]-.5;
+                               rot.z=decaltexcoords[numdecals][i][1]-.5;
+                               rot=DoRotation(rot,0,-decalrotation[numdecals],0);
+                               decaltexcoords[numdecals][i][0]=rot.x+.5;
+                               decaltexcoords[numdecals][i][1]=rot.z+.5;
+                       }
+               }
+
+               if(!(decaltexcoords[numdecals][0][0]<0&&decaltexcoords[numdecals][1][0]<0&&decaltexcoords[numdecals][2][0]<0))
+                       if(!(decaltexcoords[numdecals][0][1]<0&&decaltexcoords[numdecals][1][1]<0&&decaltexcoords[numdecals][2][1]<0))
+                               if(!(decaltexcoords[numdecals][0][0]>1&&decaltexcoords[numdecals][1][0]>1&&decaltexcoords[numdecals][2][0]>1))
+                                       if(!(decaltexcoords[numdecals][0][1]>1&&decaltexcoords[numdecals][1][1]>1&&decaltexcoords[numdecals][2][1]>1))
+                                               if(numdecals<max_decals-1)numdecals++;
+
+               decalbrightness[numdecals]=decalbright;
+
+               decalposition[numdecals]=where;
+               decaltype[numdecals]=type;
+               decalopacity[numdecals]=opacity;
+               decalrotation[numdecals]=rotation;
+               decalalivetime[numdecals]=0;
+
+               placex=(float)whichx*scale+scale;
+               placez=(float)whichy*scale;
+
+               decaltexcoords[numdecals][0][0]=(placex-where.x)/size/2+.5;
+               decaltexcoords[numdecals][0][1]=(placez-where.z)/size/2+.5;
+
+               decalvertex[numdecals][0].x=placex;
+               decalvertex[numdecals][0].z=placez;
+               decalvertex[numdecals][0].y=heightmap[whichx+1][whichy]*scale+.01;
+
+
+               placex=(float)whichx*scale;
+               placez=(float)whichy*scale;
+
+               decaltexcoords[numdecals][1][0]=(placex-where.x)/size/2+.5;
+               decaltexcoords[numdecals][1][1]=(placez-where.z)/size/2+.5;
+
+               decalvertex[numdecals][1].x=placex;
+               decalvertex[numdecals][1].z=placez;
+               decalvertex[numdecals][1].y=heightmap[whichx][whichy]*scale+.01;
+
+
+               placex=(float)whichx*scale;
+               placez=(float)whichy*scale+scale;
+
+               decaltexcoords[numdecals][2][0]=(placex-where.x)/size/2+.5;
+               decaltexcoords[numdecals][2][1]=(placez-where.z)/size/2+.5;
+
+               decalvertex[numdecals][2].x=placex;
+               decalvertex[numdecals][2].z=placez;
+               decalvertex[numdecals][2].y=heightmap[whichx][whichy+1]*scale+.01;
+
+               if(decalrotation[numdecals]){
+                       for(int i=0;i<3;i++){                   
+                               rot.y=0;
+                               rot.x=decaltexcoords[numdecals][i][0]-.5;
+                               rot.z=decaltexcoords[numdecals][i][1]-.5;
+                               rot=DoRotation(rot,0,-decalrotation[numdecals],0);
+                               decaltexcoords[numdecals][i][0]=rot.x+.5;
+                               decaltexcoords[numdecals][i][1]=rot.z+.5;
+                       }
+               }
+
+               if(!(decaltexcoords[numdecals][0][0]<0&&decaltexcoords[numdecals][1][0]<0&&decaltexcoords[numdecals][2][0]<0))
+                       if(!(decaltexcoords[numdecals][0][1]<0&&decaltexcoords[numdecals][1][1]<0&&decaltexcoords[numdecals][2][1]<0))
+                               if(!(decaltexcoords[numdecals][0][0]>1&&decaltexcoords[numdecals][1][0]>1&&decaltexcoords[numdecals][2][0]>1))
+                                       if(!(decaltexcoords[numdecals][0][1]>1&&decaltexcoords[numdecals][1][1]>1&&decaltexcoords[numdecals][2][1]>1))
+                                               if(numdecals<max_decals-1)numdecals++;
+       }
+}
+
+void Terrain::DoLighting()
+{
+       static int i,j,k,todivide;
+       static float brightness, total;
+       static XYZ blank, terrainpoint,lightloc;
+       lightloc=light.location;
+       Normalise(&lightloc);
+       //Calculate shadows
+       for(i=0;i<size;i++){
+               for(j=0;j<size;j++){
+                       terrainpoint.x=(float)i*scale;
+                       terrainpoint.z=(float)j*scale;
+                       terrainpoint.y=heightmap[i][j]*scale+.1;
+                       /*brightness=0;
+                       if(lineTerrain(lightlocation*10+terrainpoint,terrainpoint,&blank)==-1)
+                       */
+                       brightness=dotproduct(&lightloc,&normals[i][j]);
+
+                       if(brightness>1)brightness=1;
+                       if(brightness<0)brightness=0;
+
+                       colors[i][j][0]=light.color[0]*brightness+light.ambient[0];
+                       colors[i][j][1]=light.color[1]*brightness+light.ambient[1];
+                       colors[i][j][2]=light.color[2]*brightness+light.ambient[2];
+
+                       if(colors[i][j][0]>1)colors[i][j][0]=1;
+                       if(colors[i][j][1]>1)colors[i][j][1]=1;
+                       if(colors[i][j][2]>1)colors[i][j][2]=1;
+                       if(colors[i][j][0]<0)colors[i][j][0]=0;
+                       if(colors[i][j][1]<0)colors[i][j][1]=0;
+                       if(colors[i][j][2]<0)colors[i][j][2]=0;
+               }
+       }
+
+       //Smooth shadows
+       for(i=0;i<size;i++){
+               for(j=0;j<size;j++){
+                       for(k=0;k<3;k++){
+                               total=0;
+                               todivide=0;
+                               if(i!=0){                               total+=colors[j][i-1][k]; todivide++;}
+                               if(i!=size-1){                          total+=colors[j][i+1][k]; todivide++;}
+                               if(j!=0){                               total+=colors[j-1][i][k]; todivide++;}
+                               if(j!=size-1){                          total+=colors[j+1][i][k]; todivide++;}
+                               if(i!=0&&j!=0){                 total+=colors[j-1][i-1][k]; todivide++;}
+                               if(i!=size-1&&j!=0){            total+=colors[j-1][i+1][k]; todivide++;}
+                               if(j!=size-1&&i!=size-1){               total+=colors[j+1][i+1][k]; todivide++;}
+                               if(j!=size-1&&i!=0){            total+=colors[j+1][i-1][k]; todivide++;}
+                               total+=colors[j][i][k]; todivide++;
+
+                               colors[j][i][k]=total/todivide;
+                       }
+               }
+       }
+}
+
+void Terrain::DoShadows()
+{
+       static int i,j,k,l,todivide;
+       static float brightness, total;
+       static XYZ testpoint,testpoint2, terrainpoint,lightloc,col;
+       lightloc=light.location;
+       if(!skyboxtexture){
+               lightloc.x=0;
+               lightloc.z=0;
+       }
+       if(skyboxtexture&&tutoriallevel){
+               lightloc.x*=.4;
+               lightloc.z*=.4;
+       }
+       int patchx,patchz;
+       float shadowed;
+       Normalise(&lightloc);
+       //Calculate shadows
+       for(i=0;i<size;i++){
+               for(j=0;j<size;j++){
+                       terrainpoint.x=(float)(i)*scale;
+                       terrainpoint.z=(float)(j)*scale;
+                       terrainpoint.y=heightmap[i][j]*scale;
+
+                       shadowed=0;
+                       patchx=(float)(i)*subdivision/size;
+                       patchz=(float)(j)*subdivision/size;
+                       if(patchobjectnum[patchx][patchz]){
+                               for(k=0;k<patchobjectnum[patchx][patchz];k++){
+                                       l=patchobjects[patchx][patchz][k];
+                                       if(objects.type[l]!=treetrunktype){
+                                               testpoint=terrainpoint;
+                                               testpoint2=terrainpoint+lightloc*50*(1-shadowed);
+                                               if(objects.model[l].LineCheck(&testpoint,&testpoint2,&col,&objects.position[l],&objects.rotation[l])!=-1){
+                                                       shadowed=1-(findDistance(&terrainpoint,&col)/50);       
+                                               }
+                                       }
+                               }
+                               if(visibleloading)pgame->LoadingScreen();
+                       }
+                       brightness=dotproduct(&lightloc,&normals[i][j]);
+                       if(shadowed)brightness*=1-shadowed;
+
+                       if(brightness>1)brightness=1;
+                       if(brightness<0)brightness=0;
+
+                       colors[i][j][0]=light.color[0]*brightness+light.ambient[0];
+                       colors[i][j][1]=light.color[1]*brightness+light.ambient[1];
+                       colors[i][j][2]=light.color[2]*brightness+light.ambient[2];
+
+                       if(colors[i][j][0]>1)colors[i][j][0]=1;
+                       if(colors[i][j][1]>1)colors[i][j][1]=1;
+                       if(colors[i][j][2]>1)colors[i][j][2]=1;
+                       if(colors[i][j][0]<0)colors[i][j][0]=0;
+                       if(colors[i][j][1]<0)colors[i][j][1]=0;
+                       if(colors[i][j][2]<0)colors[i][j][2]=0;
+               }
+       }
+
+       if(visibleloading)pgame->LoadingScreen();
+
+       //Smooth shadows
+       for(i=0;i<size;i++){
+               for(j=0;j<size;j++){
+                       for(k=0;k<3;k++){
+                               total=0;
+                               todivide=0;
+                               if(i!=0){                               total+=colors[j][i-1][k]; todivide++;}
+                               if(i!=size-1){                          total+=colors[j][i+1][k]; todivide++;}
+                               if(j!=0){                               total+=colors[j-1][i][k]; todivide++;}
+                               if(j!=size-1){                          total+=colors[j+1][i][k]; todivide++;}
+                               if(i!=0&&j!=0){                 total+=colors[j-1][i-1][k]; todivide++;}
+                               if(i!=size-1&&j!=0){            total+=colors[j-1][i+1][k]; todivide++;}
+                               if(j!=size-1&&i!=size-1){               total+=colors[j+1][i+1][k]; todivide++;}
+                               if(j!=size-1&&i!=0){            total+=colors[j+1][i-1][k]; todivide++;}
+                               total+=colors[j][i][k]; todivide++;
+
+                               colors[j][i][k]=total/todivide;
+                       }
+               }
+       }
+
+       for(i=0;i<subdivision;i++){
+               for(j=0;j<subdivision;j++){
+                       UpdateVertexArray(i,j);
+               }
+       }
+}
+
+Terrain::Terrain()
+{
+       bloodtexture = 0;
+       bloodtexture2 = 0;
+       shadowtexture = 0;
+       footprinttexture = 0;
+       bodyprinttexture = 0;
+       breaktexture = 0;
+       terraintexture = 0;
+       size = 0;
+
+       memset(patchobjectnum, 0, sizeof(patchobjectnum));
+       memset(patchobjects, 0, sizeof(patchobjects));
+
+       scale = 0;
+       type = 0;
+       memset(heightmap, 0, sizeof(heightmap));
+       memset(normals, 0, sizeof(normals));
+       memset(facenormals, 0, sizeof(facenormals));
+       memset(triangles, 0, sizeof(triangles));
+       memset(colors, 0, sizeof(colors));
+       memset(opacityother, 0, sizeof(opacityother));
+       memset(texoffsetx, 0, sizeof(texoffsetx));
+       memset(texoffsety, 0, sizeof(texoffsety));
+       memset(numtris, 0, sizeof(numtris));
+       memset(textureness, 0, sizeof(textureness));
+
+       memset(vArray, 0, sizeof(vArray));
+
+       memset(visible, 0, sizeof(visible));
+       memset(avgypatch, 0, sizeof(avgypatch));
+       memset(maxypatch, 0, sizeof(maxypatch));
+       memset(minypatch, 0, sizeof(minypatch));
+       memset(heightypatch, 0, sizeof(heightypatch));
+
+       patch_elements = 0;
+
+       memset(decaltexcoords, 0, sizeof(decaltexcoords));
+       memset(decalvertex, 0, sizeof(decalvertex));
+       memset(decaltype, 0, sizeof(decaltype));
+       memset(decalopacity, 0, sizeof(decalopacity));
+       memset(decalrotation, 0, sizeof(decalrotation));
+       memset(decalalivetime, 0, sizeof(decalalivetime));
+       memset(decalbrightness, 0, sizeof(decalbrightness));
+       memset(decalposition, 0, sizeof(decalposition));
+       numdecals = 0;
+}
+Terrain::~Terrain()
+{
+       if(terraintexture)glDeleteTextures( 1, (const unsigned long *)&terraintexture );
+       if(shadowtexture) glDeleteTextures( 1, (const unsigned long *)&shadowtexture );
+       if(bodyprinttexture) glDeleteTextures( 1, (const unsigned long *)&bodyprinttexture );
+       if(footprinttexture) glDeleteTextures( 1, (const unsigned long *)&footprinttexture );
+       if(bloodtexture) glDeleteTextures( 1, (const unsigned long *)&bloodtexture );
+       if(bloodtexture2) glDeleteTextures( 1, (const unsigned long *)&bloodtexture2 );
+       if(breaktexture) glDeleteTextures( 1, (const unsigned long *)&breaktexture );
+}
diff --git a/Source/Terrain.h b/Source/Terrain.h
new file mode 100644 (file)
index 0000000..507ff64
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef _TERRAIN_H_
+#define _TERRAIN_H_
+
+#include "gl.h"
+#include "Frustum.h"
+#include "Lights.h"
+#include "TGALoader.h"
+#include "Quaternions.h"
+#include "Quaternions.h"
+
+#define max_terrain_size                       256             
+#define curr_terrain_size                      size
+#define subdivision                            64
+#define max_patch_elements                     (max_terrain_size/subdivision)*(max_terrain_size/subdivision)*54
+
+#define allfirst 0
+#define mixed 1
+#define allsecond 2
+
+#define max_decals 1000
+
+#define shadowdecal 0
+#define footprintdecal 1
+#define blooddecal 2
+#define blooddecalfast 3
+#define shadowdecalpermanent 4
+#define breakdecal 5
+#define blooddecalslow 6
+#define bodyprintdecal 7
+
+#define snowyenvironment 0
+#define grassyenvironment 1
+#define desertenvironment 2
+//
+// Model Structures
+//
+
+class Terrain{
+public:
+       GLuint bloodtexture;
+       GLuint bloodtexture2;
+       GLuint shadowtexture;
+       GLuint footprinttexture;
+       GLuint bodyprinttexture;
+       GLuint breaktexture;
+       GLuint terraintexture;
+       short   size;
+
+       int patchobjectnum[subdivision][subdivision];
+       int patchobjects[subdivision][subdivision][300];
+
+       float scale;
+       int type;
+       float heightmap[max_terrain_size+1][max_terrain_size+1];
+       XYZ normals[max_terrain_size][max_terrain_size];
+       XYZ facenormals[max_terrain_size][max_terrain_size];
+       XYZ triangles[(max_terrain_size-1)*(max_terrain_size-1)*2][3];
+       float colors[max_terrain_size][max_terrain_size][4];
+       float opacityother[max_terrain_size][max_terrain_size];
+       float texoffsetx[max_terrain_size][max_terrain_size];
+       float texoffsety[max_terrain_size][max_terrain_size];
+       int numtris[subdivision][subdivision];
+       int textureness[subdivision][subdivision];
+
+       GLfloat vArray[(max_patch_elements)*subdivision*subdivision];
+
+       bool visible[subdivision][subdivision];
+       float avgypatch[subdivision][subdivision];
+       float maxypatch[subdivision][subdivision];
+       float minypatch[subdivision][subdivision];
+       float heightypatch[subdivision][subdivision];
+
+       int patch_elements;
+
+       float decaltexcoords[max_decals][3][2];
+       XYZ decalvertex[max_decals][3];
+       int decaltype[max_decals];
+       float decalopacity[max_decals];
+       float decalrotation[max_decals];
+       float decalalivetime[max_decals];
+       float decalbrightness[max_decals];
+       XYZ decalposition[max_decals];
+       int numdecals;
+
+       void AddObject(XYZ where, float radius,int id);
+       void DeleteDecal(int which);
+       void MakeDecal(int type, XYZ where, float size, float opacity, float rotation);
+       void MakeDecalLock(int type, XYZ where, int whichx, int whichy, float size, float opacity, float rotation);
+       int lineTerrain(XYZ p1,XYZ p2, XYZ *p);
+       float getHeight(float pointx, float pointz);
+       float getHeightExtrude(float pointx, float pointz,float point2x, float point2z);
+       float getOpacity(float pointx, float pointz);
+       XYZ getLighting(float pointx, float pointz);
+       XYZ getNormal(float pointx, float pointz);
+       void UpdateVertexArray(int whichx, int whichy);
+       void UpdateTransparency(int whichx, int whichy);
+       void UpdateTransparencyother(int whichx, int whichy);
+       void UpdateTransparencyotherother(int whichx, int whichy);
+       bool load(char *fileName);
+       void CalculateNormals();
+       void drawdecals();
+       void draw(int layer);
+       void drawpatch(int whichx, int whichy, float opacity);
+       void drawpatchother(int whichx, int whichy, float opacity);
+       void drawpatchotherother(int whichx, int whichy, float opacity);
+       void DoLighting();
+       void DoShadows();
+
+       Terrain();
+       ~Terrain();
+};
+
+#endif
\ No newline at end of file
diff --git a/Source/Text.cpp b/Source/Text.cpp
new file mode 100644 (file)
index 0000000..f41fb6b
--- /dev/null
@@ -0,0 +1,261 @@
+/**> HEADER FILES <**/
+#include "Text.h"
+#include "Game.h"
+extern TGAImageRec texture;
+
+void Text::LoadFontTexture(char *fileName)
+{
+       GLuint          type;
+
+       LOGFUNC;
+
+       LOG(std::string("Loading font texture...") + fileName);
+
+       Game::LoadTexture(fileName, &FontTexture, false, false);
+/*
+       //Load Image
+       //LoadTGA( fileName ); 
+       unsigned char fileNamep[256];
+       CopyCStringToPascal(fileName,fileNamep);
+       //Load Image
+       upload_image( fileNamep ,1); 
+
+       //Is it valid?
+       if(1==1){
+               //Alpha channel?
+               if ( texture.bpp == 24 )
+                       type = GL_RGB;
+               else
+                       type = GL_RGBA;
+
+               glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+               if(!FontTexture)glGenTextures( 1, &FontTexture );
+               glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+
+               glBindTexture( GL_TEXTURE_2D, FontTexture);
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
+               glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
+
+               gluBuild2DMipmaps( GL_TEXTURE_2D, type, texture.sizeX, texture.sizeY, type, GL_UNSIGNED_BYTE, texture.data );
+       }
+*/
+       if (base)
+       {
+               glDeleteLists(base, 512);
+               base = 0;
+       }
+}
+
+void Text::BuildFont()                                                         // Build Our Font Display List
+{
+       float   cx;                                                                                     // Holds Our X Character Coord
+       float   cy;                                                                                     // Holds Our Y Character Coord
+       int loop;
+
+       LOGFUNC;
+
+       if (base)
+       {
+               LOG("Font already created...");
+               return;
+       }
+
+//     base=glGenLists(256);                                                           // Creating 256 Display Lists
+       base=glGenLists(512);                                                           // Creating 256 Display Lists
+       glBindTexture(GL_TEXTURE_2D, FontTexture);                      // Select Our Font Texture
+       for (loop=0; loop<256; loop++)                                          // Loop Through All 256 Lists
+       {
+               cx=float(loop%16)/16.0f;                                                // X Position Of Current Character
+               cy=float(loop/16)/16.0f;                                                // Y Position Of Current Character
+
+               glNewList(base+loop,GL_COMPILE);                                // Start Building A List
+               glBegin(GL_QUADS);                                                      // Use A Quad For Each Character
+               glTexCoord2f(cx,1-cy-0.0625f+.001);                     // Texture Coord (Bottom Left)
+               glVertex2i(0,0);                                                // Vertex Coord (Bottom Left)
+               glTexCoord2f(cx+0.0625f,1-cy-0.0625f+.001);     // Texture Coord (Bottom Right)
+               glVertex2i(16,0);                                               // Vertex Coord (Bottom Right)
+               glTexCoord2f(cx+0.0625f,1-cy-.001);                     // Texture Coord (Top Right)
+               glVertex2i(16,16);                                              // Vertex Coord (Top Right)
+               glTexCoord2f(cx,1-cy-+.001);                                    // Texture Coord (Top Left)
+               glVertex2i(0,16);                                               // Vertex Coord (Top Left)
+               glEnd();                                                                        // Done Building Our Quad (Character)
+               glTranslated(10,0,0);                                           // Move To The Right Of The Character
+               glEndList();                                                                    // Done Building The Display List
+       }                                                                                                       // Loop Until All 256 Are Built
+       for (loop=256; loop<512; loop++)                                                // Loop Through All 256 Lists
+       {
+               cx=float((loop-256)%16)/16.0f;                                          // X Position Of Current Character
+               cy=float((loop-256)/16)/16.0f;                                          // Y Position Of Current Character
+
+               glNewList(base+loop,GL_COMPILE);                                // Start Building A List
+               glBegin(GL_QUADS);                                                      // Use A Quad For Each Character
+               glTexCoord2f(cx,1-cy-0.0625f+.001);                     // Texture Coord (Bottom Left)
+               glVertex2i(0,0);                                                // Vertex Coord (Bottom Left)
+               glTexCoord2f(cx+0.0625f,1-cy-0.0625f+.001);     // Texture Coord (Bottom Right)
+               glVertex2i(16,0);                                               // Vertex Coord (Bottom Right)
+               glTexCoord2f(cx+0.0625f,1-cy-.001);                     // Texture Coord (Top Right)
+               glVertex2i(16,16);                                              // Vertex Coord (Top Right)
+               glTexCoord2f(cx,1-cy-+.001);                                    // Texture Coord (Top Left)
+               glVertex2i(0,16);                                               // Vertex Coord (Top Left)
+               glEnd();                                                                        // Done Building Our Quad (Character)
+               glTranslated(8,0,0);                                            // Move To The Right Of The Character
+               glEndList();                                                                    // Done Building The Display List
+       }                                                                                                       // Loop Until All 256 Are Built
+}
+
+void Text::glPrint(float x, float y, char *string, int set, float size, float width, float height)     // Where The Printing Happens
+{
+       if (set>1)
+       {
+               set=1;
+       }
+       glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+       glBindTexture(GL_TEXTURE_2D, FontTexture);                      // Select Our Font Texture
+       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+       glDisable(GL_LIGHTING);
+       glEnable(GL_BLEND);
+       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+       glPushMatrix();                                                                         // Store The Projection Matrix
+               glLoadIdentity();                                                                       // Reset The Projection Matrix
+               glOrtho(0,width,0,height,-100,100);                                             // Set Up An Ortho Screen
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+               glPushMatrix();                                                                         // Store The Modelview Matrix
+                       glLoadIdentity();
+                       glTranslated(x,y,0);                                                            // Position The Text (0,0 - Bottom Left)
+                       glScalef(size,size,1);                                                                  // Reset The Modelview Matrix
+                       glListBase(base-32+(128*set));                                          // Choose The Font Set (0 or 1)
+                       glCallLists(strlen(string),GL_BYTE,string);                     // Write The Text To The Screen
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+               glPopMatrix();                                                                          // Restore The Old Projection Matrix
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+       glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+}
+
+void Text::glPrint(float x, float y, char *string, int set, float size, float width, float height,int start,int end)   // Where The Printing Happens
+{
+       if (set>1)
+       {
+               set=1;
+       }
+       glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+       glBindTexture(GL_TEXTURE_2D, FontTexture);                      // Select Our Font Texture
+       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+       glDisable(GL_LIGHTING);
+       glEnable(GL_BLEND);
+       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+       glPushMatrix();                                                                         // Store The Projection Matrix
+               glLoadIdentity();                                                                       // Reset The Projection Matrix
+               glOrtho(0,width,0,height,-100,100);                                             // Set Up An Ortho Screen
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+               glPushMatrix();                                                                         // Store The Modelview Matrix
+                       glLoadIdentity();
+                       glTranslated(x,y,0);                                                            // Position The Text (0,0 - Bottom Left)
+                       glScalef(size,size,1);                                                                  // Reset The Modelview Matrix
+                       glListBase(base-32+(128*set));                                          // Choose The Font Set (0 or 1)
+                       glCallLists(end-start,GL_BYTE,&string[start]);                  // Write The Text To The Screen
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+               glPopMatrix();                                                                          // Restore The Old Projection Matrix
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+       glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+}
+
+
+void Text::glPrintOutline(float x, float y, char *string, int set, float size, float width, float height)      // Where The Printing Happens
+{
+       if (set>1)
+       {
+               set=1;
+       }
+       glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+       glBindTexture(GL_TEXTURE_2D, FontTexture);                      // Select Our Font Texture
+       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+       glDisable(GL_LIGHTING);
+       glEnable(GL_BLEND);
+       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+       glPushMatrix();                                                                         // Store The Projection Matrix
+               glLoadIdentity();                                                                       // Reset The Projection Matrix
+               glOrtho(0,width,0,height,-100,100);                                             // Set Up An Ortho Screen
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+               glPushMatrix();                                                                         // Store The Modelview Matrix
+                       glLoadIdentity();
+                       glTranslated(x,y,0);                                                            // Position The Text (0,0 - Bottom Left)
+                       glScalef(size,size,1);                                                                  // Reset The Modelview Matrix
+                       glListBase(base-32+(128*set)+256);                                              // Choose The Font Set (0 or 1)
+                       glCallLists(strlen(string),GL_BYTE,string);                     // Write The Text To The Screen
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+               glPopMatrix();                                                                          // Restore The Old Projection Matrix
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+       glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+}
+
+void Text::glPrintOutline(float x, float y, char *string, int set, float size, float width, float height,int start,int end)    // Where The Printing Happens
+{
+       if (set>1)
+       {
+               set=1;
+       }
+       glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+       glBindTexture(GL_TEXTURE_2D, FontTexture);                      // Select Our Font Texture
+       glDisable(GL_DEPTH_TEST);                                                       // Disables Depth Testing
+       glDisable(GL_LIGHTING);
+       glEnable(GL_BLEND);
+       glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+       glPushMatrix();                                                                         // Store The Projection Matrix
+               glLoadIdentity();                                                                       // Reset The Projection Matrix
+               glOrtho(0,width,0,height,-100,100);                                             // Set Up An Ortho Screen
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+               glPushMatrix();                                                                         // Store The Modelview Matrix
+                       glLoadIdentity();
+                       glTranslated(x,y,0);                                                            // Position The Text (0,0 - Bottom Left)
+                       glScalef(size,size,1);                                                                  // Reset The Modelview Matrix
+                       glListBase(base-32+(128*set)+256);                                              // Choose The Font Set (0 or 1)
+                       glCallLists(end-start,GL_BYTE,&string[start]);                  // Write The Text To The Screen
+                       glMatrixMode(GL_PROJECTION);                                            // Select The Projection Matrix
+               glPopMatrix();                                                                          // Restore The Old Projection Matrix
+               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+       glPopMatrix();                                                                          // Restore The Old Projection Matrix
+       glEnable(GL_DEPTH_TEST);                                                        // Enables Depth Testing
+       glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
+}
+
+void Text::glPrintOutlined(float x, float y, char *string, int set, float size, float width, float height)     // Where The Printing Happens
+{
+       glColor4f(0,0,0,1);
+       glPrintOutline( x-2*size,  y-2*size, string,  set,  size*2.5/2,  width,  height);
+       glColor4f(1,1,1,1);
+       glPrint( x,  y, string,  set,  size,  width,  height);
+}
+
+void Text::glPrintOutlined(float r, float g, float b, float x, float y, char *string, int set, float size, float width, float height)  // Where The Printing Happens
+{
+       glColor4f(0,0,0,1);
+       glPrintOutline( x-2*size,  y-2*size, string,  set,  size*2.5/2,  width,  height);
+       glColor4f(r,g,b,1);
+       glPrint( x,  y, string,  set,  size,  width,  height);
+}
+
+Text::Text()
+{
+       base = 0;
+       FontTexture = 0;
+}
+Text::~Text()
+{
+       if (base)
+       {
+               glDeleteLists(base, 512);
+               base = 0;
+       }
+       if (FontTexture) glDeleteTextures( 1, (const unsigned long *)&FontTexture );
+}
diff --git a/Source/Text.h b/Source/Text.h
new file mode 100644 (file)
index 0000000..bc314b1
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _TEXT_H_
+#define _TEXT_H_
+
+
+/**> HEADER FILES <**/
+#include "Quaternions.h"
+//#include "Files.h"
+#include "Quaternions.h"
+#include "gl.h"
+#include "TGALoader.h"
+
+class Text{
+public:
+       GLuint FontTexture;
+       GLuint base;
+
+       void LoadFontTexture(char *fileName);
+       void BuildFont();
+       void glPrint(float x, float y, char *string, int set, float size, float width, float height);
+       void glPrintOutline(float x, float y, char *string, int set, float size, float width, float height);
+       void glPrint(float x, float y, char *string, int set, float size, float width, float height,int start,int end);
+       void glPrintOutline(float x, float y, char *string, int set, float size, float width, float height,int start,int end);
+       void glPrintOutlined(float x, float y, char *string, int set, float size, float width, float height);
+       void glPrintOutlined(float r, float g, float b, float x, float y, char *string, int set, float size, float width, float height);
+
+       Text();
+       ~Text();
+};
+
+#endif
\ No newline at end of file
diff --git a/Source/Weapons.cpp b/Source/Weapons.cpp
new file mode 100644 (file)
index 0000000..ac7a96f
--- /dev/null
@@ -0,0 +1,1343 @@
+/**> HEADER FILES <**/
+#include "Weapons.h"
+
+extern float multiplier;
+extern Animation animation[animation_count];
+extern FSOUND_SAMPLE   *samp[100];
+extern int channels[100];
+extern Terrain terrain;
+extern float gravity;
+extern int environment;
+extern Sprites sprites;
+extern int detail;
+extern FRUSTUM frustum;
+extern XYZ viewer;
+extern float realmultiplier;
+extern int slomo;
+extern float slomodelay;
+extern bool cellophane;
+extern float texdetail;
+extern GLubyte bloodText[512*512*3];
+extern int bloodtoggle;
+extern Objects objects;
+extern bool osx;
+extern bool autoslomo;
+extern float camerashake;
+extern float woozy;
+extern float terraindetail;
+extern float viewdistance;
+extern float blackout;
+extern int difficulty;
+extern Person player[maxplayers];
+extern int numplayers;
+extern bool freeze;
+extern int bonus;
+extern float bonusvalue;
+extern float bonustotal;
+extern float bonustime;
+extern int tutoriallevel;
+extern int numthrowkill;
+extern "C"     void PlaySoundEx(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused);
+
+void   Weapons::DoStuff(){
+       static int i,whichpatchx,whichpatchz,j,k,whichhit,m;
+       static XYZ start,end,colpoint,normalrot,footvel,footpoint;
+       static XYZ terrainnormal;
+       static XYZ vel;
+       static XYZ midp;
+       static XYZ newpoint1,newpoint2;
+       static float friction=3.5;
+       static float elasticity=.4;
+       static XYZ bounceness;
+       static float frictionness;
+       static float moveamount;
+       int closestline;
+       static float closestdistance;
+       static float distance;
+       static XYZ point[3];
+       static XYZ closestpoint;
+       static XYZ closestswordpoint;
+       static XYZ extramove;
+       static float proportion;
+       static float tempmult;
+
+       //Move
+
+       for(i=0;i<numweapons;i++){
+               if(owner[i]!=-1){
+                       oldowner[i]=owner[i];
+               }
+               if(damage[i]>=2&&type[i]==staff&&owner[i]!=-1){
+                       float gLoc[3];
+                       float vel[3];
+                       gLoc[0]=tippoint[i].x;
+                       gLoc[1]=tippoint[i].y;
+                       gLoc[2]=tippoint[i].z;
+                       vel[0]=0;
+                       vel[1]=0;
+                       vel[2]=0;
+                       PlaySoundEx( staffbreaksound, samp[staffbreaksound], NULL, TRUE);
+                       FSOUND_3D_SetAttributes(channels[staffbreaksound], gLoc, vel);
+                       FSOUND_SetVolume(channels[staffbreaksound], 256);
+                       FSOUND_SetPaused(channels[staffbreaksound], FALSE);
+                       XYZ tempvel;
+                       XYZ speed;
+                       //speed=(tippoint[i]-oldtippoint[i])/multiplier/6;
+                       speed=0;
+                       /*for(j=0;j<10;j++){
+                       tempvel.x=float(abs(Random()%100)-50)/20;
+                       tempvel.y=float(abs(Random()%100)-50)/20;
+                       tempvel.z=float(abs(Random()%100)-50)/20;
+                       tempvel+=speed;
+                       sprites.MakeSprite(cloudimpactsprite, position[i]+(tippoint[i]-position[i])*((float)j-2)/8,tempvel*.5, 115/255,73/255,12/255, .15+float(abs(Random()%100)-50)/1000, .7);
+                       }*/
+                       for(j=0;j<40;j++){
+                               tempvel.x=float(abs(Random()%100)-50)/20;
+                               tempvel.y=float(abs(Random()%100)-50)/20;
+                               tempvel.z=float(abs(Random()%100)-50)/20;
+                               tempvel+=speed;
+                               sprites.MakeSprite(splintersprite, position[i]+(tippoint[i]-position[i])*((float)j-8)/32,tempvel*.5, 115/255,73/255,12/255, .1, 1);
+                       }
+                       int tempowner;
+                       tempowner=owner[i];
+                       owner[i]=-1;
+                       hitsomething[i]=0;
+                       missed[i]=1;
+                       freetime[i]=0;
+                       firstfree[i]=1;
+                       position[i]=0;
+                       physics[i]=0;
+                       if(tempowner!=-1){
+                               player[tempowner].num_weapons--;
+                               if(player[tempowner].num_weapons){
+                                       player[tempowner].weaponids[0]=player[tempowner].weaponids[player[tempowner].num_weapons];
+                                       if(player[tempowner].weaponstuck==player[tempowner].num_weapons)player[tempowner].weaponstuck=0;
+                               }
+                               player[tempowner].weaponactive=-1;
+                       }
+               }
+               oldposition[i]=position[i];
+               oldtippoint[i]=tippoint[i];
+               if(owner[i]==-1&&(velocity[i].x||velocity[i].y||velocity[i].z)&&!physics[i]){
+                       position[i]+=velocity[i]*multiplier;
+                       tippoint[i]+=velocity[i]*multiplier;
+                       whichpatchx=position[i].x/(terrain.size/subdivision*terrain.scale*terraindetail);
+                       whichpatchz=position[i].z/(terrain.size/subdivision*terrain.scale*terraindetail);
+                       if(whichpatchx>0&&whichpatchz>0&&whichpatchx<subdivision&&whichpatchz<subdivision)
+                               if(terrain.patchobjectnum[whichpatchx][whichpatchz]){
+                                       for(j=0;j<terrain.patchobjectnum[whichpatchx][whichpatchz];j++){
+                                               k=terrain.patchobjects[whichpatchx][whichpatchz][j];
+                                               start=oldtippoint[i];
+                                               end=tippoint[i];
+                                               whichhit=objects.model[k].LineCheck(&start,&end,&colpoint,&objects.position[k],&objects.rotation[k]);
+                                               if(whichhit!=-1){
+                                                       if(objects.type[k]==treetrunktype){
+                                                               objects.model[k].MakeDecal(breakdecal,DoRotation(colpoint-objects.position[k],0,-objects.rotation[k],0),.1,1,Random()%360);
+                                                               normalrot=DoRotation(objects.model[k].facenormals[whichhit],0,objects.rotation[k],0);
+                                                               velocity[i]=0;
+                                                               if(type[i]==knife)position[i]=colpoint-normalrot*.1;
+                                                               if(type[i]==sword)position[i]=colpoint-normalrot*.2;
+                                                               if(type[i]==staff)position[i]=colpoint-normalrot*.2;
+                                                               XYZ temppoint1,temppoint2,tempforward;
+                                                               float distance;
+
+                                                               temppoint1=0;
+                                                               temppoint2=normalrot;
+                                                               distance=findDistance(&temppoint1,&temppoint2);
+                                                               rotation2[i]=asin((temppoint1.y-temppoint2.y)/distance);
+                                                               rotation2[i]*=360/6.28;
+                                                               temppoint1.y=0;
+                                                               temppoint2.y=0;
+                                                               rotation1[i]=acos((temppoint1.z-temppoint2.z)/findDistance(&temppoint1,&temppoint2));
+                                                               rotation1[i]*=360/6.28;
+                                                               if(temppoint1.x>temppoint2.x)rotation1[i]=360-rotation1[i];
+
+                                                               rotation3[i]=0;
+                                                               smallrotation[i]=90;
+                                                               smallrotation2[i]=0;
+                                                               bigtilt[i]=0;
+                                                               bigtilt2[i]=0;
+                                                               bigrotation[i]=0;
+
+                                                               float gLoc[3];
+                                                               float vel[3];
+                                                               gLoc[0]=position[i].x;
+                                                               gLoc[1]=position[i].y;
+                                                               gLoc[2]=position[i].z;
+                                                               vel[0]=0;
+                                                               vel[1]=0;
+                                                               vel[2]=0;
+                                                               PlaySoundEx( knifesheathesound, samp[knifesheathesound], NULL, TRUE);
+                                                               FSOUND_3D_SetAttributes(channels[knifesheathesound], gLoc, vel);
+                                                               FSOUND_SetVolume(channels[knifesheathesound], 128);
+                                                               FSOUND_SetPaused(channels[knifesheathesound], FALSE);
+
+                                                               bloody[i]=0;
+
+                                                               sprites.MakeSprite(cloudimpactsprite, position[i],velocity[i], 1,1,1, .8, .3);                          
+                                                       }
+                                                       else {
+                                                               physics[i]=1;
+                                                               firstfree[i]=1;
+                                                               position[i]-=velocity[i]*multiplier;
+                                                               tippoint[i]-=velocity[i]*multiplier;
+                                                               tipvelocity[i]=velocity[i];
+                                                       }
+                                               }       
+                                       }
+                               }
+                               if(velocity[i].x||velocity[i].y||velocity[i].z)
+                                       for(j=0;j<numplayers;j++){
+                                               footvel=0;
+                                               footpoint=DoRotation((player[j].skeleton.joints[player[j].skeleton.jointlabels[abdomen]].position+player[j].skeleton.joints[player[j].skeleton.jointlabels[neck]].position)/2,0,player[j].rotation,0)*player[j].scale+player[j].coords;                         
+                                               if(owner[i]==-1&&findDistancefastflat(&position[i],&player[j].coords)<1.5&&findDistancefast(&position[i],&player[j].coords)<4&&player[j].weaponstuck==-1&&!player[j].skeleton.free&&j!=oldowner[i]){
+                                                       if((player[j].aitype!=attacktypecutoff||abs(Random()%6)==0||(player[j].targetanimation!=backhandspringanim&&player[j].targetanimation!=rollanim&&player[j].targetanimation!=flipanim&&Random()%2==0))&&!missed[i]){
+                                                               bool caught=0;
+                                                               if((player[j].creature==wolftype&&Random()%3!=0&&player[j].weaponactive==-1&&(player[j].isIdle()||player[j].isRun()||player[j].targetanimation==walkanim))||(player[j].creature==rabbittype&&Random()%2==0&&player[j].aitype==attacktypecutoff&&player[j].weaponactive==-1)){
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=player[j].coords.x;
+                                                                       gLoc[1]=player[j].coords.y;
+                                                                       gLoc[2]=player[j].coords.z;
+                                                                       vel[0]=player[j].velocity.x;
+                                                                       vel[1]=player[j].velocity.y;
+                                                                       vel[2]=player[j].velocity.z;
+                                                                       PlaySoundEx( knifedrawsound, samp[knifedrawsound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[knifedrawsound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[knifedrawsound], 128);
+                                                                       FSOUND_SetPaused(channels[knifedrawsound], FALSE);
+
+                                                                       player[j].weaponactive=0;
+                                                                       player[j].targetanimation=removeknifeanim;
+                                                                       player[j].targetframe=1;
+                                                                       player[j].target=1;
+                                                                       owner[i]=player[j].id;
+                                                                       if(player[j].num_weapons>0){
+                                                                               player[j].weaponids[player[j].num_weapons]=player[j].weaponids[0];
+                                                                       }
+                                                                       player[j].num_weapons++;
+                                                                       player[j].weaponids[0]=i;
+
+                                                                       player[j].aitype=attacktypecutoff;
+                                                               }
+                                                               else {
+                                                                       if(j!=0)numthrowkill++;
+                                                                       player[j].num_weapons++;
+                                                                       player[j].weaponstuck=player[j].num_weapons-1;
+                                                                       if(normaldotproduct(player[j].facing,velocity[i])>0)player[j].weaponstuckwhere=1;
+                                                                       else player[j].weaponstuckwhere=0;
+
+                                                                       player[j].weaponids[player[j].num_weapons-1]=i;
+
+                                                                       player[j].RagDoll(0);
+                                                                       player[j].skeleton.joints[player[j].skeleton.jointlabels[abdomen]].velocity+=velocity[i]*2;
+                                                                       player[j].skeleton.joints[player[j].skeleton.jointlabels[neck]].velocity+=velocity[i]*2;
+                                                                       player[j].skeleton.joints[player[j].skeleton.jointlabels[rightshoulder]].velocity+=velocity[i]*2;
+                                                                       player[j].skeleton.joints[player[j].skeleton.jointlabels[leftshoulder]].velocity+=velocity[i]*2;
+                                                                       //player[j].Puff(abdomen);
+                                                                       if(bloodtoggle&&tutoriallevel!=1)sprites.MakeSprite(cloudimpactsprite, footpoint,footvel, 1,0,0, .8, .3);
+                                                                       if(tutoriallevel==1)sprites.MakeSprite(cloudimpactsprite, footpoint,footvel, 1,1,1, .8, .3);
+                                                                       footvel=tippoint[i]-position[i];
+                                                                       Normalise(&footvel);
+                                                                       if(bloodtoggle&&tutoriallevel!=1)sprites.MakeSprite(bloodflamesprite, footpoint,footvel*-1, 1,0,0, .6, 1);
+
+                                                                       if(tutoriallevel!=1){
+                                                                               if(player[j].weaponstuckwhere==0)player[j].DoBloodBig(2,205);
+                                                                               if(player[j].weaponstuckwhere==1)player[j].DoBloodBig(2,200);
+                                                                               player[j].damage+=200/player[j].armorhigh;
+                                                                               player[j].deathbleeding=1;
+                                                                               player[j].bloodloss+=(200+abs((float)(Random()%40))-20)/player[j].armorhigh;
+                                                                               owner[i]=j;
+                                                                               bloody[i]=2;
+                                                                               blooddrip[i]=5;
+                                                                       }
+
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       gLoc[0]=position[i].x;
+                                                                       gLoc[1]=position[i].y;
+                                                                       gLoc[2]=position[i].z;
+                                                                       vel[0]=0;
+                                                                       vel[1]=0;
+                                                                       vel[2]=0;
+                                                                       PlaySoundEx( fleshstabsound, samp[fleshstabsound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[fleshstabsound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[fleshstabsound], 128);
+                                                                       FSOUND_SetPaused(channels[fleshstabsound], FALSE);
+
+                                                                       if(animation[player[0].targetanimation].height==highheight){
+                                                                               bonus=ninja;
+                                                                               bonustime=0;
+                                                                               bonusvalue=60;
+                                                                       }
+                                                                       else{
+                                                                               bonus=Bullseyebonus;
+                                                                               bonustime=0;
+                                                                               bonusvalue=30;
+                                                                       }
+                                                               }
+                                                       }
+                                                       else missed[i]=1;
+                                               }       
+                                       }
+                                       if(position[i].y<terrain.getHeight(position[i].x,position[i].z)){
+                                               if(terrain.getOpacity(position[i].x,position[i].z)<.2){
+                                                       velocity[i]=0;
+                                                       if(terrain.lineTerrain(oldposition[i],position[i],&colpoint)!=-1){
+                                                               position[i]=colpoint*terrain.scale;
+                                                       }
+                                                       else position[i].y=terrain.getHeight(position[i].x,position[i].z);
+
+                                                       terrain.MakeDecal(shadowdecalpermanent,position[i],.06,.5,0);
+                                                       normalrot=terrain.getNormal(position[i].x,position[i].z)*-1;
+                                                       velocity[i]=0;
+                                                       //position[i]-=normalrot*.1;
+                                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                                       glPushMatrix();
+                                                               GLfloat M[16];
+                                                               glLoadIdentity();
+                                                               glRotatef(bigrotation[i],0,1,0);
+                                                               glRotatef(bigtilt2[i],1,0,0);
+                                                               glRotatef(bigtilt[i],0,0,1);
+                                                               glRotatef(-rotation1[i]+90,0,1,0);
+                                                               glRotatef(-rotation2[i]+90,0,0,1);
+                                                               glRotatef(-rotation3[i],0,1,0);
+                                                               glRotatef(smallrotation[i],1,0,0);
+                                                               glRotatef(smallrotation2[i],0,1,0);
+                                                               glTranslatef(0,0,1);            
+                                                               glGetFloatv(GL_MODELVIEW_MATRIX,M);
+                                                               tippoint[i].x=M[12];
+                                                               tippoint[i].y=M[13];
+                                                               tippoint[i].z=M[14];
+                                                       glPopMatrix();
+                                                       position[i]-=tippoint[i]*.15;
+                                                       XYZ temppoint1,temppoint2,tempforward;
+                                                       float distance;
+
+                                                       rotation3[i]=0;
+                                                       smallrotation[i]=90;
+                                                       smallrotation2[i]=0;
+                                                       bigtilt[i]=0;
+                                                       bigtilt2[i]=0;
+                                                       bigrotation[i]=0;
+
+                                                       float gLoc[3];
+                                                       float vel[3];
+                                                       gLoc[0]=position[i].x;
+                                                       gLoc[1]=position[i].y;
+                                                       gLoc[2]=position[i].z;
+                                                       vel[0]=0;
+                                                       vel[1]=0;
+                                                       vel[2]=0;
+                                                       PlaySoundEx( knifesheathesound, samp[knifesheathesound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[knifesheathesound], gLoc, vel);
+                                                       FSOUND_SetVolume(channels[knifesheathesound], 128);
+                                                       FSOUND_SetPaused(channels[knifesheathesound], FALSE);
+
+                                                       XYZ terrainlight;
+                                                       terrainlight=terrain.getLighting(position[i].x,position[i].z);
+                                                       if(environment==snowyenvironment){
+                                                               if(findDistancefast(&position[i],&viewer)<viewdistance*viewdistance/4)sprites.MakeSprite(cloudsprite, position[i],velocity[i], terrainlight.x,terrainlight.y,terrainlight.z, .5, .7);
+                                                       }
+                                                       else if(environment==grassyenvironment){
+                                                               if(findDistancefast(&position[i],&viewer)<viewdistance*viewdistance/4)sprites.MakeSprite(cloudsprite, position[i],velocity[i], terrainlight.x*90/255,terrainlight.y*70/255,terrainlight.z*8/255, .5, .5);
+                                                       }
+                                                       else if(environment==desertenvironment){
+                                                               if(findDistancefast(&position[i],&viewer)<viewdistance*viewdistance/4)sprites.MakeSprite(cloudsprite, position[i],velocity[i], terrainlight.x*190/255,terrainlight.y*170/255,terrainlight.z*108/255, .5, .7);
+                                                       }
+
+                                                       bloody[i]=0;
+                                               }
+                                               else {
+                                                       physics[i]=1;
+                                                       firstfree[i]=1;
+                                                       position[i]-=velocity[i]*multiplier;
+                                                       tippoint[i]-=velocity[i]*multiplier;
+                                                       tipvelocity[i]=velocity[i];
+                                               }
+                                       }
+                                       if(velocity[i].x!=0||velocity[i].z!=0||velocity[i].y!=0){
+                                               velocity[i].y+=gravity*multiplier;
+
+                                               XYZ temppoint1,temppoint2,tempforward;
+                                               float distance;
+
+                                               temppoint1=0;
+                                               temppoint2=velocity[i];
+                                               distance=findDistance(&temppoint1,&temppoint2);
+                                               rotation2[i]=asin((temppoint1.y-temppoint2.y)/distance);
+                                               rotation2[i]*=360/6.28;
+                                               temppoint1.y=0;
+                                               temppoint2.y=0;
+                                               rotation1[i]=acos((temppoint1.z-temppoint2.z)/findDistance(&temppoint1,&temppoint2));
+                                               rotation1[i]*=360/6.28;
+                                               rotation3[i]=0;
+                                               smallrotation[i]=90;
+                                               smallrotation2[i]=0;
+                                               bigtilt[i]=0;
+                                               bigtilt2[i]=0;
+                                               bigrotation[i]=0;
+                                               if(temppoint1.x>temppoint2.x)rotation1[i]=360-rotation1[i];
+                                       }
+               }
+               //Sword physics
+               XYZ mid;
+               XYZ oldmid;
+               XYZ oldmid2;
+
+               tempmult=multiplier;
+               multiplier/=10;
+               for(int l=0;l<10;l++){
+                       if(owner[i]==-1&&(velocity[i].x||velocity[i].y||velocity[i].z)&&physics[i]){
+                               //move
+                               position[i]+=velocity[i]*multiplier;
+                               tippoint[i]+=tipvelocity[i]*multiplier;
+
+                               //Length constrain
+                               midp=(position[i]*mass[i]+tippoint[i]*tipmass[i])/(mass[i]+tipmass[i]);
+                               vel=tippoint[i]-midp;
+                               Normalise(&vel);
+                               newpoint1=midp-vel*length[i]*(tipmass[i]/(mass[i]+tipmass[i]));
+                               newpoint2=midp+vel*length[i]*(mass[i]/(mass[i]+tipmass[i]));
+                               if(!freeze){
+                                       if(freetime[i]>.04)velocity[i]=velocity[i]+(newpoint1-position[i])/multiplier;
+                                       if(freetime[i]>.04)tipvelocity[i]=tipvelocity[i]+(newpoint2-tippoint[i])/multiplier;
+                               }
+                               position[i]=newpoint1;
+                               tippoint[i]=newpoint2;
+
+
+                               //Object collisions
+                               whichpatchx=(position[i].x)/(terrain.size/subdivision*terrain.scale*terraindetail);
+                               whichpatchz=(position[i].z)/(terrain.size/subdivision*terrain.scale*terraindetail);
+                               if(whichpatchx>0&&whichpatchz>0&&whichpatchx<subdivision&&whichpatchz<subdivision)
+                                       if(terrain.patchobjectnum[whichpatchx][whichpatchz]){
+                                               for(j=0;j<terrain.patchobjectnum[whichpatchx][whichpatchz];j++){
+                                                       k=terrain.patchobjects[whichpatchx][whichpatchz][j];
+
+                                                       if(firstfree[i]){
+                                                               if(type[i]!=staff){
+                                                                       start=position[i]-(tippoint[i]-position[i])/5;
+                                                                       end=tippoint[i]+(tippoint[i]-position[i])/30;
+                                                                       whichhit=objects.model[k].LineCheck(&start,&end,&colpoint,&objects.position[k],&objects.rotation[k]);
+                                                                       if(whichhit!=-1){
+                                                                               XYZ diff;
+                                                                               diff=(colpoint-tippoint[i]);
+                                                                               Normalise(&diff);
+                                                                               hitsomething[i]=1;
+
+                                                                               position[i]+=(colpoint-tippoint[i])+diff*.05;
+                                                                               tippoint[i]=colpoint+diff*.05;                                                  
+                                                                               oldposition[i]=position[i];
+                                                                               oldtippoint[i]=tippoint[i];
+                                                                       }
+                                                               }
+                                                               if(type[i]==staff){
+                                                                       start=tippoint[i]-(position[i]-tippoint[i])/5;
+                                                                       end=position[i]+(position[i]-tippoint[i])/30;
+                                                                       whichhit=objects.model[k].LineCheck(&start,&end,&colpoint,&objects.position[k],&objects.rotation[k]);
+                                                                       if(whichhit!=-1){
+                                                                               XYZ diff;
+                                                                               diff=(colpoint-position[i]);
+                                                                               Normalise(&diff);
+                                                                               hitsomething[i]=1;
+
+                                                                               tippoint[i]+=(colpoint-position[i])+diff*.05;
+                                                                               position[i]=colpoint+diff*.05;                                                  
+                                                                               oldtippoint[i]=tippoint[i];
+                                                                               oldposition[i]=tippoint[i];
+                                                                       }
+                                                               }
+                                                       }
+
+                                                       start=oldposition[i];
+                                                       end=position[i];
+                                                       whichhit=objects.model[k].LineCheck(&start,&end,&colpoint,&objects.position[k],&objects.rotation[k]);
+                                                       if(whichhit!=-1){
+                                                               hitsomething[i]=1;
+                                                               position[i]=colpoint;                   
+                                                               terrainnormal=DoRotation(objects.model[k].facenormals[whichhit],0,objects.rotation[k],0)*-1;
+                                                               ReflectVector(&velocity[i],&terrainnormal);
+                                                               position[i]+=terrainnormal*.002;
+
+                                                               bounceness=terrainnormal*findLength(&velocity[i])*(abs(normaldotproduct(velocity[i],terrainnormal)));
+                                                               if(findLengthfast(&velocity[i])<findLengthfast(&bounceness))bounceness=0;
+                                                               frictionness=abs(normaldotproduct(velocity[i],terrainnormal));
+                                                               velocity[i]-=bounceness;
+                                                               if(1-friction*frictionness>0)velocity[i]*=1-friction*frictionness;
+                                                               else velocity[i]=0;
+                                                               velocity[i]+=bounceness*elasticity;
+
+                                                               if(findLengthfast(&bounceness)>1){
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       //int whichsound=clank1sound+abs(Random()%4);
+                                                                       int whichsound;
+                                                                       if(type[i]==staff)whichsound=footstepsound3+abs(Random()%2);
+                                                                       if(type[i]!=staff)whichsound=clank1sound+abs(Random()%4);gLoc[0]=position[i].x;
+                                                                       gLoc[1]=position[i].y;
+                                                                       gLoc[2]=position[i].z;
+                                                                       vel[0]=0;
+                                                                       vel[1]=0;
+                                                                       vel[2]=0;
+                                                                       PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[whichsound], 128*findLengthfast(&bounceness));
+                                                                       FSOUND_SetPaused(channels[whichsound], FALSE);
+                                                               }
+                                                       }
+                                                       start=oldtippoint[i];
+                                                       end=tippoint[i];
+                                                       whichhit=objects.model[k].LineCheck(&start,&end,&colpoint,&objects.position[k],&objects.rotation[k]);
+                                                       if(whichhit!=-1){
+                                                               hitsomething[i]=1;
+                                                               tippoint[i]=colpoint;                   
+                                                               terrainnormal=DoRotation(objects.model[k].facenormals[whichhit],0,objects.rotation[k],0)*-1;
+                                                               ReflectVector(&tipvelocity[i],&terrainnormal);
+                                                               tippoint[i]+=terrainnormal*.002;
+
+                                                               bounceness=terrainnormal*findLength(&tipvelocity[i])*(abs(normaldotproduct(tipvelocity[i],terrainnormal)));
+                                                               if(findLengthfast(&tipvelocity[i])<findLengthfast(&bounceness))bounceness=0;
+                                                               frictionness=abs(normaldotproduct(tipvelocity[i],terrainnormal));
+                                                               tipvelocity[i]-=bounceness;
+                                                               if(1-friction*frictionness>0)tipvelocity[i]*=1-friction*frictionness;
+                                                               else tipvelocity[i]=0;
+                                                               tipvelocity[i]+=bounceness*elasticity;
+
+                                                               if(findLengthfast(&bounceness)>1){
+                                                                       float gLoc[3];
+                                                                       float vel[3];
+                                                                       //int whichsound=clank1sound+abs(Random()%4);
+                                                                       int whichsound;
+                                                                       if(type[i]==staff)whichsound=footstepsound3+abs(Random()%2);
+                                                                       if(type[i]!=staff)whichsound=clank1sound+abs(Random()%4);gLoc[0]=position[i].x;
+                                                                       gLoc[0]=position[i].x;
+                                                                       gLoc[1]=position[i].y;
+                                                                       gLoc[2]=position[i].z;
+                                                                       vel[0]=0;
+                                                                       vel[1]=0;
+                                                                       vel[2]=0;
+                                                                       PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                                                                       FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                                                                       FSOUND_SetVolume(channels[whichsound], 128*findLengthfast(&bounceness));
+                                                                       FSOUND_SetPaused(channels[whichsound], FALSE);
+                                                               }
+                                                       }
+
+                                                       if((objects.type[k]!=boxtype&&objects.type[k]!=platformtype&&objects.type[k]!=walltype&&objects.type[k]!=weirdtype)||objects.rotation2[k]!=0)
+                                                               for(m=0;m<2;m++){
+                                                                       mid=(position[i]*(21+(float)m*10)+tippoint[i]*(19-(float)m*10))/40;
+                                                                       oldmid2=mid;
+                                                                       oldmid=(oldposition[i]*(21+(float)m*10)+oldtippoint[i]*(19-(float)m*10))/40;
+
+                                                                       start=oldmid;
+                                                                       end=mid;
+                                                                       whichhit=objects.model[k].LineCheck(&start,&end,&colpoint,&objects.position[k],&objects.rotation[k]);
+                                                                       if(whichhit!=-1){
+                                                                               hitsomething[i]=1;
+                                                                               mid=colpoint;                   
+                                                                               terrainnormal=DoRotation(objects.model[k].facenormals[whichhit],0,objects.rotation[k],0)*-1;
+                                                                               ReflectVector(&velocity[i],&terrainnormal);
+
+                                                                               bounceness=terrainnormal*findLength(&velocity[i])*(abs(normaldotproduct(velocity[i],terrainnormal)));
+                                                                               if(findLengthfast(&velocity[i])<findLengthfast(&bounceness))bounceness=0;
+                                                                               frictionness=abs(normaldotproduct(velocity[i],terrainnormal));
+                                                                               velocity[i]-=bounceness;
+                                                                               if(1-friction*frictionness>0)velocity[i]*=1-friction*frictionness;
+                                                                               else velocity[i]=0;
+                                                                               velocity[i]+=bounceness*elasticity;
+
+                                                                               if(findLengthfast(&bounceness)>1){
+                                                                                       float gLoc[3];
+                                                                                       float vel[3];
+                                                                                       //int whichsound=clank1sound+abs(Random()%4);
+                                                                                       int whichsound;
+                                                                                       if(type[i]==staff)whichsound=footstepsound3+abs(Random()%2);
+                                                                                       if(type[i]!=staff)whichsound=clank1sound+abs(Random()%4);gLoc[0]=mid.x;
+                                                                                       gLoc[1]=mid.y;
+                                                                                       gLoc[2]=mid.z;
+                                                                                       vel[0]=0;
+                                                                                       vel[1]=0;
+                                                                                       vel[2]=0;
+                                                                                       PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[whichsound], 128*findLengthfast(&bounceness));
+                                                                                       FSOUND_SetPaused(channels[whichsound], FALSE);
+                                                                               }
+                                                                               position[i]+=(mid-oldmid2)*(20/(1+(float)m*10));
+                                                                       }
+
+                                                                       mid=(position[i]*(19-(float)m*10)+tippoint[i]*(21+(float)m*10))/40;
+                                                                       oldmid2=mid;
+                                                                       oldmid=(oldposition[i]*(19-(float)m*10)+oldtippoint[i]*(21+(float)m*10))/40;
+
+                                                                       start=oldmid;
+                                                                       end=mid;
+                                                                       whichhit=objects.model[k].LineCheck(&start,&end,&colpoint,&objects.position[k],&objects.rotation[k]);
+                                                                       if(whichhit!=-1){
+                                                                               hitsomething[i]=1;
+                                                                               mid=colpoint;                   
+                                                                               terrainnormal=DoRotation(objects.model[k].facenormals[whichhit],0,objects.rotation[k],0)*-1;
+                                                                               ReflectVector(&tipvelocity[i],&terrainnormal);
+
+                                                                               bounceness=terrainnormal*findLength(&tipvelocity[i])*(abs(normaldotproduct(tipvelocity[i],terrainnormal)));
+                                                                               if(findLengthfast(&tipvelocity[i])<findLengthfast(&bounceness))bounceness=0;
+                                                                               frictionness=abs(normaldotproduct(tipvelocity[i],terrainnormal));
+                                                                               tipvelocity[i]-=bounceness;
+                                                                               if(1-friction*frictionness>0)tipvelocity[i]*=1-friction*frictionness;
+                                                                               else tipvelocity[i]=0;
+                                                                               tipvelocity[i]+=bounceness*elasticity;
+
+                                                                               if(findLengthfast(&bounceness)>1){
+                                                                                       float gLoc[3];
+                                                                                       float vel[3];
+                                                                                       //int whichsound=clank1sound+abs(Random()%4);
+                                                                                       int whichsound;
+                                                                                       if(type[i]==staff)whichsound=footstepsound3+abs(Random()%2);
+                                                                                       if(type[i]!=staff)whichsound=clank1sound+abs(Random()%4);gLoc[0]=mid.x;
+                                                                                       gLoc[1]=mid.y;
+                                                                                       gLoc[2]=mid.z;
+                                                                                       vel[0]=0;
+                                                                                       vel[1]=0;
+                                                                                       vel[2]=0;
+                                                                                       PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                                                                                       FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                                                                                       FSOUND_SetVolume(channels[whichsound], 128*findLengthfast(&bounceness));
+                                                                                       FSOUND_SetPaused(channels[whichsound], FALSE);
+                                                                               }
+                                                                               tippoint[i]+=(mid-oldmid2)*(20/(1+(float)m*10));
+                                                                       }
+                                                               }
+                                                       else
+                                                       {
+                                                               start=position[i];
+                                                               end=tippoint[i];
+                                                               whichhit=objects.model[k].LineCheck(&start,&end,&colpoint,&objects.position[k],&objects.rotation[k]);
+                                                               if(whichhit!=-1){
+                                                                       hitsomething[i]=1;
+                                                                       closestdistance=-1;
+                                                                       closestswordpoint=colpoint;//(position[i]+tippoint[i])/2;
+                                                                       point[0]=DoRotation(objects.model[k].vertex[objects.model[k].Triangles[whichhit].vertex[0]],0,objects.rotation[k],0)+objects.position[k];
+                                                                       point[1]=DoRotation(objects.model[k].vertex[objects.model[k].Triangles[whichhit].vertex[1]],0,objects.rotation[k],0)+objects.position[k];
+                                                                       point[2]=DoRotation(objects.model[k].vertex[objects.model[k].Triangles[whichhit].vertex[2]],0,objects.rotation[k],0)+objects.position[k];
+                                                                       if(DistancePointLine(&closestswordpoint, &point[0], &point[1], &distance,&colpoint ))
+                                                                               if(distance<closestdistance||closestdistance==-1){
+                                                                                       closestpoint=colpoint;
+                                                                                       closestdistance=distance;
+                                                                                       closestline=0;
+                                                                               }
+                                                                               if(DistancePointLine(&closestswordpoint, &point[1], &point[2], &distance,&colpoint ))
+                                                                                       if(distance<closestdistance||closestdistance==-1){
+                                                                                               closestpoint=colpoint;
+                                                                                               closestdistance=distance;
+                                                                                               closestline=1;
+                                                                                       }
+                                                                                       if(DistancePointLine(&closestswordpoint, &point[2], &point[0], &distance,&colpoint ))
+                                                                                               if(distance<closestdistance||closestdistance==-1){
+                                                                                                       closestpoint=colpoint;
+                                                                                                       closestdistance=distance;
+                                                                                                       closestline=2;
+                                                                                               }
+                                                                                               if(closestdistance!=-1&&isnormal(closestdistance)){
+                                                                                                       if(DistancePointLine(&closestpoint, &position[i], &tippoint[i], &distance,&colpoint )){
+                                                                                                               closestswordpoint=colpoint;
+                                                                                                               velocity[i]+=(closestpoint-closestswordpoint);
+                                                                                                               tipvelocity[i]+=(closestpoint-closestswordpoint);
+                                                                                                               position[i]+=(closestpoint-closestswordpoint);          
+                                                                                                               tippoint[i]+=(closestpoint-closestswordpoint);
+                                                                                                       }
+                                                                                               }
+                                                               }
+                                                       }
+
+                                               }
+                                       }
+                                       //Terrain collisions
+                                       whichhit=terrain.lineTerrain(oldposition[i],position[i],&colpoint);
+                                       if(whichhit!=-1||position[i].y<terrain.getHeight(position[i].x,position[i].z)){
+                                               hitsomething[i]=1;
+                                               if(whichhit!=-1)position[i]=colpoint*terrain.scale;
+                                               else position[i].y=terrain.getHeight(position[i].x,position[i].z);
+
+                                               terrainnormal=terrain.getNormal(position[i].x,position[i].z);
+                                               ReflectVector(&velocity[i],&terrainnormal);
+                                               position[i]+=terrainnormal*.002;
+                                               bounceness=terrainnormal*findLength(&velocity[i])*(abs(normaldotproduct(velocity[i],terrainnormal)));
+                                               if(findLengthfast(&velocity[i])<findLengthfast(&bounceness))bounceness=0;
+                                               frictionness=abs(normaldotproduct(velocity[i],terrainnormal));
+                                               velocity[i]-=bounceness;
+                                               if(1-friction*frictionness>0)velocity[i]*=1-friction*frictionness;
+                                               else velocity[i]=0;
+                                               if(terrain.getOpacity(position[i].x,position[i].z)<.2)velocity[i]+=bounceness*elasticity*.3;
+                                               else velocity[i]+=bounceness*elasticity;
+
+                                               if(findLengthfast(&bounceness)>1){
+                                                       float gLoc[3];
+                                                       float vel[3];
+                                                       int whichsound;
+                                                       if(terrain.getOpacity(position[i].x,position[i].z)>.2){
+                                                               if(type[i]==staff)whichsound=footstepsound3+abs(Random()%2);
+                                                               if(type[i]!=staff)whichsound=clank1sound+abs(Random()%4);
+                                                       }
+                                                       else whichsound=footstepsound+abs(Random()%2);
+                                                       gLoc[0]=position[i].x;
+                                                       gLoc[1]=position[i].y;
+                                                       gLoc[2]=position[i].z;
+                                                       vel[0]=0;
+                                                       vel[1]=0;
+                                                       vel[2]=0;
+                                                       PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                                                       if(terrain.getOpacity(position[i].x,position[i].z)>.2)FSOUND_SetVolume(channels[whichsound], 128*findLengthfast(&bounceness));
+                                                       else FSOUND_SetVolume(channels[whichsound], 32*findLengthfast(&bounceness));
+                                                       FSOUND_SetPaused(channels[whichsound], FALSE);
+
+                                                       if(terrain.getOpacity(position[i].x,position[i].z)<.2){
+                                                               XYZ terrainlight;
+                                                               terrainlight=terrain.getLighting(position[i].x,position[i].z);
+                                                               if(environment==snowyenvironment){
+                                                                       if(findDistancefast(&position[i],&viewer)<viewdistance*viewdistance/4)sprites.MakeSprite(cloudsprite, position[i],velocity[i], terrainlight.x,terrainlight.y,terrainlight.z, .5, .7);
+                                                               }
+                                                               else if(environment==grassyenvironment){
+                                                                       if(findDistancefast(&position[i],&viewer)<viewdistance*viewdistance/4)sprites.MakeSprite(cloudsprite, position[i],velocity[i], terrainlight.x*90/255,terrainlight.y*70/255,terrainlight.z*8/255, .5, .5);
+                                                               }
+                                                               else if(environment==desertenvironment){
+                                                                       if(findDistancefast(&position[i],&viewer)<viewdistance*viewdistance/4)sprites.MakeSprite(cloudsprite, position[i],velocity[i], terrainlight.x*190/255,terrainlight.y*170/255,terrainlight.z*108/255, .5, .7);
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       whichhit=terrain.lineTerrain(oldtippoint[i],tippoint[i],&colpoint);
+                                       if(whichhit!=-1||tippoint[i].y<terrain.getHeight(tippoint[i].x,tippoint[i].z)){
+                                               if(whichhit!=-1)tippoint[i]=colpoint*terrain.scale;
+                                               else tippoint[i].y=terrain.getHeight(tippoint[i].x,tippoint[i].z);
+
+                                               terrainnormal=terrain.getNormal(tippoint[i].x,tippoint[i].z);
+                                               ReflectVector(&tipvelocity[i],&terrainnormal);
+                                               tippoint[i]+=terrainnormal*.002;
+                                               bounceness=terrainnormal*findLength(&tipvelocity[i])*(abs(normaldotproduct(tipvelocity[i],terrainnormal)));
+                                               if(findLengthfast(&tipvelocity[i])<findLengthfast(&bounceness))bounceness=0;
+                                               frictionness=abs(normaldotproduct(tipvelocity[i],terrainnormal));
+                                               tipvelocity[i]-=bounceness;
+                                               if(1-friction*frictionness>0)tipvelocity[i]*=1-friction*frictionness;
+                                               else tipvelocity[i]=0;
+                                               if(terrain.getOpacity(tippoint[i].x,tippoint[i].z)<.2)tipvelocity[i]+=bounceness*elasticity*.3;
+                                               else tipvelocity[i]+=bounceness*elasticity;
+
+                                               if(findLengthfast(&bounceness)>1){
+                                                       float gLoc[3];
+                                                       float vel[3];
+                                                       int whichsound;
+                                                       if(terrain.getOpacity(tippoint[i].x,tippoint[i].z)>.2){
+                                                               if(type[i]==staff)whichsound=footstepsound3+abs(Random()%2);
+                                                               if(type[i]!=staff)whichsound=clank1sound+abs(Random()%4);
+                                                       }
+                                                       else whichsound=footstepsound+abs(Random()%2);
+                                                       gLoc[0]=tippoint[i].x;
+                                                       gLoc[1]=tippoint[i].y;
+                                                       gLoc[2]=tippoint[i].z;
+                                                       vel[0]=0;
+                                                       vel[1]=0;
+                                                       vel[2]=0;
+                                                       PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                                                       if(terrain.getOpacity(tippoint[i].x,tippoint[i].z)>.2)FSOUND_SetVolume(channels[whichsound], 128*findLengthfast(&bounceness));
+                                                       else FSOUND_SetVolume(channels[whichsound], 32*findLengthfast(&bounceness));
+                                                       FSOUND_SetPaused(channels[whichsound], FALSE);
+
+                                                       if(terrain.getOpacity(tippoint[i].x,tippoint[i].z)<.2){
+                                                               XYZ terrainlight;
+                                                               terrainlight=terrain.getLighting(tippoint[i].x,tippoint[i].z);
+                                                               if(environment==snowyenvironment){
+                                                                       if(findDistancefast(&tippoint[i],&viewer)<viewdistance*viewdistance/4)sprites.MakeSprite(cloudsprite, tippoint[i],tipvelocity[i], terrainlight.x,terrainlight.y,terrainlight.z, .5, .7);
+                                                               }
+                                                               else if(environment==grassyenvironment){
+                                                                       if(findDistancefast(&tippoint[i],&viewer)<viewdistance*viewdistance/4)sprites.MakeSprite(cloudsprite, tippoint[i],tipvelocity[i], terrainlight.x*90/255,terrainlight.y*70/255,terrainlight.z*8/255, .5, .5);
+                                                               }
+                                                               else if(environment==desertenvironment){
+                                                                       if(findDistancefast(&tippoint[i],&viewer)<viewdistance*viewdistance/4)sprites.MakeSprite(cloudsprite, tippoint[i],tipvelocity[i], terrainlight.x*190/255,terrainlight.y*170/255,terrainlight.z*108/255, .5, .7);
+                                                               }
+                                                       }
+                                               }
+                                       }
+
+                                       //Edges
+                                       mid=position[i]+tippoint[i];
+                                       mid/=2;
+                                       mid+=(position[i]-mid)/20;
+                                       oldmid=mid;
+                                       if(mid.y<terrain.getHeight(mid.x,mid.z)){
+                                               hitsomething[i]=1;
+                                               mid.y=terrain.getHeight(mid.x,mid.z);
+
+                                               terrainnormal=terrain.getNormal(mid.x,mid.z);
+                                               ReflectVector(&velocity[i],&terrainnormal);
+                                               //mid+=terrainnormal*.002;
+                                               bounceness=terrainnormal*findLength(&velocity[i])*(abs(normaldotproduct(velocity[i],terrainnormal)));
+                                               if(findLengthfast(&velocity[i])<findLengthfast(&bounceness))bounceness=0;
+                                               frictionness=abs(normaldotproduct(velocity[i],terrainnormal));
+                                               velocity[i]-=bounceness;
+                                               if(1-friction*frictionness>0)velocity[i]*=1-friction*frictionness;
+                                               else velocity[i]=0;
+                                               if(terrain.getOpacity(mid.x,mid.z)<.2)velocity[i]+=bounceness*elasticity*.3;
+                                               else velocity[i]+=bounceness*elasticity;
+
+                                               if(findLengthfast(&bounceness)>1){
+                                                       float gLoc[3];
+                                                       float vel[3];
+                                                       int whichsound;
+                                                       if(terrain.getOpacity(mid.x,mid.z)>.2){
+                                                               if(type[i]==staff)whichsound=footstepsound3+abs(Random()%2);
+                                                               if(type[i]!=staff)whichsound=clank1sound+abs(Random()%4);
+                                                       }
+                                                       else whichsound=footstepsound+abs(Random()%2);
+                                                       gLoc[0]=mid.x;
+                                                       gLoc[1]=mid.y;
+                                                       gLoc[2]=mid.z;
+                                                       vel[0]=0;
+                                                       vel[1]=0;
+                                                       vel[2]=0;
+                                                       PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                                                       if(terrain.getOpacity(position[i].x,position[i].z)>.2)FSOUND_SetVolume(channels[whichsound], 128*findLengthfast(&bounceness));
+                                                       else FSOUND_SetVolume(channels[whichsound], 32*findLengthfast(&bounceness));
+                                                       FSOUND_SetPaused(channels[whichsound], FALSE);
+                                               }
+                                               position[i]+=(mid-oldmid)*20;
+                                       }
+
+                                       mid=position[i]+tippoint[i];
+                                       mid/=2;
+                                       mid+=(tippoint[i]-mid)/20;
+                                       oldmid=mid;
+                                       if(mid.y<terrain.getHeight(mid.x,mid.z)){
+                                               hitsomething[i]=1;
+                                               mid.y=terrain.getHeight(mid.x,mid.z);
+
+                                               terrainnormal=terrain.getNormal(mid.x,mid.z);
+                                               ReflectVector(&tipvelocity[i],&terrainnormal);
+                                               //mid+=terrainnormal*.002;
+                                               bounceness=terrainnormal*findLength(&tipvelocity[i])*(abs(normaldotproduct(tipvelocity[i],terrainnormal)));
+                                               if(findLengthfast(&tipvelocity[i])<findLengthfast(&bounceness))bounceness=0;
+                                               frictionness=abs(normaldotproduct(tipvelocity[i],terrainnormal));
+                                               tipvelocity[i]-=bounceness;
+                                               if(1-friction*frictionness>0)tipvelocity[i]*=1-friction*frictionness;
+                                               else tipvelocity[i]=0;
+                                               if(terrain.getOpacity(mid.x,mid.z)<.2)tipvelocity[i]+=bounceness*elasticity*.3;
+                                               else tipvelocity[i]+=bounceness*elasticity;
+
+                                               if(findLengthfast(&bounceness)>1){
+                                                       float gLoc[3];
+                                                       float vel[3];
+                                                       int whichsound;
+                                                       if(terrain.getOpacity(mid.x,mid.z)>.2){
+                                                               if(type[i]==staff)whichsound=footstepsound3+abs(Random()%2);
+                                                               if(type[i]!=staff)whichsound=clank1sound+abs(Random()%4);
+                                                       }
+                                                       else whichsound=footstepsound+abs(Random()%2);
+                                                       gLoc[0]=mid.x;
+                                                       gLoc[1]=mid.y;
+                                                       gLoc[2]=mid.z;
+                                                       vel[0]=0;
+                                                       vel[1]=0;
+                                                       vel[2]=0;
+                                                       PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                                                       FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                                                       if(terrain.getOpacity(position[i].x,position[i].z)>.2)FSOUND_SetVolume(channels[whichsound], 128*findLengthfast(&bounceness));
+                                                       else FSOUND_SetVolume(channels[whichsound], 32*findLengthfast(&bounceness));
+                                                       FSOUND_SetPaused(channels[whichsound], FALSE);
+                                               }
+                                               tippoint[i]+=(mid-oldmid)*20;
+                                       }
+                                       /*XYZ mid;
+                                       mid=position[i]+tippoint[i];
+                                       mid/=2;
+                                       if(position[i].y<terrain.getHeightExtrude(mid.x,mid.z,position[i].x,position[i].z)){
+                                       hitsomething[i]=1;
+                                       position[i].y=terrain.getHeightExtrude(mid.x,mid.z,position[i].x,position[i].z);
+
+                                       terrainnormal=terrain.getNormal(mid.x,mid.z);
+                                       ReflectVector(&velocity[i],&terrainnormal);
+                                       position[i]+=terrainnormal*.002;
+                                       bounceness=terrainnormal*findLength(&velocity[i])*(abs(normaldotproduct(velocity[i],terrainnormal)));
+                                       if(findLengthfast(&velocity[i])<findLengthfast(&bounceness))bounceness=0;
+                                       frictionness=abs(normaldotproduct(velocity[i],terrainnormal));
+                                       velocity[i]-=bounceness;
+                                       if(1-friction*frictionness>0)velocity[i]*=1-friction*frictionness;
+                                       else velocity[i]=0;
+                                       if(terrain.getOpacity(mid.x,mid.z)<.2)velocity[i]+=bounceness*elasticity*.3;
+                                       else velocity[i]+=bounceness*elasticity;
+
+                                       if(findLengthfast(&bounceness)>1){
+                                       float gLoc[3];
+                                       float vel[3];
+                                       int whichsound;
+                                       if(terrain.getOpacity(mid.x,mid.z)>.2){
+                                       if(type[i]==staff)whichsound=footstepsound3+abs(Random()%2);
+                                       if(type[i]!=staff)whichsound=clank1sound+abs(Random()%4);
+                                       }
+                                       else whichsound=footstepsound+abs(Random()%2);
+                                       gLoc[0]=position[i].x;
+                                       gLoc[1]=position[i].y;
+                                       gLoc[2]=position[i].z;
+                                       vel[0]=0;
+                                       vel[1]=0;
+                                       vel[2]=0;
+                                       PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                                       FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                                       if(terrain.getOpacity(position[i].x,position[i].z)>.2)FSOUND_SetVolume(channels[whichsound], 128*findLengthfast(&bounceness));
+                                       else FSOUND_SetVolume(channels[whichsound], 32*findLengthfast(&bounceness));
+                                       FSOUND_SetPaused(channels[whichsound], FALSE);
+                                       }
+                                       }
+
+                                       if(tippoint[i].y<terrain.getHeightExtrude(mid.x,mid.z,tippoint[i].x,tippoint[i].z)){
+                                       hitsomething[i]=1;
+                                       tippoint[i].y=terrain.getHeightExtrude(mid.x,mid.z,tippoint[i].x,tippoint[i].z);
+
+                                       terrainnormal=terrain.getNormal(mid.x,mid.z);
+                                       ReflectVector(&tipvelocity[i],&terrainnormal);
+                                       tippoint[i]+=terrainnormal*.002;
+                                       bounceness=terrainnormal*findLength(&tipvelocity[i])*(abs(normaldotproduct(tipvelocity[i],terrainnormal)));
+                                       if(findLengthfast(&tipvelocity[i])<findLengthfast(&bounceness))bounceness=0;
+                                       frictionness=abs(normaldotproduct(tipvelocity[i],terrainnormal));
+                                       tipvelocity[i]-=bounceness;
+                                       if(1-friction*frictionness>0)tipvelocity[i]*=1-friction*frictionness;
+                                       else tipvelocity[i]=0;
+                                       if(terrain.getOpacity(mid.x,mid.z)<.2)tipvelocity[i]+=bounceness*elasticity*.3;
+                                       else tipvelocity[i]+=bounceness*elasticity;
+
+                                       if(findLengthfast(&bounceness)>1){
+                                       float gLoc[3];
+                                       float vel[3];
+                                       int whichsound;
+                                       if(terrain.getOpacity(mid.x,mid.z)>.2){
+                                       if(type[i]==staff)whichsound=footstepsound3+abs(Random()%2);
+                                       if(type[i]!=staff)whichsound=clank1sound+abs(Random()%4);
+                                       }
+                                       else whichsound=footstepsound+abs(Random()%2);
+                                       gLoc[0]=tippoint[i].x;
+                                       gLoc[1]=tippoint[i].y;
+                                       gLoc[2]=tippoint[i].z;
+                                       vel[0]=0;
+                                       vel[1]=0;
+                                       vel[2]=0;
+                                       PlaySoundEx( whichsound, samp[whichsound], NULL, TRUE);
+                                       FSOUND_3D_SetAttributes(channels[whichsound], gLoc, vel);
+                                       if(terrain.getOpacity(tippoint[i].x,tippoint[i].z)>.2)FSOUND_SetVolume(channels[whichsound], 128*findLengthfast(&bounceness));
+                                       else FSOUND_SetVolume(channels[whichsound], 32*findLengthfast(&bounceness));
+                                       FSOUND_SetPaused(channels[whichsound], FALSE);
+                                       }
+                                       }*/
+
+                                       //Fix terrain edge collision
+                                       /*start=position[i];
+                                       end=tippoint[i];
+                                       whichhit=terrain.lineTerrain(start,end,&colpoint);
+                                       if(whichhit!=-1){
+                                       XYZ tippoi,posit;
+                                       tippoi=tippoint[i];
+                                       posit=position[i];
+
+
+                                       while(whichhit!=-1){
+                                       position[i].y+=.1;
+                                       tippoint[i].y+=.1;
+                                       velocity[i].y+=.1;
+                                       tipvelocity[i].y+=.1;
+                                       start=position[i];
+                                       end=tippoint[i];
+                                       whichhit=terrain.lineTerrain(start,end,&colpoint);
+                                       if(whichhit!=-1)
+                                       closestpoint=colpoint*terrain.scale;
+                                       }
+                                       position[i].y-=.1;
+                                       tippoint[i].y-=.1;
+                                       velocity[i].y-=.1;
+                                       tipvelocity[i].y-=.1;
+                                       start=position[i];
+                                       end=tippoint[i];
+                                       whichhit=terrain.lineTerrain(start,end,&colpoint);
+                                       while(whichhit!=-1){
+                                       position[i].y+=.01;
+                                       tippoint[i].y+=.01;
+                                       velocity[i].y+=.01;
+                                       tipvelocity[i].y+=.01;
+                                       start=position[i];
+                                       end=tippoint[i];
+                                       whichhit=terrain.lineTerrain(start,end,&colpoint);
+                                       if(whichhit!=-1)
+                                       closestpoint=colpoint*terrain.scale;
+                                       }
+                                       }*/
+                                       /*if(whichhit!=-1){
+                                       whichhit=terrain.lineTerrain(end,start,&closestswordpoint);
+                                       if(whichhit!=-1){
+                                       colpoint=(closestswordpoint*terrain.scale+colpoint*terrain.scale)/2;
+                                       proportion=findDistance(&tippoint[i],&colpoint)/findDistance(&position[i],&tippoint[i]);
+                                       if(proportion<=1){
+                                       while(whichhit!=-1){
+                                       position[i].y+=.1*proportion;
+                                       tippoint[i].y+=.1*(1-proportion);
+                                       velocity[i].y+=.1*proportion;
+                                       tipvelocity[i].y+=.1*(1-proportion);
+                                       start=position[i];
+                                       end=tippoint[i];
+                                       whichhit=terrain.lineTerrain(start,end,&colpoint);
+                                       }
+                                       position[i].y-=.1*proportion;
+                                       tippoint[i].y-=.1*(1-proportion);
+                                       velocity[i].y-=.1*proportion;
+                                       tipvelocity[i].y-=.1*(1-proportion);
+                                       start=position[i];
+                                       end=tippoint[i];
+                                       whichhit=terrain.lineTerrain(start,end,&colpoint);
+                                       while(whichhit!=-1){
+                                       position[i].y+=.01*proportion;
+                                       tippoint[i].y+=.01*(1-proportion);
+                                       velocity[i].y+=.01*proportion;
+                                       tipvelocity[i].y+=.01*(1-proportion);
+                                       start=position[i];
+                                       end=tippoint[i];
+                                       whichhit=terrain.lineTerrain(start,end,&colpoint);
+                                       }
+                                       }
+                                       }
+                                       }
+                                       */
+                                       //Gravity
+                                       velocity[i].y+=gravity*multiplier;
+                                       tipvelocity[i].y+=gravity*multiplier;
+                                       //position[i].y+=gravity*multiplier*multiplier;
+                                       //tippoint[i].y+=gravity*multiplier*multiplier;
+
+                                       //Rotation
+                                       XYZ temppoint1,temppoint2,tempforward;
+                                       float distance;
+
+                                       temppoint1=position[i];
+                                       temppoint2=tippoint[i];
+                                       distance=findDistance(&temppoint1,&temppoint2);
+                                       rotation2[i]=asin((temppoint1.y-temppoint2.y)/distance);
+                                       rotation2[i]*=360/6.28;
+                                       temppoint1.y=0;
+                                       temppoint2.y=0;
+                                       rotation1[i]=acos((temppoint1.z-temppoint2.z)/findDistance(&temppoint1,&temppoint2));
+                                       rotation1[i]*=360/6.28;
+                                       rotation3[i]=0;
+                                       smallrotation[i]=90;
+                                       smallrotation2[i]=0;
+                                       bigtilt[i]=0;
+                                       bigtilt2[i]=0;
+                                       bigrotation[i]=0;
+                                       if(temppoint1.x>temppoint2.x)rotation1[i]=360-rotation1[i];
+
+                                       //Stop moving
+                                       if(findLengthfast(&velocity[i])<.3&&findLengthfast(&tipvelocity[i])<.3&&hitsomething[i]){
+                                               freetime[i]+=multiplier;
+                                       }
+
+                                       //velocity[i]=(position[i]-oldposition[i])/multiplier;
+                                       //tipvelocity[i]==(tippoint[i-+oldtippoint[i])/multiplier;                      
+                                       if(freetime[i]>.4){
+                                               velocity[i]=0;
+                                               tipvelocity[i]=0;
+                                       }
+                                       firstfree[i]=0;
+                       }
+               }
+               multiplier=tempmult;
+               if(blooddrip[i]&&bloody[i]){
+                       blooddripdelay[i]-=blooddrip[i]*multiplier/2;
+                       blooddrip[i]-=multiplier;
+                       if(blooddrip[i]<0)blooddrip[i]=0;
+                       if(blooddrip[i]>5)blooddrip[i]=5;
+                       if(blooddripdelay[i]<0&&bloodtoggle){
+                               blooddripdelay[i]=1;
+                               XYZ bloodvel;
+                               XYZ bloodloc;
+                               bloodloc=position[i]+(tippoint[i]-position[i])*.7;
+                               bloodloc.y-=.05;
+                               if(bloodtoggle){
+                                       bloodvel=0;
+                                       sprites.MakeSprite(bloodsprite, bloodloc,bloodvel, 1,1,1, .03, 1);
+                               }                       
+                       }
+               }
+               if(onfire[i]){
+                       flamedelay[i]-=multiplier;
+                       if(onfire[i]&&flamedelay[i]<=0){
+                               flamedelay[i]=.020;
+                               flamedelay[i]-=multiplier;
+                               normalrot=0;
+                               if(owner[i]!=-1){
+                                       normalrot=player[owner[i]].velocity;
+                               }
+                               normalrot.y+=1;
+                               if(owner[i]!=-1){
+                                       if(player[owner[i]].onterrain){
+                                               normalrot.y=1;
+                                       }
+                               }
+                               sprites.MakeSprite(weaponflamesprite, position[i]+tippoint[i]*(((float)abs(Random()%100))/600+.05),normalrot, 1,1,1, (.6+(float)abs(Random()%100)/200-.25)*1/3, 1);
+                               sprites.speed[sprites.numsprites-1]=4;
+                               sprites.alivetime[sprites.numsprites-1]=.3;
+                       }
+               }
+
+               if(!onfire[i]&&owner[i]==-1&&type[i]!=staff){
+                       flamedelay[i]-=multiplier;
+                       if(flamedelay[i]<=0){
+                               flamedelay[i]=.020;
+                               flamedelay[i]-=multiplier;
+                               normalrot=0;
+                               if(Random()%50==0&&findDistancefast(&position[i],&viewer)>80){
+                                       XYZ shinepoint;
+                                       shinepoint=position[i]+(tippoint[i]-position[i])*(((float)abs(Random()%100))/100);
+                                       sprites.MakeSprite(weaponshinesprite, shinepoint,normalrot, 1,1,1, (.1+(float)abs(Random()%100)/200-.25)*1/3*fast_sqrt(findDistance(&shinepoint,&viewer)), 1);
+                                       sprites.speed[sprites.numsprites-1]=4;
+                                       sprites.alivetime[sprites.numsprites-1]=.3;
+                               }
+                       }
+               }
+       }
+}
+
+int Weapons::Draw()
+{
+       static int i,j;
+       static XYZ terrainlight;
+       static GLfloat M[16];
+       static bool draw;
+       glAlphaFunc(GL_GREATER, 0.9);
+       glEnable(GL_TEXTURE_2D);
+       glEnable(GL_BLEND);
+       glEnable(GL_CULL_FACE);
+       glCullFace(GL_FRONT);
+       glDepthMask(1);
+       for(i=0;i<numweapons;i++)
+       {
+               if((frustum.SphereInFrustum(position[i].x,position[i].y,position[i].z,1)&&findDistancefast(&viewer,&position[i])<viewdistance*viewdistance))
+               {
+                       draw=0;
+                       if(owner[i]==-1)
+                       {
+                               draw=1;
+                               if(velocity[i].x&&!physics[i])drawhowmany[i]=10;
+                               else drawhowmany[i]=1;
+                       }
+                       if(owner[i]!=-1)
+                       {
+                               if(player[owner[i]].occluded<25)
+                                       if((frustum.SphereInFrustum(player[owner[i]].coords.x,player[owner[i]].coords.y+player[owner[i]].scale*3,player[owner[i]].coords.z,player[owner[i]].scale*8)&&findDistancefast(&viewer,&player[owner[i]].coords)<viewdistance*viewdistance)||player[owner[i]].skeleton.free==3)
+                                               draw=1;
+                               if((player[owner[i]].targetanimation==knifeslashstartanim||player[owner[i]].targetanimation==swordsneakattackanim||(player[owner[i]].currentanimation==staffhitanim&&player[owner[i]].currentframe>1)||(player[owner[i]].currentanimation==staffhitreversedanim&&player[owner[i]].currentframe>1)||(player[owner[i]].currentanimation==staffspinhitanim&&player[owner[i]].currentframe>1)||(player[owner[i]].currentanimation==staffspinhitreversedanim&&player[owner[i]].currentframe>1)||(player[owner[i]].currentanimation==staffgroundsmashanim&&player[owner[i]].currentframe>1)||(player[owner[i]].targetanimation==swordslashanim&&player[owner[i]].targetframe<7)||player[owner[i]].targetanimation==crouchstabanim||player[owner[i]].targetanimation==swordslashreversalanim||player[owner[i]].targetanimation==swordslashreversedanim||player[owner[i]].targetanimation==knifefollowanim||player[owner[i]].targetanimation==swordgroundstabanim||player[owner[i]].targetanimation==knifethrowanim)&&player[owner[i]].targetanimation==lastdrawnanim[i]&&!player[owner[i]].skeleton.free)
+                               {
+                                       drawhowmany[i]=10;
+                               }
+                               else drawhowmany[i]=1;
+                               if(player[owner[i]].targetanimation==swordgroundstabanim)
+                               {
+                                       lastdrawnrotation1[i]=rotation1[i];
+                                       lastdrawnrotation2[i]=rotation2[i];
+                                       lastdrawnrotation3[i]=rotation3[i];
+                                       lastdrawnbigrotation[i]=bigrotation[i];
+                                       lastdrawnbigtilt[i]=bigtilt[i];
+                                       lastdrawnbigtilt2[i]=bigtilt2[i];
+                                       lastdrawnsmallrotation[i]=smallrotation[i];
+                                       lastdrawnsmallrotation2[i]=smallrotation2[i];
+                               }
+                       }
+                       if(draw)
+                       {
+                               terrainlight=terrain.getLighting(position[i].x,position[i].z);
+                               if(drawhowmany[i]>0)
+                               {
+                                       glAlphaFunc(GL_GREATER, 0.01);
+                               }
+                               for(j=drawhowmany[i];j>0;j--)
+                               {
+                                       glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                                       glPushMatrix();
+                                               glColor4f(terrainlight.x,terrainlight.y,terrainlight.z,j/drawhowmany[i]);
+                                               if(owner[i]!=-1)glTranslatef(position[i].x*(((float)(j))/drawhowmany[i])+lastdrawnposition[i].x*(1-((float)(j))/drawhowmany[i]),position[i].y*(((float)(j))/drawhowmany[i])-.02+lastdrawnposition[i].y*(1-((float)(j))/drawhowmany[i]),position[i].z*(((float)(j))/drawhowmany[i])+lastdrawnposition[i].z*(1-((float)(j))/drawhowmany[i]));             
+                                               if(owner[i]==-1)glTranslatef(position[i].x*(((float)(j))/drawhowmany[i])+lastdrawnposition[i].x*(1-((float)(j))/drawhowmany[i]),position[i].y*(((float)(j))/drawhowmany[i])+lastdrawnposition[i].y*(1-((float)(j))/drawhowmany[i]),position[i].z*(((float)(j))/drawhowmany[i])+lastdrawnposition[i].z*(1-((float)(j))/drawhowmany[i]));                 
+                                               //glTranslatef(position[i].x,position[i].y-.02,position[i].z);
+                                               glRotatef(bigrotation[i]*(((float)(j))/drawhowmany[i])+lastdrawnbigrotation[i]*(1-((float)(j))/drawhowmany[i]),0,1,0);
+                                               glRotatef(bigtilt2[i]*(((float)(j))/drawhowmany[i])+lastdrawnbigtilt2[i]*(1-((float)(j))/drawhowmany[i]),1,0,0);
+                                               glRotatef(bigtilt[i]*(((float)(j))/drawhowmany[i])+lastdrawnbigtilt[i]*(1-((float)(j))/drawhowmany[i]),0,0,1);
+                                               glRotatef(-rotation1[i]*(((float)(j))/drawhowmany[i])-lastdrawnrotation1[i]*(1-((float)(j))/drawhowmany[i])+90,0,1,0);
+                                               glRotatef(-rotation2[i]*(((float)(j))/drawhowmany[i])-lastdrawnrotation2[i]*(1-((float)(j))/drawhowmany[i])+90,0,0,1);
+                                               glRotatef(-rotation3[i]*(((float)(j))/drawhowmany[i])-lastdrawnrotation3[i]*(1-((float)(j))/drawhowmany[i]),0,1,0);
+                                               glRotatef(smallrotation[i]*(((float)(j))/drawhowmany[i])+lastdrawnsmallrotation[i]*(1-((float)(j))/drawhowmany[i]),1,0,0);
+                                               glRotatef(smallrotation2[i]*(((float)(j))/drawhowmany[i])+lastdrawnsmallrotation2[i]*(1-((float)(j))/drawhowmany[i]),0,1,0);
+
+                                               if(owner[i]!=-1)
+                                               {
+                                                       if(player[owner[i]].targetanimation==staffhitanim||player[owner[i]].currentanimation==staffhitanim||player[owner[i]].targetanimation==staffhitreversedanim||player[owner[i]].currentanimation==staffhitreversedanim)
+                                                       {
+                                                               glTranslatef(0,0,-.3);
+                                                       }
+                                                       if(player[owner[i]].targetanimation==staffgroundsmashanim||player[owner[i]].currentanimation==staffgroundsmashanim||player[owner[i]].targetanimation==staffspinhitreversedanim||player[owner[i]].currentanimation==staffspinhitreversedanim||player[owner[i]].targetanimation==staffspinhitanim||player[owner[i]].currentanimation==staffspinhitanim)
+                                                       {
+                                                               glTranslatef(0,0,-.1);
+                                                       }
+                                               }
+                                               /*if(type[i]==knife){
+                                               if(owner[i]==-1){
+                                               if(!physics[i]&&findDistance(&position[i],&oldposition[i])*5>1)glScalef(1,1,findDistance(&position[i],&oldposition[i])*5);
+                                               }
+                                               }*/
+
+                                               if(type[i]==knife)
+                                               {
+                                                       glEnable(GL_LIGHTING);  
+                                                       if(!bloody[i]||!bloodtoggle)throwingknifemodel.drawdifftex(knifetextureptr);
+                                                       if(bloodtoggle)
+                                                       {
+                                                               if(bloody[i]==1)throwingknifemodel.drawdifftex(lightbloodknifetextureptr);
+                                                               if(bloody[i]==2)throwingknifemodel.drawdifftex(bloodknifetextureptr);
+                                                       }
+                                               }
+                                               if(type[i]==sword)
+                                               {
+                                                       glEnable(GL_LIGHTING);  
+                                                       if(!bloody[i]||!bloodtoggle)swordmodel.drawdifftex(swordtextureptr);
+                                                       if(bloodtoggle)
+                                                       {
+                                                               if(bloody[i]==1)swordmodel.drawdifftex(lightbloodswordtextureptr);
+                                                               if(bloody[i]==2)swordmodel.drawdifftex(bloodswordtextureptr);
+                                                       }
+                                               }
+                                               if(type[i]==staff)
+                                               {
+                                                       glEnable(GL_LIGHTING);  
+                                                       staffmodel.drawdifftex(stafftextureptr);
+                                               }
+
+                                       glPopMatrix();
+                               }
+
+                               lastdrawnposition[i]=position[i];
+                               lastdrawntippoint[i]=tippoint[i];
+                               lastdrawnrotation1[i]=rotation1[i];
+                               lastdrawnrotation2[i]=rotation2[i];
+                               lastdrawnrotation3[i]=rotation3[i];
+                               lastdrawnbigrotation[i]=bigrotation[i];
+                               lastdrawnbigtilt[i]=bigtilt[i];
+                               lastdrawnbigtilt2[i]=bigtilt2[i];
+                               lastdrawnsmallrotation[i]=smallrotation[i];
+                               lastdrawnsmallrotation2[i]=smallrotation2[i];
+                               if(owner[i]!=-1)lastdrawnanim[i]=player[owner[i]].currentanimation;
+                       }
+                       if(owner[i]!=-1)
+                       {
+                               glMatrixMode(GL_MODELVIEW);                                                     // Select The Modelview Matrix
+                               glPushMatrix();
+                                       glLoadIdentity();
+                                       glTranslatef(position[i].x,position[i].y-.02,position[i].z);
+                                       glRotatef(bigrotation[i],0,1,0);
+                                       glRotatef(bigtilt2[i],1,0,0);
+                                       glRotatef(bigtilt[i],0,0,1);
+                                       glRotatef(-rotation1[i]+90,0,1,0);
+                                       glRotatef(-rotation2[i]+90,0,0,1);
+                                       glRotatef(-rotation3[i],0,1,0);
+                                       glRotatef(smallrotation[i],1,0,0);
+                                       glRotatef(smallrotation2[i],0,1,0);
+                                       glTranslatef(0,0,length[i]);            
+                                       glGetFloatv(GL_MODELVIEW_MATRIX,M);
+                                       tippoint[i].x=M[12];
+                                       tippoint[i].y=M[13];
+                                       tippoint[i].z=M[14];
+                               glPopMatrix();
+                       }
+                       /*XYZ shinepoint;
+                       XYZ nothingpoint;
+                       nothingpoint=0;
+                       shinepoint=position[i];
+                       sprites.MakeSprite(weaponshinesprite, shinepoint,nothingpoint, 1,1,1,multiplier*2, 1);
+                       sprites.speed[sprites.numsprites-1]=4;
+                       sprites.alivetime[sprites.numsprites-1]=.3;
+                       shinepoint=tippoint[i];
+                       sprites.MakeSprite(weaponshinesprite, shinepoint,nothingpoint, 1,1,1,multiplier*2, 1);
+                       sprites.speed[sprites.numsprites-1]=4;
+                       sprites.alivetime[sprites.numsprites-1]=.3;*/
+               }
+       }
+       return 0;
+}
+
+Weapons::Weapons()
+{
+       rotation1.resize(max_weaponinstances);
+       rotation2.resize(max_weaponinstances);
+       rotation3.resize(max_weaponinstances);
+       bigrotation.resize(max_weaponinstances);
+       bigtilt.resize(max_weaponinstances);
+       bigtilt2.resize(max_weaponinstances);
+       smallrotation.resize(max_weaponinstances);
+       smallrotation2.resize(max_weaponinstances);
+       damage.resize(max_weaponinstances);
+
+       numweapons = 0;
+       tippoint.resize(max_weaponinstances);
+       oldtippoint.resize(max_weaponinstances);
+       position.resize(max_weaponinstances);
+       lastmult.resize(max_weaponinstances);
+       oldposition.resize(max_weaponinstances);
+       velocity.resize(max_weaponinstances);
+       tipvelocity.resize(max_weaponinstances);
+       type.resize(max_weaponinstances);
+       oldowner.resize(max_weaponinstances);
+       owner.resize(max_weaponinstances);
+       bloody.resize(max_weaponinstances);
+       blooddrip.resize(max_weaponinstances);
+       blooddripdelay.resize(max_weaponinstances);
+       onfire.resize(max_weaponinstances);
+       flamedelay.resize(max_weaponinstances);
+       missed.resize(max_weaponinstances);
+       mass.resize(max_weaponinstances);
+       tipmass.resize(max_weaponinstances);
+       length.resize(max_weaponinstances);
+       freetime.resize(max_weaponinstances);
+       firstfree.resize(max_weaponinstances);
+       physics.resize(max_weaponinstances);
+       drawhowmany.resize(max_weaponinstances);
+       hitsomething.resize(max_weaponinstances);
+
+       lastdrawnposition.resize(max_weaponinstances);
+       lastdrawntippoint.resize(max_weaponinstances);
+       lastdrawnrotation1.resize(max_weaponinstances);
+       lastdrawnrotation2.resize(max_weaponinstances);
+       lastdrawnrotation3.resize(max_weaponinstances);
+       lastdrawnbigrotation.resize(max_weaponinstances);
+       lastdrawnbigtilt.resize(max_weaponinstances);
+       lastdrawnbigtilt2.resize(max_weaponinstances);
+       lastdrawnsmallrotation.resize(max_weaponinstances);
+       lastdrawnsmallrotation2.resize(max_weaponinstances);
+       lastdrawnanim.resize(max_weaponinstances);
+
+       //              Model throwingknifemodel;
+       knifetextureptr = 0;
+       lightbloodknifetextureptr = 0;
+       bloodknifetextureptr = 0;
+
+       //              Model swordmodel;
+       swordtextureptr = 0;
+       lightbloodswordtextureptr = 0;
+       bloodswordtextureptr = 0;
+
+       //              Model staffmodel;
+       stafftextureptr = 0;
+}
+
+Weapons::~Weapons()
+{
+       if (stafftextureptr) glDeleteTextures( 1, (const unsigned long *)&stafftextureptr );
+       if (knifetextureptr) glDeleteTextures( 1, (const unsigned long *)&knifetextureptr );
+       if (lightbloodknifetextureptr) glDeleteTextures( 1, (const unsigned long *)&lightbloodknifetextureptr );
+       if (bloodknifetextureptr) glDeleteTextures( 1, (const unsigned long *)&bloodknifetextureptr );
+       if (swordtextureptr) glDeleteTextures( 1, (const unsigned long *)&swordtextureptr );
+       if (lightbloodswordtextureptr) glDeleteTextures( 1, (const unsigned long *)&lightbloodswordtextureptr );
+       if (bloodswordtextureptr) glDeleteTextures( 1, (const unsigned long *)&bloodswordtextureptr );
+}
diff --git a/Source/Weapons.h b/Source/Weapons.h
new file mode 100644 (file)
index 0000000..36f18de
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef _WEAPONS_H_
+#define _WEAPONS_H_
+
+/**> HEADER FILES <**/
+
+#include "gl.h"
+#include "Quaternions.h"
+#include "fmod.h"
+#include "skeleton.h"
+#include "models.h"
+#include "Constants.h"
+#include "Terrain.h"
+#include "Sprites.h"
+#include "Person.h"
+#include <cmath>
+
+#define max_weapons 30
+#define max_weaponinstances 20
+
+#define knife 1
+#define sword 2
+#define staff 3
+
+class Weapons
+{
+public:
+
+       std::vector<float> rotation1,rotation2,rotation3;
+       std::vector<float> bigrotation;
+       std::vector<float> bigtilt;
+       std::vector<float> bigtilt2;
+       std::vector<float> smallrotation;
+       std::vector<float> smallrotation2;
+
+       int numweapons;
+       std::vector<float> damage;
+       std::vector<XYZ> tippoint;
+       std::vector<XYZ> oldtippoint;
+       std::vector<XYZ> position;
+       std::vector<float> lastmult;
+       std::vector<XYZ> oldposition;
+       std::vector<XYZ> velocity;
+       std::vector<XYZ> tipvelocity;
+       std::vector<int> type;
+       std::vector<int> oldowner;
+       std::vector<int> owner;
+       std::vector<int> bloody;
+       std::vector<float> blooddrip;
+       std::vector<float> blooddripdelay;
+       std::vector<bool> onfire;
+       std::vector<float> flamedelay;
+       std::vector<bool> missed;
+       std::vector<float> mass;
+       std::vector<float> tipmass;
+       std::vector<float> length;
+       std::vector<float> freetime;
+       std::vector<bool> firstfree;
+       std::vector<bool> physics;
+       std::vector<float> drawhowmany;
+       std::vector<bool> hitsomething;
+
+       std::vector<XYZ> lastdrawnposition;
+       std::vector<XYZ> lastdrawntippoint;
+       std::vector<float> lastdrawnrotation1,lastdrawnrotation2,lastdrawnrotation3;
+       std::vector<float> lastdrawnbigrotation;
+       std::vector<float> lastdrawnbigtilt;
+       std::vector<float> lastdrawnbigtilt2;
+       std::vector<float> lastdrawnsmallrotation;
+       std::vector<float> lastdrawnsmallrotation2;
+       std::vector<int> lastdrawnanim;
+
+       Model throwingknifemodel;
+       GLuint knifetextureptr;
+       GLuint lightbloodknifetextureptr;
+       GLuint bloodknifetextureptr;
+
+       Model swordmodel;
+       GLuint swordtextureptr;
+       GLuint lightbloodswordtextureptr;
+       GLuint bloodswordtextureptr;
+
+       Model staffmodel;
+       GLuint stafftextureptr;
+
+       int Draw();
+       void DoStuff();
+
+       Weapons();
+
+       ~Weapons();
+};
+
+#endif
\ No newline at end of file
diff --git a/Source/WinDefs.cpp b/Source/WinDefs.cpp
new file mode 100644 (file)
index 0000000..f6cba9a
--- /dev/null
@@ -0,0 +1,108 @@
+/**> HEADER FILES <**/
+#include "WinDefs.h"
+#include <windows.h>
+#include <errno.h>
+#include <time.h>
+#include <stdio.h>
+
+
+class AppTime
+{
+public:
+       AppTime()
+       {
+               counterRate = 1;
+               baseCounter = 0;
+               QueryPerformanceFrequency( (LARGE_INTEGER*)&counterRate);
+               QueryPerformanceCounter( (LARGE_INTEGER*)&baseCounter);
+       }
+       __int64 counterRate;            // LARGE_INTEGER type has no math functions so use int64
+       __int64 baseCounter;
+};
+static AppTime g_appTime;
+
+
+
+void CopyCStringToPascal( const char* src, unsigned char dst[256])
+{
+       int len = strlen( src);
+       dst[ 0] = len;
+       memcpy( dst + 1, src, len);
+}
+
+
+void CopyPascalStringToC( const unsigned char* src, char* dst)
+{
+       int len = src[ 0];
+       memcpy( dst, src + 1, len);
+       dst[ len] = 0;
+}
+
+
+AbsoluteTime UpTime()
+{
+       __int64 counter;
+       QueryPerformanceCounter( (LARGE_INTEGER*)&counter);
+
+       counter -= g_appTime.baseCounter;
+
+       AbsoluteTime time;
+       time.lo = (unsigned long)counter;
+       time.hi = (unsigned long)(counter >> 32);
+       return time;
+}
+
+
+Duration AbsoluteDeltaToDuration( AbsoluteTime& a, AbsoluteTime& b)
+{
+       __int64 value = a.hi;
+       value <<= 32;
+       value |= a.lo;
+       __int64 value2 = b.hi;
+       value2 <<= 32;
+       value2 |= b.lo;
+       value -= value2;
+
+       if (value <= 0)
+               return durationImmediate;
+
+       __int64 frac = value % g_appTime.counterRate;
+       value /= g_appTime.counterRate;
+
+       Duration time;
+
+       if (value == 0)
+       {
+               frac *= -1000000;
+               frac /= g_appTime.counterRate;
+               time = (Duration)frac;
+       }
+       else
+       {
+               frac *= 1000;
+               frac /= g_appTime.counterRate;
+               value *= 1000;
+               value += frac;
+               time = (Duration)value;
+       }
+
+       return time;
+}
+
+
+static char g_filename[ 256];
+char* ConvertFileName( const char* orgfilename)
+{
+       // translate filename into proper path name
+       if (orgfilename[ 0] == ':')
+               orgfilename++;
+       strcpy( g_filename, orgfilename);
+
+       for (int n = 0; g_filename[ n]; n++)
+       {
+               if (g_filename[ n] == ':')
+                       g_filename[ n] = '/';
+       }
+
+       return g_filename;
+}
diff --git a/Source/WinDefs.h b/Source/WinDefs.h
new file mode 100644 (file)
index 0000000..478c744
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef _WINDEFS_H_
+#define _WINDEFS_H_
+#ifdef WIN32
+
+
+#include <stdio.h>
+#include <float.h>
+
+// stuff to make Mac code compatable with Windows
+
+
+// disable warnings about double to float conversions
+#pragma warning(disable:4305)
+#pragma warning(disable:4244)
+
+// disable warnings about boolean to int conversions
+#pragma warning(disable:4800)
+
+// disable warning about unreferenced local variables
+#pragma warning(disable:4101)
+
+typedef bool Boolean;
+
+
+struct Point
+{
+       short v;
+       short h;
+};
+
+typedef signed char SInt8;
+typedef unsigned int UInt32;
+
+
+#include "Random.h"
+
+
+void CopyCStringToPascal( const char* src, unsigned char dst[256]);
+void CopyPascalStringToC( const unsigned char* src, char* dst);
+
+
+typedef struct AbsoluteTime
+{
+       unsigned long   hi;
+       unsigned long   lo;
+} AbsoluteTime; 
+
+AbsoluteTime UpTime();         // NOTE: returns time since app started, not system start
+
+typedef long Duration; 
+
+enum
+{
+       durationMicrosecond             = -1,
+       durationMillisecond             = 1,
+       durationSecond                  = 1000,
+       durationMinute                  = 1000 * 60,
+       durationHour                    = 1000 * 60 * 60,
+       durationDay                     = 1000 * 60 * 60 * 24,
+       durationForever                 = 0x7FFFFFFF,
+       durationImmediate               = 0,
+}; 
+
+Duration AbsoluteDeltaToDuration( AbsoluteTime& a, AbsoluteTime& b);
+
+
+inline bool isnormal( double x)
+{
+       int ret = _fpclass( x);
+       return (ret == _FPCLASS_NN || ret == _FPCLASS_PN);
+}
+
+typedef unsigned int uintptr_t;
+
+
+// fix file names to use '/' instead of ':'
+char* ConvertFileName( const char* orgfilename);
+
+#define fopen( a, b) fopen( ConvertFileName( a), b);
+/*
+inline float abs( float f)
+{
+if (f < 0)
+return -f;
+return f;
+}
+
+inline double abs( double f)
+{
+if (f < 0)
+return -f;
+return f;
+}
+*/
+inline long long abs( long long f)
+{
+       if (f < 0)
+               return -f;
+       return f;
+}
+#endif
+#endif
\ No newline at end of file
diff --git a/Source/WinInput.cpp b/Source/WinInput.cpp
new file mode 100644 (file)
index 0000000..856bf12
--- /dev/null
@@ -0,0 +1,989 @@
+/**> HEADER FILES <**/
+#include "WinInput.h"
+#include "String.h"
+
+extern bool keyboardfrozen;
+extern bool buttons[3];
+/********************> IsKeyDown() <*****/
+Boolean        IsKeyDown( unsigned char *keyMap, unsigned short theKey )
+{
+       if(keyboardfrozen)return 0;
+       if(theKey< 0x80 /*1000*/){
+               static long     keyMapIndex;
+               static Boolean  isKeyDown;
+               static short    bitToCheck;
+
+               // Calculate the key map index
+               keyMapIndex = keyMap[theKey/8];
+
+               // Calculate the individual bit to check
+               bitToCheck = theKey%8;
+
+               // Check the status of the key
+               isKeyDown = ( keyMapIndex >> bitToCheck ) & 0x01;
+
+               // Return the status of the key
+               return isKeyDown;
+       }
+       else if(theKey==MAC_MOUSEBUTTON1)
+               return buttons[0];
+       else if(theKey==MAC_MOUSEBUTTON2)
+               return buttons[1];
+
+       return 0;
+}
+
+unsigned short         CharToKey(char* which)
+{
+       // alphabetic keys
+       if(!stricmp(which,"a")){
+               return MAC_A_KEY;
+       }
+       if(!stricmp(which,"b")){
+               return MAC_B_KEY;
+       }
+       if(!stricmp(which,"c")){
+               return MAC_C_KEY;
+       }
+       if(!stricmp(which,"d")){
+               return MAC_D_KEY;
+       }
+       if(!stricmp(which,"e")){
+               return MAC_E_KEY;
+       }
+       if(!stricmp(which,"f")){
+               return MAC_F_KEY;
+       }
+       if(!stricmp(which,"g")){
+               return MAC_G_KEY;
+       }
+       if(!stricmp(which,"h")){
+               return MAC_H_KEY;
+       }
+       if(!stricmp(which,"i")){
+               return MAC_I_KEY;
+       }
+       if(!stricmp(which,"j")){
+               return MAC_J_KEY;
+       }
+       if(!stricmp(which,"k")){
+               return MAC_K_KEY;
+       }
+       if(!stricmp(which,"l")){
+               return MAC_L_KEY;
+       }
+       if(!stricmp(which,"m")){
+               return MAC_M_KEY;
+       }
+       if(!stricmp(which,"n")){
+               return MAC_N_KEY;
+       }
+       if(!stricmp(which,"o")){
+               return MAC_O_KEY;
+       }
+       if(!stricmp(which,"p")){
+               return MAC_P_KEY;
+       }
+       if(!stricmp(which,"q")){
+               return MAC_Q_KEY;
+       }
+       if(!stricmp(which,"r")){
+               return MAC_R_KEY;
+       }
+       if(!stricmp(which,"s")){
+               return MAC_S_KEY;
+       }
+       if(!stricmp(which,"t")){
+               return MAC_T_KEY;
+       }
+       if(!stricmp(which,"u")){
+               return MAC_U_KEY;
+       }
+       if(!stricmp(which,"v")){
+               return MAC_V_KEY;
+       }
+       if(!stricmp(which,"w")){
+               return MAC_W_KEY;
+       }
+       if(!stricmp(which,"x")){
+               return MAC_X_KEY;
+       }
+       if(!stricmp(which,"y")){
+               return MAC_Y_KEY;
+       }
+       if(!stricmp(which,"z")){
+               return MAC_Z_KEY;
+       }
+
+       // keypad keys
+       if(!stricmp(which,"KP0")){
+               return MAC_NUMPAD_0_KEY;
+       }
+       if(!stricmp(which,"KP1")){
+               return MAC_NUMPAD_1_KEY;
+       }
+       if(!stricmp(which,"KP2")){
+               return MAC_NUMPAD_2_KEY;
+       }
+       if(!stricmp(which,"KP3")){
+               return MAC_NUMPAD_3_KEY;
+       }
+       if(!stricmp(which,"KP4")){
+               return MAC_NUMPAD_4_KEY;
+       }
+       if(!stricmp(which,"KP5")){
+               return MAC_NUMPAD_5_KEY;
+       }
+       if(!stricmp(which,"KP6")){
+               return MAC_NUMPAD_6_KEY;
+       }
+       if(!stricmp(which,"KP7")){
+               return MAC_NUMPAD_7_KEY;
+       }
+       if(!stricmp(which,"KP8")){
+               return MAC_NUMPAD_8_KEY;
+       }
+       if(!stricmp(which,"KP9")){
+               return MAC_NUMPAD_9_KEY;
+       }
+
+       // enter
+       if(!stricmp(which,"enter")){
+               return MAC_ENTER_KEY;
+       }
+
+       // number keys
+       if(!stricmp(which,"0")){
+               return MAC_0_KEY;
+       }
+       if(!stricmp(which,"1")){
+               return MAC_1_KEY;
+       }
+       if(!stricmp(which,"2")){
+               return MAC_2_KEY;
+       }
+       if(!stricmp(which,"3")){
+               return MAC_3_KEY;
+       }
+       if(!stricmp(which,"4")){
+               return MAC_4_KEY;
+       }
+       if(!stricmp(which,"5")){
+               return MAC_5_KEY;
+       }
+       if(!stricmp(which,"6")){
+               return MAC_6_KEY;
+       }
+       if(!stricmp(which,"7")){
+               return MAC_7_KEY;
+       }
+       if(!stricmp(which,"8")){
+               return MAC_8_KEY;
+       }
+       if(!stricmp(which,"9")){
+               return MAC_9_KEY;
+       }
+
+       // function keys
+       if(!stricmp(which,"F1")){
+               return MAC_F1_KEY;
+       }
+       if(!stricmp(which,"F2")){
+               return MAC_F2_KEY;
+       }
+       if(!stricmp(which,"F3")){
+               return MAC_F3_KEY;
+       }
+       if(!stricmp(which,"F4")){
+               return MAC_F4_KEY;
+       }
+       if(!stricmp(which,"F5")){
+               return MAC_F5_KEY;
+       }
+       if(!stricmp(which,"F6")){
+               return MAC_F6_KEY;
+       }
+       if(!stricmp(which,"F7")){
+               return MAC_F7_KEY;
+       }
+       if(!stricmp(which,"F8")){
+               return MAC_F8_KEY;
+       }
+       if(!stricmp(which,"F9")){
+               return MAC_F9_KEY;
+       }
+       if(!stricmp(which,"F10")){
+               return MAC_F10_KEY;
+       }
+       if(!stricmp(which,"F11")){
+               return MAC_F11_KEY;
+       }
+       if(!stricmp(which,"F12")){
+               return MAC_F12_KEY;
+       }
+
+       // escape
+       if(!stricmp(which,"escape")){
+               return MAC_ESCAPE_KEY;
+       }
+       if(!stricmp(which,"backspace")){
+               return MAC_DELETE_KEY;
+       }
+       if(!stricmp(which,"tab")){
+               return MAC_TAB_KEY;
+       }
+       if(!stricmp(which,"`")){
+               return MAC_TILDE_KEY;
+       }
+       if(!stricmp(which,"caps_lock")){
+               return MAC_CAPS_LOCK_KEY;
+       }
+//     if(which==){
+//             return "";
+//     }
+       if(!stricmp(which,"command")){
+               return MAC_COMMAND_KEY;
+       }
+       if(!stricmp(which,"option")){
+               return MAC_OPTION_KEY;
+       }
+       if(!stricmp(which,"delete")){
+               return MAC_DEL_KEY;
+       }
+       if(!stricmp(which,"insert")){
+               return MAC_INSERT_KEY;
+       }
+       if(!stricmp(which,"home")){
+               return MAC_HOME_KEY;
+       }
+       if(!stricmp(which,"end")){
+               return MAC_END_KEY;
+       }
+       if(!stricmp(which,"page_up")){
+               return MAC_PAGE_UP_KEY;
+       }
+       if(!stricmp(which,"page_down")){
+               return MAC_PAGE_DOWN_KEY;
+       }
+       if(!stricmp(which,"clear")){
+               return MAC_NUMPAD_CLEAR_KEY;
+       }
+
+       if(!stricmp(which,"control")){
+               return MAC_CONTROL_KEY;
+       }
+       if(!stricmp(which,"return")){
+               return MAC_RETURN_KEY;
+       }
+       if(!stricmp(which,"space")){
+               return MAC_SPACE_KEY;
+       }
+       if(!stricmp(which,"shift")){
+               return MAC_SHIFT_KEY;
+       }
+       if(!stricmp(which,"uparrow")){
+               return MAC_ARROW_UP_KEY;
+       }
+       if(!stricmp(which,"downarrow")){
+               return MAC_ARROW_DOWN_KEY;
+       }
+       if(!stricmp(which,"leftarrow")){
+               return MAC_ARROW_LEFT_KEY;
+       }
+       if(!stricmp(which,"rightarrow")){
+               return MAC_ARROW_RIGHT_KEY;
+       }
+       if(!stricmp(which,"mouse1")){
+               return MAC_MOUSEBUTTON1;
+       }
+       if(!stricmp(which,"mouse2")){
+               return MAC_MOUSEBUTTON2;
+       }
+       if(!stricmp(which,"+")){
+               return MAC_NUMPAD_PLUS_KEY;
+       }
+       if(!stricmp(which,"*")){
+               return MAC_NUMPAD_ASTERISK_KEY;
+       }
+       if(!stricmp(which,"/")){
+               return MAC_SLASH_KEY;
+       }
+       if(!stricmp(which,"\\")){
+               return MAC_BACKSLASH_KEY;
+       }
+       if(!stricmp(which,"[")){
+               return MAC_LEFTBRACKET_KEY;
+       }
+       if(!stricmp(which,"]")){
+               return MAC_RIGHTBRACKET_KEY;
+       }
+       if(!stricmp(which,".")){
+               return MAC_PERIOD_KEY;
+       }
+       if(!stricmp(which,",")){
+               return MAC_COMMA_KEY;
+       }
+       if(!stricmp(which,"\"")){
+               return MAC_APOSTROPHE_KEY;
+       }
+       if(!stricmp(which,";")){
+               return MAC_SEMICOLON_KEY;
+       }
+       return UNKNOWN_KEY;
+}
+
+char*  KeyToChar(unsigned short which)
+{
+       static int i;
+
+       // alphabetic keys
+       if(which==MAC_A_KEY){
+               return "a";
+       }
+       if(which==MAC_B_KEY){
+               return "b";
+       }
+       if(which==MAC_C_KEY){
+               return "c";
+       }
+       if(which==MAC_D_KEY){
+               return "d";
+       }
+       if(which==MAC_E_KEY){
+               return "e";
+       }
+       if(which==MAC_F_KEY){
+               return "f";
+       }
+       if(which==MAC_G_KEY){
+               return "g";
+       }
+       if(which==MAC_H_KEY){
+               return "h";
+       }
+       if(which==MAC_I_KEY){
+               return "i";
+       }
+       if(which==MAC_J_KEY){
+               return "j";
+       }
+       if(which==MAC_K_KEY){
+               return "k";
+       }
+       if(which==MAC_L_KEY){
+               return "l";
+       }
+       if(which==MAC_M_KEY){
+               return "m";
+       }
+       if(which==MAC_N_KEY){
+               return "n";
+       }
+       if(which==MAC_O_KEY){
+               return "o";
+       }
+       if(which==MAC_P_KEY){
+               return "p";
+       }
+       if(which==MAC_Q_KEY){
+               return "q";
+       }
+       if(which==MAC_R_KEY){
+               return "r";
+       }
+       if(which==MAC_S_KEY){
+               return "s";
+       }
+       if(which==MAC_T_KEY){
+               return "t";
+       }
+       if(which==MAC_U_KEY){
+               return "u";
+       }
+       if(which==MAC_V_KEY){
+               return "v";
+       }
+       if(which==MAC_W_KEY){
+               return "w";
+       }
+       if(which==MAC_X_KEY){
+               return "x";
+       }
+       if(which==MAC_Y_KEY){
+               return "y";
+       }
+       if(which==MAC_Z_KEY){
+               return "z";
+       }
+
+       // keypad keys
+       if(which==MAC_NUMPAD_1_KEY){
+               return "KP1";
+       }
+       if(which==MAC_NUMPAD_2_KEY){
+               return "KP2";
+       }
+       if(which==MAC_NUMPAD_3_KEY){
+               return "KP3";
+       }
+       if(which==MAC_NUMPAD_4_KEY){
+               return "KP4";
+       }
+       if(which==MAC_NUMPAD_5_KEY){
+               return "KP5";
+       }
+       if(which==MAC_NUMPAD_6_KEY){
+               return "KP6";
+       }
+       if(which==MAC_NUMPAD_7_KEY){
+               return "KP7";
+       }
+       if(which==MAC_NUMPAD_8_KEY){
+               return "KP8";
+       }
+       if(which==MAC_NUMPAD_9_KEY){
+               return "KP9";
+       }
+       if(which==MAC_NUMPAD_0_KEY){
+               return "KP0";
+       }
+
+       // enter
+       if(which==MAC_ENTER_KEY){
+               return "enter";
+       }
+
+       // number keys
+       if(which==MAC_1_KEY){
+               return "1";
+       }
+       if(which==MAC_2_KEY){
+               return "2";
+       }
+       if(which==MAC_3_KEY){
+               return "3";
+       }
+       if(which==MAC_4_KEY){
+               return "4";
+       }
+       if(which==MAC_5_KEY){
+               return "5";
+       }
+       if(which==MAC_6_KEY){
+               return "6";
+       }
+       if(which==MAC_7_KEY){
+               return "7";
+       }
+       if(which==MAC_8_KEY){
+               return "8";
+       }
+       if(which==MAC_9_KEY){
+               return "9";
+       }
+       if(which==MAC_0_KEY){
+               return "0";
+       }
+
+       // function keys
+       if(which==MAC_F1_KEY){
+               return "F1";
+       }
+       if(which==MAC_F2_KEY){
+               return "F2";
+       }
+       if(which==MAC_F3_KEY){
+               return "F3";
+       }
+       if(which==MAC_F4_KEY){
+               return "F4";
+       }
+       if(which==MAC_F5_KEY){
+               return "F5";
+       }
+       if(which==MAC_F6_KEY){
+               return "F6";
+       }
+       if(which==MAC_F7_KEY){
+               return "F7";
+       }
+       if(which==MAC_F8_KEY){
+               return "F8";
+       }
+       if(which==MAC_F9_KEY){
+               return "F9";
+       }
+       if(which==MAC_F10_KEY){
+               return "F10";
+       }
+       if(which==MAC_F11_KEY){
+               return "F11";
+       }
+       if(which==MAC_F12_KEY){
+               return "F12";
+       }
+
+       // escape
+       if(which==MAC_ESCAPE_KEY){
+               return "escape";
+       }
+       if(which==MAC_DELETE_KEY){
+               return "backspace";
+       }
+       if(which==MAC_TAB_KEY){
+               return "tab";
+       }
+       if(which==MAC_TILDE_KEY){
+               return "`";
+       }
+       if(which==MAC_CAPS_LOCK_KEY){
+               return "caps_lock";
+       }
+       if(which==MAC_COMMAND_KEY){
+               return "command";
+       }
+       if(which==MAC_OPTION_KEY){
+               return "option";
+       }
+       if(which==MAC_DEL_KEY){
+               return "delete";
+       }
+       if(which==MAC_INSERT_KEY){
+               return "insert";
+       }
+       if(which==MAC_HOME_KEY){
+               return "home";
+       }
+       if(which==MAC_END_KEY){
+               return "end";
+       }
+       if(which==MAC_PAGE_UP_KEY){
+               return "page_up";
+       }
+       if(which==MAC_PAGE_DOWN_KEY){
+               return "page_down";
+       }
+       if(which==MAC_NUMPAD_CLEAR_KEY){
+               return "clear";
+       }
+       if(which==MAC_CONTROL_KEY){
+               return "control";
+       }
+       if(which==MAC_SPACE_KEY){
+               return "space";
+       }
+       if(which==MAC_RETURN_KEY){
+               return "return";
+       }
+       if(which==MAC_SHIFT_KEY){
+               return "shift";
+       }
+       if(which==MAC_ARROW_UP_KEY){
+               return "uparrow";
+       }
+       if(which==MAC_ARROW_DOWN_KEY){
+               return "downarrow";
+       }
+       if(which==MAC_ARROW_LEFT_KEY){
+               return "leftarrow";
+       }
+       if(which==MAC_ARROW_RIGHT_KEY){
+               return "rightarrow";
+       }
+       if(which==MAC_MOUSEBUTTON1){
+               return "mouse1";
+       }
+       if(which==MAC_MOUSEBUTTON2){
+               return "mouse2";
+       }
+       if(which==MAC_ARROW_RIGHT_KEY){
+               return "rightarrow";
+       }
+       if(which==MAC_MINUS_KEY||which==MAC_NUMPAD_MINUS_KEY){
+               return "-";
+       }
+       if(which==MAC_PLUS_KEY||which==MAC_NUMPAD_EQUALS_KEY){
+               return "=";
+       }
+       if(which==MAC_NUMPAD_PLUS_KEY){
+               return "+";
+       }
+       if(which==MAC_NUMPAD_ASTERISK_KEY){
+               return "*";
+       }
+       if(which==MAC_SLASH_KEY||which==MAC_NUMPAD_SLASH_KEY){
+               return "/";
+       }
+       if(which==MAC_BACKSLASH_KEY){
+               return "\\";
+       }
+       if(which==MAC_LEFTBRACKET_KEY){
+               return "[";
+       }
+       if(which==MAC_RIGHTBRACKET_KEY){
+               return "]";
+       }
+       if(which==MAC_PERIOD_KEY||which==MAC_NUMPAD_PERIOD_KEY){
+               return ".";
+       }
+       if(which==MAC_COMMA_KEY){
+               return ",";
+       }
+       if(which==MAC_APOSTROPHE_KEY){
+               return "\"";
+       }
+       if(which==MAC_SEMICOLON_KEY){
+               return ";";
+       }
+       return "unknown";
+}
+
+char   KeyToSingleChar(unsigned short which)
+{
+       static int i;
+
+       if(which==MAC_A_KEY){
+               return 'a';
+       }
+       if(which==MAC_B_KEY){
+               return 'b';
+       }
+       if(which==MAC_C_KEY){
+               return 'c';
+       }
+       if(which==MAC_D_KEY){
+               return 'd';
+       }
+       if(which==MAC_E_KEY){
+               return 'e';
+       }
+       if(which==MAC_F_KEY){
+               return 'f';
+       }
+       if(which==MAC_G_KEY){
+               return 'g';
+       }
+       if(which==MAC_H_KEY){
+               return 'h';
+       }
+       if(which==MAC_I_KEY){
+               return 'i';
+       }
+       if(which==MAC_J_KEY){
+               return 'j';
+       }
+       if(which==MAC_K_KEY){
+               return 'k';
+       }
+       if(which==MAC_L_KEY){
+               return 'l';
+       }
+       if(which==MAC_M_KEY){
+               return 'm';
+       }
+       if(which==MAC_N_KEY){
+               return 'n';
+       }
+       if(which==MAC_O_KEY){
+               return 'o';
+       }
+       if(which==MAC_P_KEY){
+               return 'p';
+       }
+       if(which==MAC_Q_KEY){
+               return 'q';
+       }
+       if(which==MAC_R_KEY){
+               return 'r';
+       }
+       if(which==MAC_S_KEY){
+               return 's';
+       }
+       if(which==MAC_T_KEY){
+               return 't';
+       }
+       if(which==MAC_U_KEY){
+               return 'u';
+       }
+       if(which==MAC_V_KEY){
+               return 'v';
+       }
+       if(which==MAC_W_KEY){
+               return 'w';
+       }
+       if(which==MAC_X_KEY){
+               return 'x';
+       }
+       if(which==MAC_Y_KEY){
+               return 'y';
+       }
+       if(which==MAC_Z_KEY){
+               return 'z';
+       }
+       if(which==MAC_NUMPAD_1_KEY){
+               return '1';
+       }
+       if(which==MAC_NUMPAD_2_KEY){
+               return '2';
+       }
+       if(which==MAC_NUMPAD_3_KEY){
+               return '3';
+       }
+       if(which==MAC_NUMPAD_4_KEY){
+               return '4';
+       }
+       if(which==MAC_NUMPAD_5_KEY){
+               return '5';
+       }
+       if(which==MAC_NUMPAD_6_KEY){
+               return '6';
+       }
+       if(which==MAC_NUMPAD_7_KEY){
+               return '7';
+       }
+       if(which==MAC_NUMPAD_8_KEY){
+               return '8';
+       }
+       if(which==MAC_NUMPAD_9_KEY){
+               return '9';
+       }
+       if(which==MAC_NUMPAD_0_KEY){
+               return '0';
+       }
+       if(which==MAC_1_KEY){
+               return '1';
+       }
+       if(which==MAC_2_KEY){
+               return '2';
+       }
+       if(which==MAC_3_KEY){
+               return '3';
+       }
+       if(which==MAC_4_KEY){
+               return '4';
+       }
+       if(which==MAC_5_KEY){
+               return '5';
+       }
+       if(which==MAC_6_KEY){
+               return '6';
+       }
+       if(which==MAC_7_KEY){
+               return '7';
+       }
+       if(which==MAC_8_KEY){
+               return '8';
+       }
+       if(which==MAC_9_KEY){
+               return '9';
+       }
+       if(which==MAC_0_KEY){
+               return '0';
+       }
+       if(which==MAC_SPACE_KEY){
+               return ' ';
+       }
+       if(which==MAC_MINUS_KEY||which==MAC_NUMPAD_MINUS_KEY){
+               return '-';
+       }
+       if(which==MAC_PLUS_KEY||which==MAC_NUMPAD_EQUALS_KEY){
+               return '=';
+       }
+       if(which==MAC_NUMPAD_PLUS_KEY){
+               return '+';
+       }
+       if(which==MAC_NUMPAD_ASTERISK_KEY){
+               return '*';
+       }
+       if(which==MAC_SLASH_KEY||which==MAC_NUMPAD_SLASH_KEY){
+               return '/';
+       }
+       if(which==MAC_BACKSLASH_KEY){
+               return '\\';
+       }
+       if(which==MAC_LEFTBRACKET_KEY){
+               return '[';
+       }
+       if(which==MAC_RIGHTBRACKET_KEY){
+               return ']';
+       }
+       if(which==MAC_PERIOD_KEY||which==MAC_NUMPAD_PERIOD_KEY){
+               return '.';
+       }
+       if(which==MAC_COMMA_KEY){
+               return ',';
+       }
+       if(which==MAC_APOSTROPHE_KEY){
+               return '\'';
+       }
+       if(which==MAC_SEMICOLON_KEY){
+               return ';';
+       }
+       return '\0';
+}
+
+char   Shift(char which)
+{
+       static int i;
+
+       if(which=='a'){
+               return 'A';
+       }
+       if(which=='b'){
+               return 'B';
+       }
+       if(which=='c'){
+               return 'C';
+       }
+       if(which=='d'){
+               return 'D';
+       }
+       if(which=='e'){
+               return 'E';
+       }
+       if(which=='f'){
+               return 'F';
+       }
+       if(which=='g'){
+               return 'G';
+       }
+       if(which=='h'){
+               return 'H';
+       }
+       if(which=='e'){
+               return 'E';
+       }
+       if(which=='f'){
+               return 'F';
+       }
+       if(which=='g'){
+               return 'G';
+       }
+       if(which=='h'){
+               return 'H';
+       }
+       if(which=='i'){
+               return 'I';
+       }
+       if(which=='j'){
+               return 'J';
+       }
+       if(which=='k'){
+               return 'K';
+       }
+       if(which=='l'){
+               return 'L';
+       }
+       if(which=='m'){
+               return 'M';
+       }
+       if(which=='n'){
+               return 'N';
+       }
+       if(which=='o'){
+               return 'O';
+       }
+       if(which=='p'){
+               return 'P';
+       }
+       if(which=='q'){
+               return 'Q';
+       }
+       if(which=='r'){
+               return 'R';
+       }
+       if(which=='s'){
+               return 'S';
+       }
+       if(which=='t'){
+               return 'T';
+       }
+       if(which=='u'){
+               return 'U';
+       }
+       if(which=='v'){
+               return 'V';
+       }
+       if(which=='w'){
+               return 'W';
+       }
+       if(which=='x'){
+               return 'X';
+       }
+       if(which=='y'){
+               return 'Y';
+       }
+       if(which=='z'){
+               return 'Z';
+       }
+       if(which=='1'){
+               return '!';
+       }
+       if(which=='2'){
+               return '@';
+       }
+       if(which=='3'){
+               return '#';
+       }
+       if(which=='4'){
+               return '$';
+       }
+       if(which=='5'){
+               return '%';
+       }
+       if(which=='6'){
+               return '^';
+       }
+       if(which=='7'){
+               return '&';
+       }
+       if(which=='8'){
+               return '*';
+       }
+       if(which=='9'){
+               return '(';
+       }
+       if(which=='0'){
+               return ')';
+       }
+       if(which=='-'){
+               return '_';
+       }
+       if(which=='='){
+               return '+';
+       }
+       if(which=='['){
+               return '{';
+       }
+       if(which==']'){
+               return '}';
+       }
+       if(which=='\\'){
+               return '|';
+       }
+       if(which=='.'){
+               return '>';
+       }
+       if(which==','){
+               return '<';
+       }
+       if(which=='/'){
+               return '?';
+       }
+       if(which==';'){
+               return ':';
+       }
+       if(which=='\''){
+               return '\"';
+       }
+       return which;
+}
+
+bool   Compare(char *thestring, char *tocompare, int start, int end)
+{
+       static int i;
+       for(i=start;i<=end;i++){
+               if(thestring[i]!=tocompare[i-start]&&thestring[i]!=tocompare[i-start]+'A'-'a')return 0;
+       }
+       return 1;
+}
\ No newline at end of file
diff --git a/Source/WinInput.h b/Source/WinInput.h
new file mode 100644 (file)
index 0000000..3728cf2
--- /dev/null
@@ -0,0 +1,136 @@
+#ifndef _WININPUT_H_
+#define _WININPUT_H_
+
+/**> HEADER FILES <**/
+#include <stdlib.h>
+#include <stdio.h>
+#include "WinDefs.h"
+
+/**> CONSTANT DECLARATIONS <**/
+// Mac Keyboard Codes
+#define        MAC_1_KEY                               0x12
+#define        MAC_2_KEY                               0x13
+#define        MAC_3_KEY                               0x14
+#define        MAC_4_KEY                               0x15
+#define        MAC_5_KEY                               0x17
+#define        MAC_6_KEY                               0x16
+#define        MAC_7_KEY                               0x1A
+#define        MAC_8_KEY                               0x1C
+#define        MAC_9_KEY                               0x19
+#define        MAC_0_KEY                               0x1D
+#define        MAC_NUMPAD_1_KEY                0x53
+#define        MAC_NUMPAD_2_KEY                0x54
+#define        MAC_NUMPAD_3_KEY                0x55
+#define        MAC_NUMPAD_4_KEY                0x56
+#define        MAC_NUMPAD_5_KEY                0x57
+#define        MAC_NUMPAD_6_KEY                0x58
+#define        MAC_NUMPAD_7_KEY                0x59
+#define        MAC_NUMPAD_8_KEY                0x5B
+#define        MAC_NUMPAD_9_KEY                0x5C
+#define        MAC_NUMPAD_0_KEY                0x52
+#define        MAC_A_KEY                               0x00
+#define        MAC_B_KEY                               0x0B
+#define        MAC_C_KEY                               0x08
+#define        MAC_D_KEY                               0x02
+#define        MAC_E_KEY                               0x0E
+#define        MAC_F_KEY                               0x03
+#define        MAC_G_KEY                               0x05
+#define        MAC_H_KEY                               0x04
+#define        MAC_I_KEY                               0x22
+#define        MAC_J_KEY                               0x26
+#define        MAC_K_KEY                               0x28
+#define        MAC_L_KEY                               0x25
+#define        MAC_M_KEY                               0x2E
+#define        MAC_N_KEY                               0x2D
+#define        MAC_O_KEY                               0x1F
+#define        MAC_P_KEY                               0x23
+#define        MAC_Q_KEY                               0x0C
+#define        MAC_R_KEY                               0x0F
+#define        MAC_S_KEY                               0x01
+#define        MAC_T_KEY                               0x11
+#define        MAC_U_KEY                               0x20
+#define        MAC_V_KEY                               0x09
+#define        MAC_W_KEY                               0x0D
+#define        MAC_X_KEY                               0x07
+#define        MAC_Y_KEY                               0x10
+#define        MAC_Z_KEY                               0x06
+#define        MAC_F1_KEY                              0x7A
+#define        MAC_F2_KEY                              0x78
+#define        MAC_F3_KEY                              0x63
+#define        MAC_F4_KEY                              0x76
+#define        MAC_F5_KEY                              0x60
+#define        MAC_F6_KEY                              0x61
+#define        MAC_F7_KEY                              0x62
+#define        MAC_F8_KEY                              0x64
+#define        MAC_F9_KEY                              0x65
+#define        MAC_F10_KEY                             0x6D
+#define        MAC_F11_KEY                             0x67
+#define        MAC_F12_KEY                             0x6F
+#define        MAC_RETURN_KEY                  0x24
+#define        MAC_ENTER_KEY                   0x4C
+#define        MAC_TAB_KEY                             0x30
+#define        MAC_SPACE_KEY                   0x31
+#define        MAC_DELETE_KEY                  0x33
+#define        MAC_ESCAPE_KEY                  0x35
+#define        MAC_COMMAND_KEY                 0x37
+#define        MAC_SHIFT_KEY                   0x38
+#define        MAC_CAPS_LOCK_KEY               0x39
+#define        MAC_OPTION_KEY                  0x3A
+#define        MAC_CONTROL_KEY                 0x3B
+#define        MAC_PAGE_UP_KEY                 0x74
+#define        MAC_PAGE_DOWN_KEY               0x79
+#define        MAC_INSERT_KEY                  0x72
+#define        MAC_DEL_KEY                             0x75
+#define        MAC_HOME_KEY                    0x73
+#define        MAC_END_KEY                             0x77
+#define        MAC_LEFT_BRACKET_KEY    0x21
+#define        MAC_RIGHT_BRACKET_KEY   0x1E
+#define        MAC_ARROW_UP_KEY                0x7E
+#define        MAC_ARROW_DOWN_KEY              0x7D
+#define        MAC_ARROW_LEFT_KEY              0x7B
+#define        MAC_ARROW_RIGHT_KEY             0x7C
+#define        MAC_TILDE_KEY                   0x32
+#define MAC_MINUS_KEY                  0x1B
+#define MAC_PLUS_KEY                   0x18
+#define MAC_SLASH_KEY                  0x2C
+#define MAC_PERIOD_KEY                 0x2F
+#define MAC_COMMA_KEY                  0x2B
+#define MAC_BACKSLASH_KEY              0x2A
+#define MAC_LEFTBRACKET_KEY            0x21
+#define MAC_RIGHTBRACKET_KEY   0x1E
+#define MAC_NUMPAD_CLEAR_KEY   0x47
+#define MAC_NUMPAD_MINUS_KEY   0x4E
+#define MAC_NUMPAD_EQUALS_KEY  0x51
+#define MAC_NUMPAD_PLUS_KEY            0x45
+#define MAC_NUMPAD_SLASH_KEY   0x4B
+#define MAC_NUMPAD_ASTERISK_KEY        0x43
+#define MAC_NUMPAD_ENTER_KEY   0x4C
+#define MAC_NUMPAD_PERIOD_KEY  0x41
+#define MAC_SEMICOLON_KEY              0x29
+#define MAC_APOSTROPHE_KEY             0x27
+#define MAC_MOUSEBUTTON1               10000
+#define MAC_MOUSEBUTTON2               10001
+
+#define UNKNOWN_KEY 0xFF
+
+
+/**> FUNCTION PROTOTYPES <**/
+Boolean        IsKeyDown( unsigned char *keyMap, unsigned short theKey );
+void   InitMouse();
+void   MoveMouse(int xcoord, int ycoord, Point *mouseloc);
+void   RefreshMouse(Point *mouseloc);
+void   DisposeMouse();
+unsigned short         CharToKey(char* which);
+char*  KeyToChar(unsigned short which);
+char   KeyToSingleChar(unsigned short which);
+char   Shift(char which);
+bool   Compare(char *thestring, char *tocompare, int start, int end);
+
+
+typedef unsigned char KeyMap[16];
+void GetKeys( unsigned char theKeys[16]);
+
+Boolean Button();
+
+
+#endif
\ No newline at end of file
diff --git a/Source/binio.h b/Source/binio.h
new file mode 100644 (file)
index 0000000..4572b3e
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef binio_h
+#define binio_h
+
+#include <stdarg.h>
+#include <stdio.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+       /*
+       Notes on format of format strings:
+       * whitespace is ignored
+       * each "group" consists of an optional count (defaults to 1),
+       an optional byte-order marker (defaults to H, "host-native"),
+       and a  data-type specifier.
+       * when unpacking, each variable argument is a pointer to the
+       appropriate number of objects of the appropriate type.
+       * when packing, each variable argument is an object of the
+       appropriate type if the count is omitted, or a pointer to the
+       appropriate number of objects of the appropriate type if the
+       count is specified.
+       * the buffer supplied to pack/unpack must be of sufficient length
+       to hold all the data, or the behavior is unspecified.
+       * the file provided to the "f" versions of the functions must be
+       open in the appropriate mode, or the behavior is unspecified.
+       * the file supplied to funpackf must be of sufficient length to
+       hold all the data, or the behavior is unspecified.
+       * the behavior of all functions is unspecified if the format string
+       is incorrectly-formed.
+
+       Data-type specifiers:
+       x skipped byte; no corresponding argument
+       b byte
+       s two-byte two's-complement integer
+       i four-byte two's-complement integer
+       l eight-byte two's-complement integer
+       f four-byte IEEE754 float
+       d eight-byte IEEE754 double
+
+       Byte-order specifiers:
+       L little-endian
+       B big-endian
+       H host's native byte order
+       N network byte order
+       */
+
+#if defined(BinIO_STDINT_HEADER)
+#include BinIO_STDINT_HEADER
+       typedef float              float32_t;
+       typedef double             float64_t;
+#else
+       typedef unsigned char      uint8_t;
+       typedef unsigned short     uint16_t;
+       typedef unsigned long       uint32_t;
+#ifdef WIN32
+       typedef unsigned __int64        uint64_t;
+#else
+       typedef unsigned long long uint64_t;
+#endif
+       typedef float              float32_t;
+       typedef double             float64_t;
+#endif
+
+       typedef struct
+       {
+               float64_t d;
+               uint64_t  l;
+               int  i;
+               float32_t f;
+               uint16_t  s;
+               uint8_t   b;
+       }
+       test_data;
+
+       extern void packf    (                    const char *format, ...);
+       extern void spackf   (void *buffer,       const char *format, ...);
+       extern void fpackf   (FILE *file,         const char *format, ...);
+       extern void vspackf  (void *buffer,       const char *format, va_list args);
+       extern void vfpackf  (FILE *file,         const char *format, va_list args);
+
+       extern void unpackf  (                    const char *format, ...);
+       extern void sunpackf (const void *buffer, const char *format, ...);
+       extern void funpackf (FILE       *file,   const char *format, ...);
+       extern void vsunpackf(const void *buffer, const char *format, va_list args);
+       extern void vfunpackf(FILE       *file,   const char *format, va_list args);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
diff --git a/Source/fmod.h b/Source/fmod.h
new file mode 100644 (file)
index 0000000..729ab20
--- /dev/null
@@ -0,0 +1,17 @@
+// wrapper for FMOD to account for filename conversions in windows
+
+#ifndef _FMODWRAPPER_H_
+#define _FMODWRAPPER_H_
+
+#include "fmod_header.h"
+#include "WinDefs.h"
+
+
+#ifdef WIN32
+
+#define FSOUND_Sample_Load( a, b, c, d) FSOUND_Sample_Load( a, ConvertFileName( b), c, d, 0);
+
+#endif
+
+
+#endif
diff --git a/Source/fmod_errors.h b/Source/fmod_errors.h
new file mode 100644 (file)
index 0000000..9004ec1
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef _FMOD_ERRORS_H
+#define _FMOD_ERRORS_H
+
+static char *FMOD_ErrorString(int errcode)
+{
+       switch (errcode)
+       {
+               case FMOD_ERR_NONE:                             return "No errors";
+               case FMOD_ERR_BUSY:                             return "Cannot call this command after FSOUND_Init.  Call FSOUND_Close first.";
+               case FMOD_ERR_UNINITIALIZED:    return "This command failed because FSOUND_Init was not called";
+               case FMOD_ERR_PLAY:                             return "Playing the sound failed.";
+               case FMOD_ERR_INIT:                             return "Error initializing output device.";
+               case FMOD_ERR_ALLOCATED:                return "The output device is already in use and cannot be reused.";
+               case FMOD_ERR_OUTPUT_FORMAT:    return "Soundcard does not support the features needed for this soundsystem (16bit stereo output)";
+               case FMOD_ERR_COOPERATIVELEVEL: return "Error setting cooperative level for hardware.";
+               case FMOD_ERR_CREATEBUFFER:             return "Error creating hardware sound buffer.";
+               case FMOD_ERR_FILE_NOTFOUND:    return "File not found";
+               case FMOD_ERR_FILE_FORMAT:              return "Unknown file format";
+               case FMOD_ERR_FILE_BAD:                 return "Error loading file";
+               case FMOD_ERR_MEMORY:                   return "Not enough memory ";
+               case FMOD_ERR_VERSION:                  return "The version number of this file format is not supported";
+               case FMOD_ERR_INVALID_PARAM:    return "An invalid parameter was passed to this function";
+               case FMOD_ERR_NO_EAX:                   return "Tried to use an EAX command on a non EAX enabled channel or output.";
+               case FMOD_ERR_CHANNEL_ALLOC:    return "Failed to allocate a new channel";
+               case FMOD_ERR_RECORD:                   return "Recording not supported on this device";
+               case FMOD_ERR_MEDIAPLAYER:              return "Required Mediaplayer codec is not installed";
+
+               default :                                               return "Unknown error";
+       };
+}
+
+#endif
diff --git a/Source/fmod_header.h b/Source/fmod_header.h
new file mode 100644 (file)
index 0000000..79fa926
--- /dev/null
@@ -0,0 +1,1219 @@
+/* ========================================================================================== */
+/* FMOD Main header file. Copyright (c), Firelight Technologies Pty, Ltd. 1999-2004.          */
+/* ========================================================================================== */
+
+#ifndef _FMOD_H_
+#define _FMOD_H_
+
+/* ========================================================================================== */
+/* DEFINITIONS                                                                                */
+/* ========================================================================================== */
+
+#if (!defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) && !defined(_WIN64) && !defined(_WIN32_WCE) && !defined(_XBOX)) || (defined(__GNUC__) && defined(WIN32))
+    #ifndef __cdecl
+        #define __cdecl
+    #endif
+    #ifndef __stdcall
+        #define __stdcall
+    #endif
+#endif 
+
+#if defined(_WIN32_WCE)
+    #define F_API _cdecl
+    #define F_CALLBACKAPI _cdecl
+#else
+    #define F_API __stdcall
+    #define F_CALLBACKAPI __stdcall
+#endif
+
+#ifdef DLL_EXPORTS
+    #define DLL_API __declspec(dllexport)
+#else
+    #if defined(__LCC__) || defined(__MINGW32__) || defined(__CYGWIN32__)
+        #define DLL_API F_API
+    #else
+        #define DLL_API
+    #endif /* __LCC__ ||  __MINGW32__ || __CYGWIN32__ */
+#endif /* DLL_EXPORTS */
+
+#define FMOD_VERSION    3.74f
+
+/* 
+    FMOD defined types 
+*/
+typedef struct FSOUND_SAMPLE    FSOUND_SAMPLE;
+typedef struct FSOUND_STREAM    FSOUND_STREAM;
+typedef struct FSOUND_DSPUNIT   FSOUND_DSPUNIT;
+typedef struct FSOUND_SYNCPOINT FSOUND_SYNCPOINT;
+typedef struct FMUSIC_MODULE    FMUSIC_MODULE;
+
+/* 
+    Callback types
+*/
+typedef void *      (F_CALLBACKAPI *FSOUND_OPENCALLBACK)    (const char *name);
+typedef void        (F_CALLBACKAPI *FSOUND_CLOSECALLBACK)   (void *handle);
+typedef int         (F_CALLBACKAPI *FSOUND_READCALLBACK)    (void *buffer, int size, void *handle);
+typedef int         (F_CALLBACKAPI *FSOUND_SEEKCALLBACK)    (void *handle, int pos, signed char mode);
+typedef int         (F_CALLBACKAPI *FSOUND_TELLCALLBACK)    (void *handle);
+
+typedef void *      (F_CALLBACKAPI *FSOUND_ALLOCCALLBACK)   (unsigned int size);
+typedef void *      (F_CALLBACKAPI *FSOUND_REALLOCCALLBACK) (void *ptr, unsigned int size);
+typedef void        (F_CALLBACKAPI *FSOUND_FREECALLBACK)    (void *ptr);
+
+typedef void *      (F_CALLBACKAPI *FSOUND_DSPCALLBACK)     (void *originalbuffer, void *newbuffer, int length, void *userdata);
+typedef signed char (F_CALLBACKAPI *FSOUND_STREAMCALLBACK)  (FSOUND_STREAM *stream, void *buff, int len, void *userdata);
+typedef signed char (F_CALLBACKAPI *FSOUND_METADATACALLBACK)(char *name, char *value, void *userdata);
+typedef void        (F_CALLBACKAPI *FMUSIC_CALLBACK)        (FMUSIC_MODULE *mod, unsigned char param);
+
+
+/*
+[ENUM]
+[
+    [DESCRIPTION]   
+    On failure of commands in FMOD, use FSOUND_GetError to attain what happened.
+    
+    [SEE_ALSO]      
+    FSOUND_GetError
+]
+*/
+enum FMOD_ERRORS 
+{
+    FMOD_ERR_NONE,             /* No errors */
+    FMOD_ERR_BUSY,             /* Cannot call this command after FSOUND_Init.  Call FSOUND_Close first. */
+    FMOD_ERR_UNINITIALIZED,    /* This command failed because FSOUND_Init or FSOUND_SetOutput was not called */
+    FMOD_ERR_INIT,             /* Error initializing output device. */
+    FMOD_ERR_ALLOCATED,        /* Error initializing output device, but more specifically, the output device is already in use and cannot be reused. */
+    FMOD_ERR_PLAY,             /* Playing the sound failed. */
+    FMOD_ERR_OUTPUT_FORMAT,    /* Soundcard does not support the features needed for this soundsystem (16bit stereo output) */
+    FMOD_ERR_COOPERATIVELEVEL, /* Error setting cooperative level for hardware. */
+    FMOD_ERR_CREATEBUFFER,     /* Error creating hardware sound buffer. */
+    FMOD_ERR_FILE_NOTFOUND,    /* File not found */
+    FMOD_ERR_FILE_FORMAT,      /* Unknown file format */
+    FMOD_ERR_FILE_BAD,         /* Error loading file */
+    FMOD_ERR_MEMORY,           /* Not enough memory or resources */
+    FMOD_ERR_VERSION,          /* The version number of this file format is not supported */
+    FMOD_ERR_INVALID_PARAM,    /* An invalid parameter was passed to this function */
+    FMOD_ERR_NO_EAX,           /* Tried to use an EAX command on a non EAX enabled channel or output. */
+    FMOD_ERR_CHANNEL_ALLOC,    /* Failed to allocate a new channel */
+    FMOD_ERR_RECORD,           /* Recording is not supported on this machine */
+    FMOD_ERR_MEDIAPLAYER,      /* Windows Media Player not installed so cannot play wma or use internet streaming. */
+    FMOD_ERR_CDDEVICE          /* An error occured trying to open the specified CD device */
+};
+
+
+/*
+[ENUM]
+[
+    [DESCRIPTION]   
+    These output types are used with FSOUND_SetOutput, to choose which output driver to use.
+    
+    FSOUND_OUTPUT_DSOUND will not support hardware 3d acceleration if the sound card driver 
+    does not support DirectX 6 Voice Manager Extensions.
+
+    FSOUND_OUTPUT_WINMM is recommended for NT and CE.
+
+    [SEE_ALSO]      
+    FSOUND_SetOutput
+    FSOUND_GetOutput
+]
+*/
+enum FSOUND_OUTPUTTYPES
+{
+    FSOUND_OUTPUT_NOSOUND,    /* NoSound driver, all calls to this succeed but do nothing. */
+    FSOUND_OUTPUT_WINMM,      /* Windows Multimedia driver. */
+    FSOUND_OUTPUT_DSOUND,     /* DirectSound driver.  You need this to get EAX2 or EAX3 support, or FX api support. */
+    FSOUND_OUTPUT_A3D,        /* A3D driver. */
+
+    FSOUND_OUTPUT_OSS,        /* Linux/Unix OSS (Open Sound System) driver, i.e. the kernel sound drivers. */
+    FSOUND_OUTPUT_ESD,        /* Linux/Unix ESD (Enlightment Sound Daemon) driver. */
+    FSOUND_OUTPUT_ALSA,       /* Linux Alsa driver. */
+
+    FSOUND_OUTPUT_ASIO,       /* Low latency ASIO driver */
+    FSOUND_OUTPUT_XBOX,       /* Xbox driver */
+    FSOUND_OUTPUT_PS2,        /* PlayStation 2 driver */
+    FSOUND_OUTPUT_MAC,        /* Mac SoundManager driver */
+    FSOUND_OUTPUT_GC,         /* Gamecube driver */
+
+    FSOUND_OUTPUT_NOSOUND_NONREALTIME   /* This is the same as nosound, but the sound generation is driven by FSOUND_Update */
+};
+
+
+/*
+[ENUM]
+[
+    [DESCRIPTION]   
+    These mixer types are used with FSOUND_SetMixer, to choose which mixer to use, or to act 
+    upon for other reasons using FSOUND_GetMixer.
+    It is not nescessary to set the mixer.  FMOD will autodetect the best mixer for you.
+
+    [SEE_ALSO]      
+    FSOUND_SetMixer
+    FSOUND_GetMixer
+]
+*/
+enum FSOUND_MIXERTYPES
+{
+    FSOUND_MIXER_AUTODETECT,        /* CE/PS2/GC Only - Non interpolating/low quality mixer. */
+    FSOUND_MIXER_BLENDMODE,         /* Removed / obsolete. */
+    FSOUND_MIXER_MMXP5,             /* Removed / obsolete. */
+    FSOUND_MIXER_MMXP6,             /* Removed / obsolete. */
+
+    FSOUND_MIXER_QUALITY_AUTODETECT,/* All platforms - Autodetect the fastest quality mixer based on your cpu. */
+    FSOUND_MIXER_QUALITY_FPU,       /* Win32/Linux only - Interpolating/volume ramping FPU mixer.  */
+    FSOUND_MIXER_QUALITY_MMXP5,     /* Win32/Linux only - Interpolating/volume ramping P5 MMX mixer.  */
+    FSOUND_MIXER_QUALITY_MMXP6,     /* Win32/Linux only - Interpolating/volume ramping ppro+ MMX mixer. */
+
+    FSOUND_MIXER_MONO,              /* CE/PS2/GC only - MONO non interpolating/low quality mixer. For speed*/
+    FSOUND_MIXER_QUALITY_MONO,      /* CE/PS2/GC only - MONO Interpolating mixer.  For speed */
+
+    FSOUND_MIXER_MAX
+};
+
+
+/*
+[ENUM]
+[
+    [DESCRIPTION]   
+    These definitions describe the type of song being played.
+
+    [SEE_ALSO]      
+    FMUSIC_GetType  
+]
+*/
+enum FMUSIC_TYPES
+{
+    FMUSIC_TYPE_NONE,       
+    FMUSIC_TYPE_MOD,        /* Protracker / Fasttracker */
+    FMUSIC_TYPE_S3M,        /* ScreamTracker 3 */
+    FMUSIC_TYPE_XM,         /* FastTracker 2 */
+    FMUSIC_TYPE_IT,         /* Impulse Tracker. */
+    FMUSIC_TYPE_MIDI,       /* MIDI file */
+    FMUSIC_TYPE_FSB         /* FMOD Sample Bank file */
+};
+
+
+/*
+[DEFINE_START] 
+[
+    [NAME] 
+    FSOUND_DSP_PRIORITIES
+
+    [DESCRIPTION]   
+    These default priorities are used by FMOD internal system DSP units.  They describe the 
+    position of the DSP chain, and the order of how audio processing is executed.
+    You can actually through the use of FSOUND_DSP_GetxxxUnit (where xxx is the name of the DSP
+    unit), disable or even change the priority of a DSP unit.
+
+    [SEE_ALSO]      
+    FSOUND_DSP_Create
+    FSOUND_DSP_SetPriority
+    FSOUND_DSP_GetSpectrum
+]
+*/
+#define FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT        0       /* DSP CLEAR unit - done first */
+#define FSOUND_DSP_DEFAULTPRIORITY_SFXUNIT          100     /* DSP SFX unit - done second */
+#define FSOUND_DSP_DEFAULTPRIORITY_MUSICUNIT        200     /* DSP MUSIC unit - done third */
+#define FSOUND_DSP_DEFAULTPRIORITY_USER             300     /* User priority, use this as reference for your own DSP units */
+#define FSOUND_DSP_DEFAULTPRIORITY_FFTUNIT          900     /* This reads data for FSOUND_DSP_GetSpectrum, so it comes after user units */
+#define FSOUND_DSP_DEFAULTPRIORITY_CLIPANDCOPYUNIT  1000    /* DSP CLIP AND COPY unit - last */
+/* [DEFINE_END] */
+
+
+/*
+[DEFINE_START] 
+[
+    [NAME] 
+    FSOUND_CAPS
+
+    [DESCRIPTION]   
+    Driver description bitfields.  Use FSOUND_Driver_GetCaps to determine if a driver enumerated
+    has the settings you are after.  The enumerated driver depends on the output mode, see
+    FSOUND_OUTPUTTYPES
+
+    [SEE_ALSO]
+    FSOUND_GetDriverCaps
+    FSOUND_OUTPUTTYPES
+]
+*/
+#define FSOUND_CAPS_HARDWARE                0x1     /* This driver supports hardware accelerated 3d sound. */
+#define FSOUND_CAPS_EAX2                    0x2     /* This driver supports EAX 2 reverb */
+#define FSOUND_CAPS_EAX3                    0x10    /* This driver supports EAX 3 reverb */
+/* [DEFINE_END] */
+
+
+/*
+[DEFINE_START] 
+[
+    [NAME] 
+    FSOUND_MODES
+    
+    [DESCRIPTION]   
+    Sample description bitfields, OR them together for loading and describing samples.
+    NOTE.  If the file format being loaded already has a defined format, such as WAV or MP3, then 
+    trying to override the pre-defined format with a new set of format flags will not work.  For
+    example, an 8 bit WAV file will not load as 16bit if you specify FSOUND_16BITS.  It will just
+    ignore the flag and go ahead loading it as 8bits.  For these type of formats the only flags
+    you can specify that will really alter the behaviour of how it is loaded, are the following.
+    ---------
+    Looping behaviour - FSOUND_LOOP_OFF, FSOUND_LOOP_NORMAL, FSOUND_LOOP_BIDI 
+    Load destination - FSOUND_HW3D, FSOUND_HW2D, FSOUND_2D
+    Loading behaviour - FSOUND_NONBLOCKING, FSOUND_LOADMEMORY, FSOUND_LOADRAW, FSOUND_MPEGACCURATE, FSOUND_MPEGHALFRATE, FSOUND_FORCEMONO
+    Playback behaviour - FSOUND_STREAMABLE, FSOUND_ENABLEFX
+    PlayStation 2 only - FSOUND_USECORE0, FSOUND_USECORE1, FSOUND_LOADMEMORYIOP    
+    ---------
+    See flag descriptions for what these do.
+]
+*/
+#define FSOUND_LOOP_OFF      0x00000001  /* For non looping samples. */
+#define FSOUND_LOOP_NORMAL   0x00000002  /* For forward looping samples. */
+#define FSOUND_LOOP_BIDI     0x00000004  /* For bidirectional looping samples.  (no effect if in hardware). */
+#define FSOUND_8BITS         0x00000008  /* For 8 bit samples. */
+#define FSOUND_16BITS        0x00000010  /* For 16 bit samples. */
+#define FSOUND_MONO          0x00000020  /* For mono samples. */
+#define FSOUND_STEREO        0x00000040  /* For stereo samples. */
+#define FSOUND_UNSIGNED      0x00000080  /* For user created source data containing unsigned samples. */
+#define FSOUND_SIGNED        0x00000100  /* For user created source data containing signed data. */
+#define FSOUND_DELTA         0x00000200  /* For user created source data stored as delta values. */
+#define FSOUND_IT214         0x00000400  /* For user created source data stored using IT214 compression. */
+#define FSOUND_IT215         0x00000800  /* For user created source data stored using IT215 compression. */
+#define FSOUND_HW3D          0x00001000  /* Attempts to make samples use 3d hardware acceleration. (if the card supports it) */
+#define FSOUND_2D            0x00002000  /* Tells software (not hardware) based sample not to be included in 3d processing. */
+#define FSOUND_STREAMABLE    0x00004000  /* For a streamimg sound where you feed the data to it. */
+#define FSOUND_LOADMEMORY    0x00008000  /* "name" will be interpreted as a pointer to data for streaming and samples. */
+#define FSOUND_LOADRAW       0x00010000  /* Will ignore file format and treat as raw pcm. */
+#define FSOUND_MPEGACCURATE  0x00020000  /* For FSOUND_Stream_Open - for accurate FSOUND_Stream_GetLengthMs/FSOUND_Stream_SetTime.  WARNING, see FSOUND_Stream_Open for inital opening time performance issues. */
+#define FSOUND_FORCEMONO     0x00040000  /* For forcing stereo streams and samples to be mono - needed if using FSOUND_HW3D and stereo data - incurs a small speed hit for streams */
+#define FSOUND_HW2D          0x00080000  /* 2D hardware sounds.  allows hardware specific effects */
+#define FSOUND_ENABLEFX      0x00100000  /* Allows DX8 FX to be played back on a sound.  Requires DirectX 8 - Note these sounds cannot be played more than once, be 8 bit, be less than a certain size, or have a changing frequency */
+#define FSOUND_MPEGHALFRATE  0x00200000  /* For FMODCE only - decodes mpeg streams using a lower quality decode, but faster execution */
+#define FSOUND_IMAADPCM      0x00400000  /* Contents are stored compressed as IMA ADPCM */
+#define FSOUND_VAG           0x00800000  /* For PS2 only - Contents are compressed as Sony VAG format */
+#define FSOUND_NONBLOCKING   0x01000000  /* For FSOUND_Stream_Open/FMUSIC_LoadSong - Causes stream or music to open in the background and not block the foreground app.  See FSOUND_Stream_GetOpenState or FMUSIC_GetOpenState to determine when it IS ready. */
+#define FSOUND_GCADPCM       0x02000000  /* For Gamecube only - Contents are compressed as Gamecube DSP-ADPCM format */
+#define FSOUND_MULTICHANNEL  0x04000000  /* For PS2 and Gamecube only - Contents are interleaved into a multi-channel (more than stereo) format */
+#define FSOUND_USECORE0      0x08000000  /* For PS2 only - Sample/Stream is forced to use hardware voices 00-23 */
+#define FSOUND_USECORE1      0x10000000  /* For PS2 only - Sample/Stream is forced to use hardware voices 24-47 */
+#define FSOUND_LOADMEMORYIOP 0x20000000  /* For PS2 only - "name" will be interpreted as a pointer to data for streaming and samples.  The address provided will be an IOP address */
+#define FSOUND_IGNORETAGS    0x40000000  /* Skips id3v2 etc tag checks when opening a stream, to reduce seek/read overhead when opening files (helps with CD performance) */
+#define FSOUND_STREAM_NET    0x80000000  /* Specifies an internet stream */
+
+#define FSOUND_NORMAL       (FSOUND_16BITS | FSOUND_SIGNED | FSOUND_MONO)      
+/* [DEFINE_END] */
+
+
+
+/*
+[DEFINE_START] 
+[
+    [NAME] 
+    FSOUND_CDPLAYMODES
+    
+    [DESCRIPTION]   
+    Playback method for a CD Audio track, with FSOUND_CD_SetPlayMode
+
+    [SEE_ALSO]    
+    FSOUND_CD_SetPlayMode  
+    FSOUND_CD_Play
+]
+*/
+#define FSOUND_CD_PLAYCONTINUOUS    0   /* Starts from the current track and plays to end of CD. */
+#define FSOUND_CD_PLAYONCE          1   /* Plays the specified track then stops. */
+#define FSOUND_CD_PLAYLOOPED        2   /* Plays the specified track looped, forever until stopped manually. */
+#define FSOUND_CD_PLAYRANDOM        3   /* Plays tracks in random order */
+/* [DEFINE_END] */
+
+
+/*
+[DEFINE_START] 
+[
+    [NAME] 
+    FSOUND_MISC_VALUES
+    
+    [DESCRIPTION]
+    Miscellaneous values for FMOD functions.
+
+    [SEE_ALSO]
+    FSOUND_PlaySound
+    FSOUND_PlaySoundEx
+    FSOUND_Sample_Alloc
+    FSOUND_Sample_Load
+    FSOUND_SetPan
+]
+*/
+#define FSOUND_FREE             -1      /* value to play on any free channel, or to allocate a sample in a free sample slot. */
+#define FSOUND_UNMANAGED        -2      /* value to allocate a sample that is NOT managed by FSOUND or placed in a sample slot. */
+#define FSOUND_ALL              -3      /* for a channel index , this flag will affect ALL channels available!  Not supported by every function. */
+#define FSOUND_STEREOPAN        -1      /* value for FSOUND_SetPan so that stereo sounds are not played at half volume.  See FSOUND_SetPan for more on this. */
+#define FSOUND_SYSTEMCHANNEL    -1000   /* special 'channel' ID for all channel based functions that want to alter the global FSOUND software mixing output channel */
+#define FSOUND_SYSTEMSAMPLE     -1000   /* special 'sample' ID for all sample based functions that want to alter the global FSOUND software mixing output sample */
+
+/* [DEFINE_END] */
+
+
+/*
+[STRUCTURE] 
+[
+    [DESCRIPTION]
+    Structure defining a reverb environment.
+    For more indepth descriptions of the reverb properties under win32, please see the EAX2 and EAX3
+    documentation at http://developer.creative.com/ under the 'downloads' section.
+    If they do not have the EAX3 documentation, then most information can be attained from
+    the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of EAX2.
+    Note the default reverb properties are the same as the FSOUND_PRESET_GENERIC preset.
+    Note that integer values that typically range from -10,000 to 1000 are represented in decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear.
+    PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox).  
+    Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then the reverb should product a similar effect on either platform.
+    
+    The numerical values listed below are the maximum, minimum and default values for each variable respectively.
+
+    [SEE_ALSO]
+    FSOUND_Reverb_SetProperties
+    FSOUND_Reverb_GetProperties
+    FSOUND_REVERB_PRESETS
+    FSOUND_REVERB_FLAGS
+]
+*/
+typedef struct _FSOUND_REVERB_PROPERTIES /* MIN     MAX    DEFAULT   DESCRIPTION */
+{                                   
+    unsigned int Environment;            /* 0     , 25    , 0      , sets all listener properties (WIN32/PS2 only) */
+    float        EnvSize;                /* 1.0   , 100.0 , 7.5    , environment size in meters (WIN32 only) */
+    float        EnvDiffusion;           /* 0.0   , 1.0   , 1.0    , environment diffusion (WIN32/XBOX) */
+    int          Room;                   /* -10000, 0     , -1000  , room effect level (at mid frequencies) (WIN32/XBOX/PS2) */
+    int          RoomHF;                 /* -10000, 0     , -100   , relative room effect level at high frequencies (WIN32/XBOX) */
+    int          RoomLF;                 /* -10000, 0     , 0      , relative room effect level at low frequencies (WIN32 only) */
+    float        DecayTime;              /* 0.1   , 20.0  , 1.49   , reverberation decay time at mid frequencies (WIN32/XBOX) */
+    float        DecayHFRatio;           /* 0.1   , 2.0   , 0.83   , high-frequency to mid-frequency decay time ratio (WIN32/XBOX) */
+    float        DecayLFRatio;           /* 0.1   , 2.0   , 1.0    , low-frequency to mid-frequency decay time ratio (WIN32 only) */
+    int          Reflections;            /* -10000, 1000  , -2602  , early reflections level relative to room effect (WIN32/XBOX) */
+    float        ReflectionsDelay;       /* 0.0   , 0.3   , 0.007  , initial reflection delay time (WIN32/XBOX) */
+    float        ReflectionsPan[3];      /*       ,       , [0,0,0], early reflections panning vector (WIN32 only) */
+    int          Reverb;                 /* -10000, 2000  , 200    , late reverberation level relative to room effect (WIN32/XBOX) */
+    float        ReverbDelay;            /* 0.0   , 0.1   , 0.011  , late reverberation delay time relative to initial reflection (WIN32/XBOX) */
+    float        ReverbPan[3];           /*       ,       , [0,0,0], late reverberation panning vector (WIN32 only) */
+    float        EchoTime;               /* .075  , 0.25  , 0.25   , echo time (WIN32/PS2 only.  PS2 = Delay time for ECHO/DELAY modes only) */
+    float        EchoDepth;              /* 0.0   , 1.0   , 0.0    , echo depth (WIN32/PS2 only.  PS2 = Feedback level for ECHO mode only) */
+    float        ModulationTime;         /* 0.04  , 4.0   , 0.25   , modulation time (WIN32 only) */
+    float        ModulationDepth;        /* 0.0   , 1.0   , 0.0    , modulation depth (WIN32 only) */
+    float        AirAbsorptionHF;        /* -100  , 0.0   , -5.0   , change in level per meter at high frequencies (WIN32 only) */
+    float        HFReference;            /* 1000.0, 20000 , 5000.0 , reference high frequency (hz) (WIN32/XBOX) */
+    float        LFReference;            /* 20.0  , 1000.0, 250.0  , reference low frequency (hz) (WIN32 only) */
+    float        RoomRolloffFactor;      /* 0.0   , 10.0  , 0.0    , like FSOUND_3D_SetRolloffFactor but for room effect (WIN32/XBOX) */
+    float        Diffusion;              /* 0.0   , 100.0 , 100.0  , Value that controls the echo density in the late reverberation decay. (XBOX only) */
+    float        Density;                /* 0.0   , 100.0 , 100.0  , Value that controls the modal density in the late reverberation decay (XBOX only) */
+    unsigned int Flags;                  /* FSOUND_REVERB_FLAGS - modifies the behavior of above properties (WIN32/PS2 only) */
+} FSOUND_REVERB_PROPERTIES;
+
+
+/*
+[DEFINE_START] 
+[
+    [NAME] 
+    FSOUND_REVERB_FLAGS
+    
+    [DESCRIPTION]
+    Values for the Flags member of the FSOUND_REVERB_PROPERTIES structure.
+
+    [SEE_ALSO]
+    FSOUND_REVERB_PROPERTIES
+]
+*/
+#define FSOUND_REVERB_FLAGS_DECAYTIMESCALE        0x00000001 /* 'EnvSize' affects reverberation decay time */
+#define FSOUND_REVERB_FLAGS_REFLECTIONSSCALE      0x00000002 /* 'EnvSize' affects reflection level */
+#define FSOUND_REVERB_FLAGS_REFLECTIONSDELAYSCALE 0x00000004 /* 'EnvSize' affects initial reflection delay time */
+#define FSOUND_REVERB_FLAGS_REVERBSCALE           0x00000008 /* 'EnvSize' affects reflections level */
+#define FSOUND_REVERB_FLAGS_REVERBDELAYSCALE      0x00000010 /* 'EnvSize' affects late reverberation delay time */
+#define FSOUND_REVERB_FLAGS_DECAYHFLIMIT          0x00000020 /* AirAbsorptionHF affects DecayHFRatio */
+#define FSOUND_REVERB_FLAGS_ECHOTIMESCALE         0x00000040 /* 'EnvSize' affects echo time */
+#define FSOUND_REVERB_FLAGS_MODULATIONTIMESCALE   0x00000080 /* 'EnvSize' affects modulation time */
+#define FSOUND_REVERB_FLAGS_CORE0                 0x00000100 /* PS2 Only - Reverb is applied to CORE0 (hw voices 0-23) */
+#define FSOUND_REVERB_FLAGS_CORE1                 0x00000200 /* PS2 Only - Reverb is applied to CORE1 (hw voices 24-47) */
+#define FSOUND_REVERB_FLAGS_DEFAULT              (FSOUND_REVERB_FLAGS_DECAYTIMESCALE |        \
+                                                  FSOUND_REVERB_FLAGS_REFLECTIONSSCALE |      \
+                                                  FSOUND_REVERB_FLAGS_REFLECTIONSDELAYSCALE | \
+                                                  FSOUND_REVERB_FLAGS_REVERBSCALE |           \
+                                                  FSOUND_REVERB_FLAGS_REVERBDELAYSCALE |      \
+                                                  FSOUND_REVERB_FLAGS_DECAYHFLIMIT |          \
+                                                  FSOUND_REVERB_FLAGS_CORE0 |                 \
+                                                  FSOUND_REVERB_FLAGS_CORE1 )
+/* [DEFINE_END] */
+
+
+
+
+/*
+[DEFINE_START] 
+[
+    [NAME] 
+    FSOUND_REVERB_PRESETS
+    
+    [DESCRIPTION]   
+    A set of predefined environment PARAMETERS, created by Creative Labs
+    These are used to initialize an FSOUND_REVERB_PROPERTIES structure statically.
+    ie 
+    FSOUND_REVERB_PROPERTIES prop = FSOUND_PRESET_GENERIC;
+
+    [SEE_ALSO]
+    FSOUND_Reverb_SetProperties
+]
+*/
+/*                                     Env  Size    Diffus  Room   RoomHF  RmLF DecTm   DecHF  DecLF   Refl  RefDel  RefPan               Revb  RevDel  ReverbPan           EchoTm  EchDp  ModTm  ModDp  AirAbs  HFRef    LFRef  RRlOff Diffus  Densty  FLAGS */
+#define FSOUND_PRESET_OFF              {0,     7.5f,   1.00f, -10000, -10000, 0,   1.00f,  1.00f, 1.0f,  -2602, 0.007f, { 0.0f,0.0f,0.0f },   200, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f,   0.0f,   0.0f, 0x33f }
+#define FSOUND_PRESET_GENERIC          {0,     7.5f,   1.00f, -1000,  -100,   0,   1.49f,  0.83f, 1.0f,  -2602, 0.007f, { 0.0f,0.0f,0.0f },   200, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_PADDEDCELL       {1,     1.4f,   1.00f, -1000,  -6000,  0,   0.17f,  0.10f, 1.0f,  -1204, 0.001f, { 0.0f,0.0f,0.0f },   207, 0.002f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_ROOM                {2,  1.9f,   1.00f, -1000,  -454,   0,   0.40f,  0.83f, 1.0f,  -1646, 0.002f, { 0.0f,0.0f,0.0f },    53, 0.003f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_BATHROOM                {3,      1.4f,   1.00f, -1000,  -1200,  0,   1.49f,  0.54f, 1.0f,   -370, 0.007f, { 0.0f,0.0f,0.0f },  1030, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f,  60.0f, 0x3f }
+#define FSOUND_PRESET_LIVINGROOM       {4,     2.5f,   1.00f, -1000,  -6000,  0,   0.50f,  0.10f, 1.0f,  -1376, 0.003f, { 0.0f,0.0f,0.0f }, -1104, 0.004f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_STONEROOM        {5,     11.6f,  1.00f, -1000,  -300,   0,   2.31f,  0.64f, 1.0f,   -711, 0.012f, { 0.0f,0.0f,0.0f },    83, 0.017f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_AUDITORIUM       {6,     21.6f,  1.00f, -1000,  -476,   0,   4.32f,  0.59f, 1.0f,   -789, 0.020f, { 0.0f,0.0f,0.0f },  -289, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_CONCERTHALL      {7,     19.6f,  1.00f, -1000,  -500,   0,   3.92f,  0.70f, 1.0f,  -1230, 0.020f, { 0.0f,0.0f,0.0f },    -2, 0.029f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_CAVE             {8,     14.6f,  1.00f, -1000,  0,      0,   2.91f,  1.30f, 1.0f,   -602, 0.015f, { 0.0f,0.0f,0.0f },  -302, 0.022f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f }
+#define FSOUND_PRESET_ARENA            {9,     36.2f,  1.00f, -1000,  -698,   0,   7.24f,  0.33f, 1.0f,  -1166, 0.020f, { 0.0f,0.0f,0.0f },    16, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_HANGAR           {10,    50.3f,  1.00f, -1000,  -1000,  0,   10.05f, 0.23f, 1.0f,   -602, 0.020f, { 0.0f,0.0f,0.0f },   198, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_CARPETTEDHALLWAY {11,    1.9f,   1.00f, -1000,  -4000,  0,   0.30f,  0.10f, 1.0f,  -1831, 0.002f, { 0.0f,0.0f,0.0f }, -1630, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_HALLWAY          {12,    1.8f,   1.00f, -1000,  -300,   0,   1.49f,  0.59f, 1.0f,  -1219, 0.007f, { 0.0f,0.0f,0.0f },   441, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_STONECORRIDOR    {13,    13.5f,  1.00f, -1000,  -237,   0,   2.70f,  0.79f, 1.0f,  -1214, 0.013f, { 0.0f,0.0f,0.0f },   395, 0.020f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_ALLEY           {14,     7.5f,   0.30f, -1000,  -270,   0,   1.49f,  0.86f, 1.0f,  -1204, 0.007f, { 0.0f,0.0f,0.0f },    -4, 0.011f, { 0.0f,0.0f,0.0f }, 0.125f, 0.95f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_FOREST          {15,     38.0f,  0.30f, -1000,  -3300,  0,   1.49f,  0.54f, 1.0f,  -2560, 0.162f, { 0.0f,0.0f,0.0f },  -229, 0.088f, { 0.0f,0.0f,0.0f }, 0.125f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f,  79.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_CITY             {16,    7.5f,   0.50f, -1000,  -800,   0,   1.49f,  0.67f, 1.0f,  -2273, 0.007f, { 0.0f,0.0f,0.0f }, -1691, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f,  50.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_MOUNTAINS        {17,    100.0f, 0.27f, -1000,  -2500,  0,   1.49f,  0.21f, 1.0f,  -2780, 0.300f, { 0.0f,0.0f,0.0f }, -1434, 0.100f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f,  27.0f, 100.0f, 0x1f }
+#define FSOUND_PRESET_QUARRY           {18,    17.5f,  1.00f, -1000,  -1000,  0,   1.49f,  0.83f, 1.0f, -10000, 0.061f, { 0.0f,0.0f,0.0f },   500, 0.025f, { 0.0f,0.0f,0.0f }, 0.125f, 0.70f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_PLAIN            {19,    42.5f,  0.21f, -1000,  -2000,  0,   1.49f,  0.50f, 1.0f,  -2466, 0.179f, { 0.0f,0.0f,0.0f }, -1926, 0.100f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f,  21.0f, 100.0f, 0x3f }
+#define FSOUND_PRESET_PARKINGLOT       {20,    8.3f,   1.00f, -1000,  0,      0,   1.65f,  1.50f, 1.0f,  -1363, 0.008f, { 0.0f,0.0f,0.0f }, -1153, 0.012f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f }
+#define FSOUND_PRESET_SEWERPIPE        {21,    1.7f,   0.80f, -1000,  -1000,  0,   2.81f,  0.14f, 1.0f,    429, 0.014f, { 0.0f,0.0f,0.0f },  1023, 0.021f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 0.000f, -5.0f, 5000.0f, 250.0f, 0.0f,  80.0f,  60.0f, 0x3f }
+#define FSOUND_PRESET_UNDERWATER       {22,    1.8f,   1.00f, -1000,  -4000,  0,   1.49f,  0.10f, 1.0f,   -449, 0.007f, { 0.0f,0.0f,0.0f },  1700, 0.011f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 1.18f, 0.348f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x3f }
+
+/* Non I3DL2 presets */
+
+#define FSOUND_PRESET_DRUGGED          {23,    1.9f,   0.50f, -1000,  0,      0,   8.39f,  1.39f, 1.0f,  -115,  0.002f, { 0.0f,0.0f,0.0f },   985, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 0.25f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f }
+#define FSOUND_PRESET_DIZZY            {24,    1.8f,   0.60f, -1000,  -400,   0,   17.23f, 0.56f, 1.0f,  -1713, 0.020f, { 0.0f,0.0f,0.0f },  -613, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 1.00f, 0.81f, 0.310f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f }
+#define FSOUND_PRESET_PSYCHOTIC        {25,    1.0f,   0.50f, -1000,  -151,   0,   7.56f,  0.91f, 1.0f,  -626,  0.020f, { 0.0f,0.0f,0.0f },   774, 0.030f, { 0.0f,0.0f,0.0f }, 0.250f, 0.00f, 4.00f, 1.000f, -5.0f, 5000.0f, 250.0f, 0.0f, 100.0f, 100.0f, 0x1f }
+
+/* PlayStation 2 Only presets */
+
+#define FSOUND_PRESET_PS2_ROOM         {1,     0,          0,         0,  0,      0,   0.0f,   0.0f,  0.0f,     0,  0.000f, { 0.0f,0.0f,0.0f },     0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f,  0.0f, 0000.0f,   0.0f, 0.0f,   0.0f,   0.0f, 0x31f }
+#define FSOUND_PRESET_PS2_STUDIO_A     {2,     0,          0,         0,  0,      0,   0.0f,   0.0f,  0.0f,     0,  0.000f, { 0.0f,0.0f,0.0f },     0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f,  0.0f, 0000.0f,   0.0f, 0.0f,   0.0f,   0.0f, 0x31f }
+#define FSOUND_PRESET_PS2_STUDIO_B     {3,     0,          0,         0,  0,      0,   0.0f,   0.0f,  0.0f,     0,  0.000f, { 0.0f,0.0f,0.0f },     0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f,  0.0f, 0000.0f,   0.0f, 0.0f,   0.0f,   0.0f, 0x31f }
+#define FSOUND_PRESET_PS2_STUDIO_C     {4,     0,          0,         0,  0,      0,   0.0f,   0.0f,  0.0f,     0,  0.000f, { 0.0f,0.0f,0.0f },     0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f,  0.0f, 0000.0f,   0.0f, 0.0f,   0.0f,   0.0f, 0x31f }
+#define FSOUND_PRESET_PS2_HALL         {5,     0,          0,         0,  0,      0,   0.0f,   0.0f,  0.0f,     0,  0.000f, { 0.0f,0.0f,0.0f },     0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f,  0.0f, 0000.0f,   0.0f, 0.0f,   0.0f,   0.0f, 0x31f }
+#define FSOUND_PRESET_PS2_SPACE        {6,     0,          0,         0,  0,      0,   0.0f,   0.0f,  0.0f,     0,  0.000f, { 0.0f,0.0f,0.0f },     0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f,  0.0f, 0000.0f,   0.0f, 0.0f,   0.0f,   0.0f, 0x31f }
+#define FSOUND_PRESET_PS2_ECHO         {7,     0,          0,         0,  0,      0,   0.0f,   0.0f,  0.0f,     0,  0.000f, { 0.0f,0.0f,0.0f },     0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f,  0.0f, 0000.0f,   0.0f, 0.0f,   0.0f,   0.0f, 0x31f }
+#define FSOUND_PRESET_PS2_DELAY        {8,     0,          0,         0,  0,      0,   0.0f,   0.0f,  0.0f,     0,  0.000f, { 0.0f,0.0f,0.0f },     0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f,  0.0f, 0000.0f,   0.0f, 0.0f,   0.0f,   0.0f, 0x31f }
+#define FSOUND_PRESET_PS2_PIPE         {9,     0,          0,         0,  0,      0,   0.0f,   0.0f,  0.0f,     0,  0.000f, { 0.0f,0.0f,0.0f },     0, 0.000f, { 0.0f,0.0f,0.0f }, 0.000f, 0.00f, 0.00f, 0.000f,  0.0f, 0000.0f,   0.0f, 0.0f,   0.0f,   0.0f, 0x31f }
+
+/* [DEFINE_END] */
+
+
+/*
+[STRUCTURE] 
+[
+    [DESCRIPTION]
+    Structure defining the properties for a reverb source, related to a FSOUND channel.
+    For more indepth descriptions of the reverb properties under win32, please see the EAX3
+    documentation at http://developer.creative.com/ under the 'downloads' section.
+    If they do not have the EAX3 documentation, then most information can be attained from
+    the EAX2 documentation, as EAX3 only adds some more parameters and functionality on top of 
+    EAX2.
+    
+    Note the default reverb properties are the same as the FSOUND_PRESET_GENERIC preset.
+    Note that integer values that typically range from -10,000 to 1000 are represented in 
+    decibels, and are of a logarithmic scale, not linear, wheras float values are typically linear.
+    PORTABILITY: Each member has the platform it supports in braces ie (win32/xbox).  
+    Some reverb parameters are only supported in win32 and some only on xbox. If all parameters are set then
+    the reverb should product a similar effect on either platform.
+    Linux and FMODCE do not support the reverb api.
+    
+    The numerical values listed below are the maximum, minimum and default values for each variable respectively.
+
+    [SEE_ALSO]
+    FSOUND_Reverb_SetChannelProperties
+    FSOUND_Reverb_GetChannelProperties
+    FSOUND_REVERB_CHANNELFLAGS
+]
+*/
+typedef struct _FSOUND_REVERB_CHANNELPROPERTIES /* MIN     MAX    DEFAULT */
+{                                   
+    int    Direct;                              /* -10000, 1000,  0,    direct path level (at low and mid frequencies) (WIN32/XBOX) */
+    int    DirectHF;                            /* -10000, 0,     0,    relative direct path level at high frequencies (WIN32/XBOX) */
+    int    Room;                                /* -10000, 1000,  0,    room effect level (at low and mid frequencies) (WIN32/XBOX/PS2) */
+    int    RoomHF;                              /* -10000, 0,     0,    relative room effect level at high frequencies (WIN32/XBOX) */
+    int    Obstruction;                         /* -10000, 0,     0,    main obstruction control (attenuation at high frequencies)  (WIN32/XBOX) */
+    float  ObstructionLFRatio;                  /* 0.0,    1.0,   0.0,  obstruction low-frequency level re. main control (WIN32/XBOX) */
+    int    Occlusion;                           /* -10000, 0,     0,    main occlusion control (attenuation at high frequencies) (WIN32/XBOX) */
+    float  OcclusionLFRatio;                    /* 0.0,    1.0,   0.25, occlusion low-frequency level re. main control (WIN32/XBOX) */
+    float  OcclusionRoomRatio;                  /* 0.0,    10.0,  1.5,  relative occlusion control for room effect (WIN32) */
+    float  OcclusionDirectRatio;                /* 0.0,    10.0,  1.0,  relative occlusion control for direct path (WIN32) */
+    int    Exclusion;                           /* -10000, 0,     0,    main exlusion control (attenuation at high frequencies) (WIN32) */
+    float  ExclusionLFRatio;                    /* 0.0,    1.0,   1.0,  exclusion low-frequency level re. main control (WIN32) */
+    int    OutsideVolumeHF;                     /* -10000, 0,     0,    outside sound cone level at high frequencies (WIN32) */
+    float  DopplerFactor;                       /* 0.0,    10.0,  0.0,  like DS3D flDopplerFactor but per source (WIN32) */
+    float  RolloffFactor;                       /* 0.0,    10.0,  0.0,  like DS3D flRolloffFactor but per source (WIN32) */
+    float  RoomRolloffFactor;                   /* 0.0,    10.0,  0.0,  like DS3D flRolloffFactor but for room effect (WIN32/XBOX) */
+    float  AirAbsorptionFactor;                 /* 0.0,    10.0,  1.0,  multiplies AirAbsorptionHF member of FSOUND_REVERB_PROPERTIES (WIN32) */
+    int    Flags;                               /* FSOUND_REVERB_CHANNELFLAGS - modifies the behavior of properties (WIN32) */
+} FSOUND_REVERB_CHANNELPROPERTIES;
+
+
+/*
+[DEFINE_START] 
+[
+    [NAME] 
+    FSOUND_REVERB_CHANNELFLAGS
+    
+    [DESCRIPTION]
+    Values for the Flags member of the FSOUND_REVERB_CHANNELPROPERTIES structure.
+
+    [SEE_ALSO]
+    FSOUND_REVERB_CHANNELPROPERTIES
+]
+*/
+#define FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO  0x00000001 /* Automatic setting of 'Direct'  due to distance from listener */
+#define FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO      0x00000002 /* Automatic setting of 'Room'  due to distance from listener */
+#define FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO    0x00000004 /* Automatic setting of 'RoomHF' due to distance from listener */
+#define FSOUND_REVERB_CHANNELFLAGS_DEFAULT       (FSOUND_REVERB_CHANNELFLAGS_DIRECTHFAUTO |   \
+                                                  FSOUND_REVERB_CHANNELFLAGS_ROOMAUTO|        \
+                                                  FSOUND_REVERB_CHANNELFLAGS_ROOMHFAUTO)
+/* [DEFINE_END] */
+
+
+/*
+[ENUM] 
+[
+    [DESCRIPTION]
+    These values are used with FSOUND_FX_Enable to enable DirectX 8 FX for a channel.
+
+    [SEE_ALSO]
+    FSOUND_FX_Enable
+    FSOUND_FX_Disable
+    FSOUND_FX_SetChorus
+    FSOUND_FX_SetCompressor
+    FSOUND_FX_SetDistortion
+    FSOUND_FX_SetEcho
+    FSOUND_FX_SetFlanger
+    FSOUND_FX_SetGargle
+    FSOUND_FX_SetI3DL2Reverb
+    FSOUND_FX_SetParamEQ
+    FSOUND_FX_SetWavesReverb
+]
+*/
+enum FSOUND_FX_MODES
+{
+    FSOUND_FX_CHORUS,
+    FSOUND_FX_COMPRESSOR,
+    FSOUND_FX_DISTORTION,
+    FSOUND_FX_ECHO,
+    FSOUND_FX_FLANGER,
+    FSOUND_FX_GARGLE,
+    FSOUND_FX_I3DL2REVERB,
+    FSOUND_FX_PARAMEQ,
+    FSOUND_FX_WAVES_REVERB,
+
+    FSOUND_FX_MAX
+};
+
+/*
+[ENUM]
+[
+    [DESCRIPTION]   
+    These are speaker types defined for use with the FSOUND_SetSpeakerMode command.
+    Note - Only reliably works with FSOUND_OUTPUT_DSOUND or FSOUND_OUTPUT_XBOX output modes.  Other output modes will only 
+    interpret FSOUND_SPEAKERMODE_MONO and set everything else to be stereo.
+
+    Using either DolbyDigital or DTS will use whatever 5.1 digital mode is available if destination hardware is unsure.
+
+    [SEE_ALSO]
+    FSOUND_SetSpeakerMode
+
+]
+*/
+enum FSOUND_SPEAKERMODES
+{
+    FSOUND_SPEAKERMODE_DOLBYDIGITAL,        /* Dolby Digital Output (XBOX or PC only). */
+    FSOUND_SPEAKERMODE_HEADPHONES,          /* The speakers are headphones. */
+    FSOUND_SPEAKERMODE_MONO,                /* The speakers are monaural. */
+    FSOUND_SPEAKERMODE_QUAD,                /* The speakers are quadraphonic.  */
+    FSOUND_SPEAKERMODE_STEREO,              /* The speakers are stereo (default value). */
+    FSOUND_SPEAKERMODE_SURROUND,            /* The speakers are surround sound. */
+    FSOUND_SPEAKERMODE_DTS,                 /* DTS output (XBOX only). */
+    FSOUND_SPEAKERMODE_PROLOGIC2,           /* Dolby Prologic 2.  Playstation 2 and Gamecube only.  PlayStation 2 doesnt support interior panning, but supports 48 voices simultaneously. */
+    FSOUND_SPEAKERMODE_PROLOGIC2_INTERIOR   /* Dolby Prologic 2.  Playstation 2 and Gamecube only.  PlayStation 2 does support interior panning, but only supports 24 voices simultaneously. */
+};
+
+
+/*
+[DEFINE_START] 
+[
+    [NAME] 
+    FSOUND_INIT_FLAGS
+    
+    [DESCRIPTION]   
+    Initialization flags.  Use them with FSOUND_Init in the flags parameter to change various behaviour.
+    
+    FSOUND_INIT_ENABLESYSTEMCHANNELFX Is an init mode which enables the FSOUND mixer buffer to be affected by DirectX 8 effects.
+    Note that due to limitations of DirectSound, FSOUND_Init may fail if this is enabled because the buffersize is too small.
+    This can be fixed with FSOUND_SetBufferSize.  Increase the BufferSize until it works.
+    When it is enabled you can use the FSOUND_FX api, and use FSOUND_SYSTEMCHANNEL as the channel id when setting parameters.
+
+    [SEE_ALSO]
+    FSOUND_Init
+]
+*/
+#define FSOUND_INIT_USEDEFAULTMIDISYNTH     0x0001    /* Win32 only - Causes MIDI playback to force software decoding. */
+#define FSOUND_INIT_GLOBALFOCUS             0x0002    /* Win32 only - For DirectSound output - sound is not muted when window is out of focus. */
+#define FSOUND_INIT_ENABLESYSTEMCHANNELFX   0x0004    /* Win32 only - For DirectSound output - Allows FSOUND_FX api to be used on global software mixer output! (use FSOUND_SYSTEMCHANNEL as channel id) */
+#define FSOUND_INIT_ACCURATEVULEVELS        0x0008    /* This latency adjusts FSOUND_GetCurrentLevels, but incurs a small cpu and memory hit */
+#define FSOUND_INIT_PS2_DISABLECORE0REVERB  0x0010    /* PS2 only   - Disable reverb on CORE 0 (SPU2 voices 00-23) to regain SRAM */
+#define FSOUND_INIT_PS2_DISABLECORE1REVERB  0x0020    /* PS2 only   - Disable reverb on CORE 1 (SPU2 voices 24-47) to regain SRAM */
+#define FSOUND_INIT_PS2_SWAPDMACORES        0x0040    /* PS2 only   - By default FMOD uses DMA CH0 for mixing, CH1 for uploads, this flag swaps them around */
+#define FSOUND_INIT_DONTLATENCYADJUST       0x0080    /* Callbacks are not latency adjusted, and are called at mix time.  Also information functions are immediate */
+#define FSOUND_INIT_GC_INITLIBS             0x0100    /* GC only    - Initializes GC audio libraries */
+#define FSOUND_INIT_STREAM_FROM_MAIN_THREAD 0x0200    /* Turns off fmod streamer thread, and makes streaming update from FSOUND_Update called by the user */
+#define FSOUND_INIT_PS2_USEVOLUMERAMPING    0x0400    /* PS2 only   - Turns on volume ramping system to remove hardware clicks. */
+#define FSOUND_INIT_DSOUND_DEFERRED         0x0800    /* Win32 only - For DirectSound output.  3D commands are batched together and executed at FSOUND_Update. */
+#define FSOUND_INIT_DSOUND_HRTF_LIGHT       0x1000    /* Win32 only - For DirectSound output.  FSOUND_HW3D buffers use a slightly higher quality algorithm when 3d hardware acceleration is not present. */
+#define FSOUND_INIT_DSOUND_HRTF_FULL        0x2000    /* Win32 only - For DirectSound output.  FSOUND_HW3D buffers use full quality 3d playback when 3d hardware acceleration is not present. */
+/* [DEFINE_END] */
+
+
+/*
+[ENUM]
+[
+    [DESCRIPTION]   
+    Status values for internet streams. Use FSOUND_Stream_Net_GetStatus to get the current status of an internet stream.
+
+    [SEE_ALSO]
+    FSOUND_Stream_Net_GetStatus
+]
+*/
+enum FSOUND_STREAM_NET_STATUS
+{
+    FSOUND_STREAM_NET_NOTCONNECTED = 0,     /* Stream hasn't connected yet */
+    FSOUND_STREAM_NET_CONNECTING,           /* Stream is connecting to remote host */
+    FSOUND_STREAM_NET_BUFFERING,            /* Stream is buffering data */
+    FSOUND_STREAM_NET_READY,                /* Stream is ready to play */
+    FSOUND_STREAM_NET_ERROR                 /* Stream has suffered a fatal error */
+};
+
+
+/*
+[ENUM]
+[
+    [DESCRIPTION]   
+    Describes the type of a particular tag field.
+
+    [SEE_ALSO]
+    FSOUND_Stream_GetNumTagFields
+    FSOUND_Stream_GetTagField
+    FSOUND_Stream_FindTagField
+]
+*/
+enum FSOUND_TAGFIELD_TYPE
+{
+    FSOUND_TAGFIELD_VORBISCOMMENT = 0,      /* A vorbis comment */
+    FSOUND_TAGFIELD_ID3V1,                  /* Part of an ID3v1 tag */
+    FSOUND_TAGFIELD_ID3V2,                  /* An ID3v2 frame */
+    FSOUND_TAGFIELD_SHOUTCAST,              /* A SHOUTcast header line */
+    FSOUND_TAGFIELD_ICECAST,                /* An Icecast header line */
+    FSOUND_TAGFIELD_ASF                     /* An Advanced Streaming Format header line */
+};
+
+
+/*
+[DEFINE_START] 
+[
+    [NAME] 
+    FSOUND_STATUS_FLAGS
+    
+    [DESCRIPTION]   
+    These values describe the protocol and format of an internet stream. Use FSOUND_Stream_Net_GetStatus to retrieve this information for an open internet stream.
+    
+    [SEE_ALSO]
+    FSOUND_Stream_Net_GetStatus
+]
+*/
+#define FSOUND_PROTOCOL_SHOUTCAST   0x00000001
+#define FSOUND_PROTOCOL_ICECAST     0x00000002
+#define FSOUND_PROTOCOL_HTTP        0x00000004
+#define FSOUND_FORMAT_MPEG          0x00010000
+#define FSOUND_FORMAT_OGGVORBIS     0x00020000
+/* [DEFINE_END] */
+
+
+/*
+[STRUCTURE] 
+[
+    [DESCRIPTION]
+    Structure defining a CD table of contents. This structure is returned as a tag from FSOUND_Stream_FindTagField when the tag name "CD_TOC" is specified.
+    Note: All tracks on the CD - including data tracks- will be represented in this structure so it's use for anything other than generating disc id information is not recommended.
+    See the cdda example program for info on retrieving and using this structure.
+
+    [SEE_ALSO]
+    FSOUND_Stream_Open
+    FSOUND_Stream_FindTagField
+]
+*/
+typedef struct _FSOUND_TOC_TAG
+{
+    char name[4];                           /* The string "TOC", just in case this structure is accidentally treated as a string */
+    int  numtracks;                         /* The number of tracks on the CD */
+    int  min[100];                          /* The start offset of each track in minutes */
+    int  sec[100];                          /* The start offset of each track in seconds */
+    int  frame[100];                        /* The start offset of each track in frames */
+
+} FSOUND_TOC_TAG;
+
+
+/* ========================================================================================== */
+/* FUNCTION PROTOTYPES                                                                        */
+/* ========================================================================================== */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ================================== */
+/* Initialization / Global functions. */
+/* ================================== */
+
+/* 
+    PRE - FSOUND_Init functions. These can't be called after FSOUND_Init is 
+    called (they will fail). They set up FMOD system functionality. 
+*/
+
+DLL_API signed char     F_API FSOUND_SetOutput(int outputtype);
+DLL_API signed char     F_API FSOUND_SetDriver(int driver);
+DLL_API signed char     F_API FSOUND_SetMixer(int mixer);
+DLL_API signed char     F_API FSOUND_SetBufferSize(int len_ms);
+DLL_API signed char     F_API FSOUND_SetHWND(void *hwnd);
+DLL_API signed char     F_API FSOUND_SetMinHardwareChannels(int min);
+DLL_API signed char     F_API FSOUND_SetMaxHardwareChannels(int max);
+DLL_API signed char     F_API FSOUND_SetMemorySystem(void *pool, 
+                                                     int poollen, 
+                                                     FSOUND_ALLOCCALLBACK   useralloc,
+                                                     FSOUND_REALLOCCALLBACK userrealloc,
+                                                     FSOUND_FREECALLBACK    userfree);
+/* 
+    Main initialization / closedown functions.
+    Note : Use FSOUND_INIT_USEDEFAULTMIDISYNTH with FSOUND_Init for software override 
+           with MIDI playback.
+         : Use FSOUND_INIT_GLOBALFOCUS with FSOUND_Init to make sound audible no matter 
+           which window is in focus. (FSOUND_OUTPUT_DSOUND only)
+*/
+
+DLL_API signed char     F_API FSOUND_Init(int mixrate, int maxsoftwarechannels, unsigned int flags);
+DLL_API void            F_API FSOUND_Close();
+
+/* 
+    Runtime system level functions 
+*/
+
+DLL_API void            F_API FSOUND_Update();   /* This is called to update 3d sound / non-realtime output */
+
+DLL_API void            F_API FSOUND_SetSpeakerMode(unsigned int speakermode);
+DLL_API void            F_API FSOUND_SetSFXMasterVolume(int volume);
+DLL_API void            F_API FSOUND_SetPanSeperation(float pansep);
+DLL_API void            F_API FSOUND_File_SetCallbacks(FSOUND_OPENCALLBACK  useropen,
+                                                       FSOUND_CLOSECALLBACK userclose,
+                                                       FSOUND_READCALLBACK  userread,
+                                                       FSOUND_SEEKCALLBACK  userseek,
+                                                       FSOUND_TELLCALLBACK  usertell);
+
+/* 
+    System information functions. 
+*/
+
+DLL_API int             F_API FSOUND_GetError();
+DLL_API float           F_API FSOUND_GetVersion();
+DLL_API int             F_API FSOUND_GetOutput();
+DLL_API void *          F_API FSOUND_GetOutputHandle();
+DLL_API int             F_API FSOUND_GetDriver();
+DLL_API int             F_API FSOUND_GetMixer();
+DLL_API int             F_API FSOUND_GetNumDrivers();
+DLL_API const char *    F_API FSOUND_GetDriverName(int id);
+DLL_API signed char     F_API FSOUND_GetDriverCaps(int id, unsigned int *caps);
+DLL_API int             F_API FSOUND_GetOutputRate();
+DLL_API int             F_API FSOUND_GetMaxChannels();
+DLL_API int             F_API FSOUND_GetMaxSamples();
+DLL_API int             F_API FSOUND_GetSFXMasterVolume();
+DLL_API signed char     F_API FSOUND_GetNumHWChannels(int *num2d, int *num3d, int *total);
+DLL_API int             F_API FSOUND_GetChannelsPlaying();
+DLL_API float           F_API FSOUND_GetCPUUsage();
+DLL_API void            F_API FSOUND_GetMemoryStats(unsigned int *currentalloced, unsigned int *maxalloced);
+
+/* =================================== */
+/* Sample management / load functions. */
+/* =================================== */
+
+/* 
+    Sample creation and management functions
+    Note : Use FSOUND_LOADMEMORY   flag with FSOUND_Sample_Load to load from memory.
+           Use FSOUND_LOADRAW      flag with FSOUND_Sample_Load to treat as as raw pcm data.
+*/
+
+DLL_API FSOUND_SAMPLE * F_API FSOUND_Sample_Load(int index, const char *name_or_data, unsigned int mode, int offset, int length);
+DLL_API FSOUND_SAMPLE * F_API FSOUND_Sample_Alloc(int index, int length, unsigned int mode, int deffreq, int defvol, int defpan, int defpri);
+DLL_API void            F_API FSOUND_Sample_Free(FSOUND_SAMPLE *sptr);
+DLL_API signed char     F_API FSOUND_Sample_Upload(FSOUND_SAMPLE *sptr, void *srcdata, unsigned int mode);
+DLL_API signed char     F_API FSOUND_Sample_Lock(FSOUND_SAMPLE *sptr, int offset, int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2);
+DLL_API signed char     F_API FSOUND_Sample_Unlock(FSOUND_SAMPLE *sptr, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2);
+
+/*
+    Sample control functions
+*/
+
+DLL_API signed char     F_API FSOUND_Sample_SetMode(FSOUND_SAMPLE *sptr, unsigned int mode);
+DLL_API signed char     F_API FSOUND_Sample_SetLoopPoints(FSOUND_SAMPLE *sptr, int loopstart, int loopend);
+DLL_API signed char     F_API FSOUND_Sample_SetDefaults(FSOUND_SAMPLE *sptr, int deffreq, int defvol, int defpan, int defpri);
+DLL_API signed char     F_API FSOUND_Sample_SetDefaultsEx(FSOUND_SAMPLE *sptr, int deffreq, int defvol, int defpan, int defpri, int varfreq, int varvol, int varpan);
+DLL_API signed char     F_API FSOUND_Sample_SetMinMaxDistance(FSOUND_SAMPLE *sptr, float min, float max);
+DLL_API signed char     F_API FSOUND_Sample_SetMaxPlaybacks(FSOUND_SAMPLE *sptr, int max);
+
+/* 
+    Sample information functions
+*/
+
+DLL_API FSOUND_SAMPLE * F_API FSOUND_Sample_Get(int sampno);
+DLL_API const char *    F_API FSOUND_Sample_GetName(FSOUND_SAMPLE *sptr);
+DLL_API unsigned int    F_API FSOUND_Sample_GetLength(FSOUND_SAMPLE *sptr);
+DLL_API signed char     F_API FSOUND_Sample_GetLoopPoints(FSOUND_SAMPLE *sptr, int *loopstart, int *loopend);
+DLL_API signed char     F_API FSOUND_Sample_GetDefaults(FSOUND_SAMPLE *sptr, int *deffreq, int *defvol, int *defpan, int *defpri);
+DLL_API signed char     F_API FSOUND_Sample_GetDefaultsEx(FSOUND_SAMPLE *sptr, int *deffreq, int *defvol, int *defpan, int *defpri, int *varfreq, int *varvol, int *varpan);
+DLL_API unsigned int    F_API FSOUND_Sample_GetMode(FSOUND_SAMPLE *sptr);
+DLL_API signed char     F_API FSOUND_Sample_GetMinMaxDistance(FSOUND_SAMPLE *sptr, float *min, float *max);
+  
+/* ============================ */
+/* Channel control functions.   */
+/* ============================ */
+
+/* 
+    Playing and stopping sounds.  
+    Note : Use FSOUND_FREE as the 'channel' variable, to let FMOD pick a free channel for you.
+           Use FSOUND_ALL as the 'channel' variable to control ALL channels with one function call!
+*/
+
+DLL_API int             F_API FSOUND_PlaySound(int channel, FSOUND_SAMPLE *sptr);
+DLL_API int             F_API FSOUND_PlaySoundEx(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused);
+DLL_API signed char     F_API FSOUND_StopSound(int channel);
+
+/* 
+    Functions to control playback of a channel.
+    Note : FSOUND_ALL can be used on most of these functions as a channel value.
+*/
+
+DLL_API signed char     F_API FSOUND_SetFrequency(int channel, int freq);
+DLL_API signed char     F_API FSOUND_SetVolume(int channel, int vol);
+DLL_API signed char     F_API FSOUND_SetVolumeAbsolute(int channel, int vol);
+DLL_API signed char     F_API FSOUND_SetPan(int channel, int pan);
+DLL_API signed char     F_API FSOUND_SetSurround(int channel, signed char surround);
+DLL_API signed char     F_API FSOUND_SetMute(int channel, signed char mute);
+DLL_API signed char     F_API FSOUND_SetPriority(int channel, int priority);
+DLL_API signed char     F_API FSOUND_SetReserved(int channel, signed char reserved);
+DLL_API signed char     F_API FSOUND_SetPaused(int channel, signed char paused);
+DLL_API signed char     F_API FSOUND_SetLoopMode(int channel, unsigned int loopmode);
+DLL_API signed char     F_API FSOUND_SetCurrentPosition(int channel, unsigned int offset);
+DLL_API signed char     F_API FSOUND_3D_SetAttributes(int channel, const float *pos, const float *vel);
+DLL_API signed char     F_API FSOUND_3D_SetMinMaxDistance(int channel, float min, float max);
+
+/* 
+    Channel information functions.
+*/
+
+DLL_API signed char     F_API FSOUND_IsPlaying(int channel);
+DLL_API int             F_API FSOUND_GetFrequency(int channel);
+DLL_API int             F_API FSOUND_GetVolume(int channel);
+DLL_API int             F_API FSOUND_GetAmplitude(int channel);
+DLL_API int             F_API FSOUND_GetPan(int channel);
+DLL_API signed char     F_API FSOUND_GetSurround(int channel);
+DLL_API signed char     F_API FSOUND_GetMute(int channel);
+DLL_API int             F_API FSOUND_GetPriority(int channel);
+DLL_API signed char     F_API FSOUND_GetReserved(int channel);
+DLL_API signed char     F_API FSOUND_GetPaused(int channel);
+DLL_API unsigned int    F_API FSOUND_GetLoopMode(int channel);
+DLL_API unsigned int    F_API FSOUND_GetCurrentPosition(int channel);
+DLL_API FSOUND_SAMPLE * F_API FSOUND_GetCurrentSample(int channel);
+DLL_API signed char     F_API FSOUND_GetCurrentLevels(int channel, float *l, float *r);
+DLL_API int             F_API FSOUND_GetNumSubChannels(int channel);
+DLL_API int             F_API FSOUND_GetSubChannel(int channel, int subchannel);
+DLL_API signed char     F_API FSOUND_3D_GetAttributes(int channel, float *pos, float *vel);
+DLL_API signed char     F_API FSOUND_3D_GetMinMaxDistance(int channel, float *min, float *max);
+
+/* ========================== */
+/* Global 3D sound functions. */
+/* ========================== */
+
+/*
+    See also 3d sample and channel based functions above.
+    Call FSOUND_Update once a frame to process 3d information.
+*/
+
+DLL_API void            F_API FSOUND_3D_Listener_SetAttributes(const float *pos, const float *vel, float fx, float fy, float fz, float tx, float ty, float tz);
+DLL_API void            F_API FSOUND_3D_Listener_GetAttributes(float *pos, float *vel, float *fx, float *fy, float *fz, float *tx, float *ty, float *tz);
+DLL_API void            F_API FSOUND_3D_Listener_SetCurrent(int current, int numlisteners);  /* use this if you use multiple listeners / splitscreen */
+DLL_API void            F_API FSOUND_3D_SetDopplerFactor(float scale);
+DLL_API void            F_API FSOUND_3D_SetDistanceFactor(float scale);
+DLL_API void            F_API FSOUND_3D_SetRolloffFactor(float scale);
+
+/* =================== */
+/* FX functions.       */
+/* =================== */
+
+/* 
+    Functions to control DX8 only effects processing.
+
+    - FX enabled samples can only be played once at a time, not multiple times at once.
+    - Sounds have to be created with FSOUND_HW2D or FSOUND_HW3D for this to work.
+    - FSOUND_INIT_ENABLESYSTEMCHANNELFX can be used to apply hardware effect processing to the
+      global mixed output of FMOD's software channels.
+    - FSOUND_FX_Enable returns an FX handle that you can use to alter fx parameters.
+    - FSOUND_FX_Enable can be called multiple times in a row, even on the same FX type,
+      it will return a unique handle for each FX.
+    - FSOUND_FX_Enable cannot be called if the sound is playing or locked.
+    - FSOUND_FX_Disable must be called to reset/clear the FX from a channel.
+*/
+
+DLL_API int             F_API FSOUND_FX_Enable(int channel, unsigned int fxtype);    /* See FSOUND_FX_MODES */
+DLL_API signed char     F_API FSOUND_FX_Disable(int channel);                        /* Disables all effects */
+
+DLL_API signed char     F_API FSOUND_FX_SetChorus(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase);
+DLL_API signed char     F_API FSOUND_FX_SetCompressor(int fxid, float Gain, float Attack, float Release, float Threshold, float Ratio, float Predelay);
+DLL_API signed char     F_API FSOUND_FX_SetDistortion(int fxid, float Gain, float Edge, float PostEQCenterFrequency, float PostEQBandwidth, float PreLowpassCutoff);
+DLL_API signed char     F_API FSOUND_FX_SetEcho(int fxid, float WetDryMix, float Feedback, float LeftDelay, float RightDelay, int PanDelay);
+DLL_API signed char     F_API FSOUND_FX_SetFlanger(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase);
+DLL_API signed char     F_API FSOUND_FX_SetGargle(int fxid, int RateHz, int WaveShape);
+DLL_API signed char     F_API FSOUND_FX_SetI3DL2Reverb(int fxid, int Room, int RoomHF, float RoomRolloffFactor, float DecayTime, float DecayHFRatio, int Reflections, float ReflectionsDelay, int Reverb, float ReverbDelay, float Diffusion, float Density, float HFReference);
+DLL_API signed char     F_API FSOUND_FX_SetParamEQ(int fxid, float Center, float Bandwidth, float Gain);
+DLL_API signed char     F_API FSOUND_FX_SetWavesReverb(int fxid, float InGain, float ReverbMix, float ReverbTime, float HighFreqRTRatio);  
+/* ========================= */
+/* File Streaming functions. */
+/* ========================= */
+
+/*
+    Note : Use FSOUND_LOADMEMORY   flag with FSOUND_Stream_Open to stream from memory.
+           Use FSOUND_LOADRAW      flag with FSOUND_Stream_Open to treat stream as raw pcm data.
+           Use FSOUND_MPEGACCURATE flag with FSOUND_Stream_Open to open mpegs in 'accurate mode' for settime/gettime/getlengthms.
+           Use FSOUND_FREE as the 'channel' variable, to let FMOD pick a free channel for you.
+*/
+
+DLL_API signed char        F_API FSOUND_Stream_SetBufferSize(int ms);      /* call this before opening streams, not after */
+                           
+DLL_API FSOUND_STREAM *    F_API FSOUND_Stream_Open(const char *name_or_data, unsigned int mode, int offset, int length);
+DLL_API FSOUND_STREAM *    F_API FSOUND_Stream_Create(FSOUND_STREAMCALLBACK callback, int length, unsigned int mode, int samplerate, void *userdata);
+DLL_API signed char        F_API FSOUND_Stream_Close(FSOUND_STREAM *stream);
+                           
+DLL_API int                F_API FSOUND_Stream_Play(int channel, FSOUND_STREAM *stream);
+DLL_API int                F_API FSOUND_Stream_PlayEx(int channel, FSOUND_STREAM *stream, FSOUND_DSPUNIT *dsp, signed char startpaused);
+DLL_API signed char        F_API FSOUND_Stream_Stop(FSOUND_STREAM *stream);
+                           
+DLL_API signed char        F_API FSOUND_Stream_SetPosition(FSOUND_STREAM *stream, unsigned int position);
+DLL_API unsigned int       F_API FSOUND_Stream_GetPosition(FSOUND_STREAM *stream);
+DLL_API signed char        F_API FSOUND_Stream_SetTime(FSOUND_STREAM *stream, int ms);
+DLL_API int                F_API FSOUND_Stream_GetTime(FSOUND_STREAM *stream);
+DLL_API int                F_API FSOUND_Stream_GetLength(FSOUND_STREAM *stream);
+DLL_API int                F_API FSOUND_Stream_GetLengthMs(FSOUND_STREAM *stream);
+                           
+DLL_API signed char        F_API FSOUND_Stream_SetMode(FSOUND_STREAM *stream, unsigned int mode);
+DLL_API unsigned int       F_API FSOUND_Stream_GetMode(FSOUND_STREAM *stream);
+DLL_API signed char        F_API FSOUND_Stream_SetLoopPoints(FSOUND_STREAM *stream, unsigned int loopstartpcm, unsigned int loopendpcm);
+DLL_API signed char        F_API FSOUND_Stream_SetLoopCount(FSOUND_STREAM *stream, int count);
+DLL_API int                F_API FSOUND_Stream_GetOpenState(FSOUND_STREAM *stream);                /* use with FSOUND_NONBLOCKING opened streams */
+DLL_API FSOUND_SAMPLE *    F_API FSOUND_Stream_GetSample(FSOUND_STREAM *stream);
+DLL_API FSOUND_DSPUNIT *   F_API FSOUND_Stream_CreateDSP(FSOUND_STREAM *stream, FSOUND_DSPCALLBACK callback, int priority, void *userdata);
+                           
+DLL_API signed char        F_API FSOUND_Stream_SetEndCallback(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, void *userdata);
+DLL_API signed char        F_API FSOUND_Stream_SetSyncCallback(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, void *userdata);
+
+DLL_API FSOUND_SYNCPOINT * F_API FSOUND_Stream_AddSyncPoint(FSOUND_STREAM *stream, unsigned int pcmoffset, const char *name);
+DLL_API signed char        F_API FSOUND_Stream_DeleteSyncPoint(FSOUND_SYNCPOINT *point);
+DLL_API int                F_API FSOUND_Stream_GetNumSyncPoints(FSOUND_STREAM *stream);
+DLL_API FSOUND_SYNCPOINT * F_API FSOUND_Stream_GetSyncPoint(FSOUND_STREAM *stream, int index);
+DLL_API char *             F_API FSOUND_Stream_GetSyncPointInfo(FSOUND_SYNCPOINT *point, unsigned int *pcmoffset);
+
+DLL_API signed char        F_API FSOUND_Stream_SetSubStream(FSOUND_STREAM *stream, int index);     /* For FMOD .FSB bank files. */
+DLL_API int                F_API FSOUND_Stream_GetNumSubStreams(FSOUND_STREAM *stream);            /* For FMOD .FSB bank files. */
+DLL_API signed char        F_API FSOUND_Stream_SetSubStreamSentence(FSOUND_STREAM *stream, const int *sentencelist, int numitems);
+
+DLL_API signed char        F_API FSOUND_Stream_GetNumTagFields(FSOUND_STREAM *stream, int *num);
+DLL_API signed char        F_API FSOUND_Stream_GetTagField(FSOUND_STREAM *stream, int num, int *type, char **name, void **value, int *length);
+DLL_API signed char        F_API FSOUND_Stream_FindTagField(FSOUND_STREAM *stream, int type, const char *name, void **value, int *length);
+
+/*
+    Internet streaming functions
+*/
+
+DLL_API signed char        F_API FSOUND_Stream_Net_SetProxy(const char *proxy);
+DLL_API char *             F_API FSOUND_Stream_Net_GetLastServerStatus();
+DLL_API signed char        F_API FSOUND_Stream_Net_SetBufferProperties(int buffersize, int prebuffer_percent, int rebuffer_percent);
+DLL_API signed char        F_API FSOUND_Stream_Net_GetBufferProperties(int *buffersize, int *prebuffer_percent, int *rebuffer_percent);
+DLL_API signed char        F_API FSOUND_Stream_Net_SetMetadataCallback(FSOUND_STREAM *stream, FSOUND_METADATACALLBACK callback, void *userdata);
+DLL_API signed char        F_API FSOUND_Stream_Net_GetStatus(FSOUND_STREAM *stream, int *status, int *bufferpercentused, int *bitrate, unsigned int *flags);
+
+/* =================== */
+/* CD audio functions. */
+/* =================== */
+
+/*
+    Note : 0 = default cdrom.  Otherwise specify the drive letter, for example. 'D'. 
+*/
+
+DLL_API signed char     F_API FSOUND_CD_Play(char drive, int track);
+DLL_API void            F_API FSOUND_CD_SetPlayMode(char drive, signed char mode);
+DLL_API signed char     F_API FSOUND_CD_Stop(char drive);
+DLL_API signed char     F_API FSOUND_CD_SetPaused(char drive, signed char paused);
+DLL_API signed char     F_API FSOUND_CD_SetVolume(char drive, int volume);
+DLL_API signed char     F_API FSOUND_CD_SetTrackTime(char drive, unsigned int ms);
+DLL_API signed char     F_API FSOUND_CD_OpenTray(char drive, signed char open);
+
+DLL_API signed char     F_API FSOUND_CD_GetPaused(char drive);
+DLL_API int             F_API FSOUND_CD_GetTrack(char drive);
+DLL_API int             F_API FSOUND_CD_GetNumTracks(char drive);
+DLL_API int             F_API FSOUND_CD_GetVolume(char drive);
+DLL_API int             F_API FSOUND_CD_GetTrackLength(char drive, int track); 
+DLL_API int             F_API FSOUND_CD_GetTrackTime(char drive);
+
+/* ============== */
+/* DSP functions. */
+/* ============== */
+
+/* 
+    DSP Unit control and information functions. 
+    These functions allow you access to the mixed stream that FMOD uses to play back sound on.
+*/
+
+DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_Create(FSOUND_DSPCALLBACK callback, int priority, void *userdata);
+DLL_API void            F_API FSOUND_DSP_Free(FSOUND_DSPUNIT *unit);
+DLL_API void            F_API FSOUND_DSP_SetPriority(FSOUND_DSPUNIT *unit, int priority);
+DLL_API int             F_API FSOUND_DSP_GetPriority(FSOUND_DSPUNIT *unit);
+DLL_API void            F_API FSOUND_DSP_SetActive(FSOUND_DSPUNIT *unit, signed char active);
+DLL_API signed char     F_API FSOUND_DSP_GetActive(FSOUND_DSPUNIT *unit);
+
+/* 
+    Functions to get hold of FSOUND 'system DSP unit' handles. 
+*/
+
+DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetClearUnit();
+DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetSFXUnit();
+DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetMusicUnit();
+DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetFFTUnit();
+DLL_API FSOUND_DSPUNIT *F_API FSOUND_DSP_GetClipAndCopyUnit();
+
+/* 
+    Miscellaneous DSP functions 
+    Note for the spectrum analysis function to work, you have to enable the FFT DSP unit with 
+    the following code FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE);
+    It is off by default to save cpu usage.
+*/
+
+DLL_API signed char     F_API FSOUND_DSP_MixBuffers(void *destbuffer, void *srcbuffer, int len, int freq, int vol, int pan, unsigned int mode);
+DLL_API void            F_API FSOUND_DSP_ClearMixBuffer();
+DLL_API int             F_API FSOUND_DSP_GetBufferLength();      /* Length of each DSP update */
+DLL_API int             F_API FSOUND_DSP_GetBufferLengthTotal(); /* Total buffer length due to FSOUND_SetBufferSize */
+DLL_API float *         F_API FSOUND_DSP_GetSpectrum();          /* Array of 512 floats - call FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE)) for this to work. */
+
+/* =================================================================================== */
+/* Reverb functions. (eax2/eax3 reverb)  (ONLY SUPPORTED ON WIN32 W/ FSOUND_HW3D FLAG) */
+/* =================================================================================== */
+
+/*
+    See top of file for definitions and information on the reverb parameters.
+*/
+
+DLL_API signed char     F_API FSOUND_Reverb_SetProperties(const FSOUND_REVERB_PROPERTIES *prop);
+DLL_API signed char     F_API FSOUND_Reverb_GetProperties(FSOUND_REVERB_PROPERTIES *prop);
+DLL_API signed char     F_API FSOUND_Reverb_SetChannelProperties(int channel, const FSOUND_REVERB_CHANNELPROPERTIES *prop);
+DLL_API signed char     F_API FSOUND_Reverb_GetChannelProperties(int channel, FSOUND_REVERB_CHANNELPROPERTIES *prop);
+
+/* ===================================================== */
+/* Recording functions  (ONLY SUPPORTED IN WIN32, WINCE) */
+/* ===================================================== */
+
+/*
+    Recording initialization functions
+*/
+
+DLL_API signed char     F_API FSOUND_Record_SetDriver(int outputtype);
+DLL_API int             F_API FSOUND_Record_GetNumDrivers();
+DLL_API const char *    F_API FSOUND_Record_GetDriverName(int id);
+DLL_API int             F_API FSOUND_Record_GetDriver();
+
+/*
+    Recording functionality.  Only one recording session will work at a time.
+*/
+
+DLL_API signed char     F_API FSOUND_Record_StartSample(FSOUND_SAMPLE *sptr, signed char loop);
+DLL_API signed char     F_API FSOUND_Record_Stop();
+DLL_API int             F_API FSOUND_Record_GetPosition();  
+
+/* ========================================================================================== */
+/* FMUSIC API (MOD,S3M,XM,IT,MIDI PLAYBACK)                                                   */
+/* ========================================================================================== */
+
+/* 
+    Song management / playback functions.
+*/
+
+DLL_API FMUSIC_MODULE * F_API FMUSIC_LoadSong(const char *name);
+DLL_API FMUSIC_MODULE * F_API FMUSIC_LoadSongEx(const char *name_or_data, int offset, int length, unsigned int mode, const int *samplelist, int samplelistnum);
+DLL_API int             F_API FMUSIC_GetOpenState(FMUSIC_MODULE *mod);
+DLL_API signed char     F_API FMUSIC_FreeSong(FMUSIC_MODULE *mod);
+DLL_API signed char     F_API FMUSIC_PlaySong(FMUSIC_MODULE *mod);
+DLL_API signed char     F_API FMUSIC_StopSong(FMUSIC_MODULE *mod);
+DLL_API void            F_API FMUSIC_StopAllSongs();
+
+DLL_API signed char     F_API FMUSIC_SetZxxCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback);
+DLL_API signed char     F_API FMUSIC_SetRowCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int rowstep);
+DLL_API signed char     F_API FMUSIC_SetOrderCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int orderstep);
+DLL_API signed char     F_API FMUSIC_SetInstCallback(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int instrument);
+
+DLL_API signed char     F_API FMUSIC_SetSample(FMUSIC_MODULE *mod, int sampno, FSOUND_SAMPLE *sptr);
+DLL_API signed char     F_API FMUSIC_SetUserData(FMUSIC_MODULE *mod, void *userdata);
+DLL_API signed char     F_API FMUSIC_OptimizeChannels(FMUSIC_MODULE *mod, int maxchannels, int minvolume);
+
+/*
+    Runtime song functions. 
+*/
+
+DLL_API signed char     F_API FMUSIC_SetReverb(signed char reverb);             /* MIDI only */
+DLL_API signed char     F_API FMUSIC_SetLooping(FMUSIC_MODULE *mod, signed char looping);
+DLL_API signed char     F_API FMUSIC_SetOrder(FMUSIC_MODULE *mod, int order);
+DLL_API signed char     F_API FMUSIC_SetPaused(FMUSIC_MODULE *mod, signed char pause);
+DLL_API signed char     F_API FMUSIC_SetMasterVolume(FMUSIC_MODULE *mod, int volume);
+DLL_API signed char     F_API FMUSIC_SetMasterSpeed(FMUSIC_MODULE *mode, float speed);
+DLL_API signed char     F_API FMUSIC_SetPanSeperation(FMUSIC_MODULE *mod, float pansep);
+/* 
+    Static song information functions.
+*/
+
+DLL_API const char *    F_API FMUSIC_GetName(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetType(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetNumOrders(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetNumPatterns(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetNumInstruments(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetNumSamples(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetNumChannels(FMUSIC_MODULE *mod);
+DLL_API FSOUND_SAMPLE * F_API FMUSIC_GetSample(FMUSIC_MODULE *mod, int sampno);
+DLL_API int             F_API FMUSIC_GetPatternLength(FMUSIC_MODULE *mod, int orderno);
+/* 
+    Runtime song information.
+*/
+
+DLL_API signed char     F_API FMUSIC_IsFinished(FMUSIC_MODULE *mod);
+DLL_API signed char     F_API FMUSIC_IsPlaying(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetMasterVolume(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetGlobalVolume(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetOrder(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetPattern(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetSpeed(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetBPM(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetRow(FMUSIC_MODULE *mod);
+DLL_API signed char     F_API FMUSIC_GetPaused(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetTime(FMUSIC_MODULE *mod);
+DLL_API int             F_API FMUSIC_GetRealChannel(FMUSIC_MODULE *mod, int modchannel);
+DLL_API void *          F_API FMUSIC_GetUserData(FMUSIC_MODULE *mod);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Source/fmoddyn.h b/Source/fmoddyn.h
new file mode 100644 (file)
index 0000000..44f1c8f
--- /dev/null
@@ -0,0 +1,543 @@
+/* =========================================================================================== */
+/* FMOD Dynamic DLL loading header. Copyright (c), Firelight Technologies Pty, Ltd. 1999-2004. */
+/* =========================================================================================== */
+
+#ifndef _FMODDYN_H_
+#define _FMODDYN_H_
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
+  #include <windows.h>
+#else
+  #include <dlfcn.h>
+  #include <string.h>
+#endif
+#include <stdlib.h>
+
+#include "fmod.h"
+
+typedef struct
+{
+    void *module;
+
+    signed char       (F_API *FSOUND_SetOutput)(int outputtype);
+    signed char       (F_API *FSOUND_SetDriver)(int driver);
+    signed char       (F_API *FSOUND_SetMixer)(int mixer);
+    signed char       (F_API *FSOUND_SetBufferSize)(int len_ms);
+    signed char       (F_API *FSOUND_SetHWND)(void *hwnd);
+    signed char       (F_API *FSOUND_SetMinHardwareChannels)(int min);
+    signed char       (F_API *FSOUND_SetMaxHardwareChannels)(int max);
+    signed char       (F_API *FSOUND_SetMemorySystem)(void *pool, int poollen, FSOUND_ALLOCCALLBACK useralloc, FSOUND_REALLOCCALLBACK userrealloc, FSOUND_FREECALLBACK userfree);
+    signed char       (F_API *FSOUND_Init)(int mixrate, int maxsoftwarechannels, unsigned int flags);
+    void              (F_API *FSOUND_Close)();
+    void              (F_API *FSOUND_Update)();   /* you must call this once a frame */
+    void              (F_API *FSOUND_SetSpeakerMode)(unsigned int speakermode);
+    void              (F_API *FSOUND_SetSFXMasterVolume)(int volume);
+    void              (F_API *FSOUND_SetPanSeperation)(float pansep);
+    void              (F_API *FSOUND_File_SetCallbacks)(FSOUND_OPENCALLBACK  useropen, FSOUND_CLOSECALLBACK userclose, FSOUND_READCALLBACK userread, FSOUND_SEEKCALLBACK  userseek, FSOUND_TELLCALLBACK  usertell);
+    int               (F_API *FSOUND_GetError)();
+    float             (F_API *FSOUND_GetVersion)();
+    int               (F_API *FSOUND_GetOutput)();
+    void *            (F_API *FSOUND_GetOutputHandle)();
+    int               (F_API *FSOUND_GetDriver)();
+    int               (F_API *FSOUND_GetMixer)();
+    int               (F_API *FSOUND_GetNumDrivers)();
+    signed char *     (F_API *FSOUND_GetDriverName)(int id);
+    signed char       (F_API *FSOUND_GetDriverCaps)(int id, unsigned int *caps);
+    int               (F_API *FSOUND_GetOutputRate)();
+    int               (F_API *FSOUND_GetMaxChannels)();
+    int               (F_API *FSOUND_GetMaxSamples)();
+    int               (F_API *FSOUND_GetSFXMasterVolume)();
+    signed char       (F_API *FSOUND_GetNumHWChannels)(int *num2d, int *num3d, int *total);
+    int               (F_API *FSOUND_GetChannelsPlaying)();
+    float             (F_API *FSOUND_GetCPUUsage)();
+    void              (F_API *FSOUND_GetMemoryStats)(unsigned int *currentalloced, unsigned int *maxalloced);
+    FSOUND_SAMPLE *   (F_API *FSOUND_Sample_Load)(int index, const char *name_or_data, unsigned int mode, int offset, int length);
+    FSOUND_SAMPLE *   (F_API *FSOUND_Sample_Alloc)(int index, int length, unsigned int mode, int deffreq, int defvol, int defpan, int defpri);
+    void              (F_API *FSOUND_Sample_Free)(FSOUND_SAMPLE *sptr);
+    signed char       (F_API *FSOUND_Sample_Upload)(FSOUND_SAMPLE *sptr, void *srcdata, unsigned int mode);
+    signed char       (F_API *FSOUND_Sample_Lock)(FSOUND_SAMPLE *sptr, int offset, int length, void **ptr1, void **ptr2, unsigned int *len1, unsigned int *len2);
+    signed char       (F_API *FSOUND_Sample_Unlock)(FSOUND_SAMPLE *sptr, void *ptr1, void *ptr2, unsigned int len1, unsigned int len2);
+    signed char       (F_API *FSOUND_Sample_SetMode)(FSOUND_SAMPLE *sptr, unsigned int mode);
+    signed char       (F_API *FSOUND_Sample_SetLoopPoints)(FSOUND_SAMPLE *sptr, int loopstart, int loopend);
+    signed char       (F_API *FSOUND_Sample_SetDefaults)(FSOUND_SAMPLE *sptr, int deffreq, int defvol, int defpan, int defpri);
+    signed char       (F_API *FSOUND_Sample_SetDefaultsEx)(FSOUND_SAMPLE *sptr, int deffreq, int defvol, int defpan, int defpri, int varfreq, int varvol, int varpan);
+    signed char       (F_API *FSOUND_Sample_SetMinMaxDistance)(FSOUND_SAMPLE *sptr, float min, float max);
+    signed char       (F_API *FSOUND_Sample_SetMaxPlaybacks)(FSOUND_SAMPLE *sptr, int max);
+    FSOUND_SAMPLE *   (F_API *FSOUND_Sample_Get)(int sampno);
+    char *            (F_API *FSOUND_Sample_GetName)(FSOUND_SAMPLE *sptr);
+    unsigned int      (F_API *FSOUND_Sample_GetLength)(FSOUND_SAMPLE *sptr);
+    signed char       (F_API *FSOUND_Sample_GetLoopPoints)(FSOUND_SAMPLE *sptr, int *loopstart, int *loopend);
+    signed char       (F_API *FSOUND_Sample_GetDefaults)(FSOUND_SAMPLE *sptr, int *deffreq, int *defvol, int *defpan, int *defpri);
+    signed char       (F_API *FSOUND_Sample_GetDefaultsEx)(FSOUND_SAMPLE *sptr, int *deffreq, int *defvol, int *defpan, int *defpri, int *varfreq, int *varvol, int *varpan);
+    unsigned int      (F_API *FSOUND_Sample_GetMode)(FSOUND_SAMPLE *sptr);
+    signed char       (F_API *FSOUND_Sample_GetMinMaxDistance)(FSOUND_SAMPLE *sptr, float *min, float *max);
+    int               (F_API *FSOUND_PlaySound)(int channel, FSOUND_SAMPLE *sptr);
+    int               (F_API *FSOUND_PlaySoundEx)(int channel, FSOUND_SAMPLE *sptr, FSOUND_DSPUNIT *dsp, signed char startpaused);
+    signed char       (F_API *FSOUND_StopSound)(int channel);
+    signed char       (F_API *FSOUND_SetFrequency)(int channel, int freq);
+    signed char       (F_API *FSOUND_SetVolume)(int channel, int vol);
+    signed char       (F_API *FSOUND_SetVolumeAbsolute)(int channel, int vol);
+    signed char       (F_API *FSOUND_SetPan)(int channel, int pan);
+    signed char       (F_API *FSOUND_SetSurround)(int channel, signed char surround);
+    signed char       (F_API *FSOUND_SetMute)(int channel, signed char mute);
+    signed char       (F_API *FSOUND_SetPriority)(int channel, int priority);
+    signed char       (F_API *FSOUND_SetReserved)(int channel, signed char reserved);
+    signed char       (F_API *FSOUND_SetPaused)(int channel, signed char paused);
+    signed char       (F_API *FSOUND_SetLoopMode)(int channel, unsigned int loopmode);
+    signed char       (F_API *FSOUND_SetCurrentPosition)(int channel, unsigned int offset);
+    signed char       (F_API *FSOUND_3D_SetAttributes)(int channel, float *pos, float *vel);
+    signed char       (F_API *FSOUND_3D_SetMinMaxDistance)(int channel, float min, float max);
+    signed char       (F_API *FSOUND_IsPlaying)(int channel);
+    int               (F_API *FSOUND_GetFrequency)(int channel);
+    int               (F_API *FSOUND_GetVolume)(int channel);
+    int               (F_API *FSOUND_GetAmplitude)(int channel);
+    int               (F_API *FSOUND_GetPan)(int channel);
+    signed char       (F_API *FSOUND_GetSurround)(int channel);
+    signed char       (F_API *FSOUND_GetMute)(int channel);
+    int               (F_API *FSOUND_GetPriority)(int channel);
+    signed char       (F_API *FSOUND_GetReserved)(int channel);
+    signed char       (F_API *FSOUND_GetPaused)(int channel);
+    unsigned int      (F_API *FSOUND_GetLoopMode)(int channel);
+    unsigned int      (F_API *FSOUND_GetCurrentPosition)(int channel);
+    FSOUND_SAMPLE *   (F_API *FSOUND_GetCurrentSample)(int channel);
+    signed char       (F_API *FSOUND_GetCurrentLevels)(int channel, float *l, float *r);
+    int               (F_API *FSOUND_GetNumSubChannels)(int channel);
+    int               (F_API *FSOUND_GetSubChannel)(int channel, int subchannel);
+    signed char       (F_API *FSOUND_3D_GetAttributes)(int channel, float *pos, float *vel);
+    signed char       (F_API *FSOUND_3D_GetMinMaxDistance)(int channel, float *min, float *max);
+    void              (F_API *FSOUND_3D_SetDopplerFactor)(float scale);
+    void              (F_API *FSOUND_3D_SetDistanceFactor)(float scale);
+    void              (F_API *FSOUND_3D_SetRolloffFactor)(float scale);
+    void              (F_API *FSOUND_3D_Listener_SetCurrent)(int current, int numlisteners);  /* use this if you use multiple listeners / splitscreen */
+    void              (F_API *FSOUND_3D_Listener_SetAttributes)(float *pos, float *vel, float fx, float fy, float fz, float tx, float ty, float tz);
+    void              (F_API *FSOUND_3D_Listener_GetAttributes)(float *pos, float *vel, float *fx, float *fy, float *fz, float *tx, float *ty, float *tz);
+    int               (F_API *FSOUND_FX_Enable)(int channel, unsigned int fx);    /* See FSOUND_FX_MODES */
+    signed char       (F_API *FSOUND_FX_Disable)(int channel);
+    signed char       (F_API *FSOUND_FX_SetChorus)(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase);
+    signed char       (F_API *FSOUND_FX_SetCompressor)(int fxid, float Gain, float Attack, float Release, float Threshold, float Ratio, float Predelay);
+    signed char       (F_API *FSOUND_FX_SetDistortion)(int fxid, float Gain, float Edge, float PostEQCenterFrequency, float PostEQBandwidth, float PreLowpassCutoff);
+    signed char       (F_API *FSOUND_FX_SetEcho)(int fxid, float WetDryMix, float Feedback, float LeftDelay, float RightDelay, int PanDelay);
+    signed char       (F_API *FSOUND_FX_SetFlanger)(int fxid, float WetDryMix, float Depth, float Feedback, float Frequency, int Waveform, float Delay, int Phase);
+    signed char       (F_API *FSOUND_FX_SetGargle)(int fxid, int RateHz, int WaveShape);
+    signed char       (F_API *FSOUND_FX_SetI3DL2Reverb)(int fxid, int Room, int RoomHF, float RoomRolloffFactor, float DecayTime, float DecayHFRatio, int Reflections, float ReflectionsDelay, int Reverb, float ReverbDelay, float Diffusion, float Density, float HFReference);
+    signed char       (F_API *FSOUND_FX_SetParamEQ)(int fxid, float Center, float Bandwidth, float Gain);
+    signed char       (F_API *FSOUND_FX_SetWavesReverb)(int fxid, float InGain, float ReverbMix, float ReverbTime, float HighFreqRTRatio);  
+    signed char       (F_API *FSOUND_Stream_SetBufferSize)(int ms);      /* call this before opening streams, not after */
+    FSOUND_STREAM *   (F_API *FSOUND_Stream_Open)(const char *name_or_data, unsigned int mode, int offset, int length);
+    FSOUND_STREAM *   (F_API *FSOUND_Stream_Create)(FSOUND_STREAMCALLBACK callback, int length, unsigned int mode, int samplerate, void *userdata);
+    signed char       (F_API *FSOUND_Stream_Close)(FSOUND_STREAM *stream);
+    int               (F_API *FSOUND_Stream_Play)(int channel, FSOUND_STREAM *stream);
+    int               (F_API *FSOUND_Stream_PlayEx)(int channel, FSOUND_STREAM *stream, FSOUND_DSPUNIT *dsp, signed char startpaused);
+    signed char       (F_API *FSOUND_Stream_Stop)(FSOUND_STREAM *stream);
+    signed char       (F_API *FSOUND_Stream_SetPosition)(FSOUND_STREAM *stream, unsigned int position);
+    unsigned int      (F_API *FSOUND_Stream_GetPosition)(FSOUND_STREAM *stream);
+    signed char       (F_API *FSOUND_Stream_SetTime)(FSOUND_STREAM *stream, int ms);
+    int               (F_API *FSOUND_Stream_GetTime)(FSOUND_STREAM *stream);
+    int               (F_API *FSOUND_Stream_GetLength)(FSOUND_STREAM *stream);
+    int               (F_API *FSOUND_Stream_GetLengthMs)(FSOUND_STREAM *stream);
+    signed char       (F_API *FSOUND_Stream_SetMode)(FSOUND_STREAM *stream, unsigned int mode);
+    unsigned int      (F_API *FSOUND_Stream_GetMode)(FSOUND_STREAM *stream);
+    signed char       (F_API *FSOUND_Stream_SetLoopPoints)(FSOUND_STREAM *stream, unsigned int loopstartpcm, unsigned int loopendpcm);
+    signed char       (F_API *FSOUND_Stream_SetLoopCount)(FSOUND_STREAM *stream, int count);
+    int               (F_API *FSOUND_Stream_GetOpenState)(FSOUND_STREAM *stream);
+    FSOUND_SAMPLE *   (F_API *FSOUND_Stream_GetSample)(FSOUND_STREAM *stream);   /* every stream contains a sample to playback on */
+    FSOUND_DSPUNIT *  (F_API *FSOUND_Stream_CreateDSP)(FSOUND_STREAM *stream, FSOUND_DSPCALLBACK callback, int priority, void *userdata);
+    signed char       (F_API *FSOUND_Stream_SetEndCallback)(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, void *userdata);
+    signed char       (F_API *FSOUND_Stream_SetSyncCallback)(FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, void *userdata);
+    FSOUND_SYNCPOINT *(F_API *FSOUND_Stream_AddSyncPoint)(FSOUND_STREAM *stream, unsigned int pcmoffset, void *userdata);
+    signed char       (F_API *FSOUND_Stream_DeleteSyncPoint)(FSOUND_SYNCPOINT *point);
+    int               (F_API *FSOUND_Stream_GetNumSyncPoints)(FSOUND_STREAM *stream);
+    FSOUND_SYNCPOINT *(F_API *FSOUND_Stream_GetSyncPoint)(FSOUND_STREAM *stream, int index);
+    char *            (F_API *FSOUND_Stream_GetSyncPointInfo)(FSOUND_SYNCPOINT *point, unsigned int *pcmoffset);
+    signed char       (F_API *FSOUND_Stream_SetSubStream)(FSOUND_STREAM *stream, int index);
+    int               (F_API *FSOUND_Stream_GetNumSubStreams)(FSOUND_STREAM *stream);
+    signed char       (F_API *FSOUND_Stream_SetSubStreamSentence)(FSOUND_STREAM *stream, int *sentencelist, int numitems);
+    signed char       (F_API *FSOUND_Stream_GetNumTagFields)(FSOUND_STREAM *stream, int *num);
+    signed char       (F_API *FSOUND_Stream_GetTagField)(FSOUND_STREAM *stream, int num, int *type, char **name, void **value, int *length);
+    signed char       (F_API *FSOUND_Stream_FindTagField)(FSOUND_STREAM *stream, int type, const char *name, void **value, int *length);
+    signed char       (F_API *FSOUND_Stream_Net_SetProxy)(const char *proxy);
+    char *            (F_API *FSOUND_Stream_Net_GetLastServerStatus)();
+    signed char       (F_API *FSOUND_Stream_Net_SetBufferProperties)(int buffersize, int prebuffer_percent, int rebuffer_percent);
+    signed char       (F_API *FSOUND_Stream_Net_GetBufferProperties)(int *buffersize, int *prebuffer_percent, int *rebuffer_percent);
+    signed char       (F_API *FSOUND_Stream_Net_SetMetadataCallback)(FSOUND_STREAM *stream, FSOUND_METADATACALLBACK callback, void *userdata);
+    signed char       (F_API *FSOUND_Stream_Net_GetStatus)(FSOUND_STREAM *stream, int *status, int *bufferpercentused, int *bitrate, unsigned int *flags);
+    signed char       (F_API *FSOUND_CD_Play)(char drive, int track);
+    void              (F_API *FSOUND_CD_SetPlayMode)(char drive, signed char mode);
+    signed char       (F_API *FSOUND_CD_Stop)(char drive);
+    signed char       (F_API *FSOUND_CD_SetPaused)(char drive, signed char paused);
+    signed char       (F_API *FSOUND_CD_SetVolume)(char drive, int volume);
+    signed char       (F_API *FSOUND_CD_SetTrackTime)(char drive, unsigned int ms);
+    signed char       (F_API *FSOUND_CD_OpenTray)(char drive, signed char open);
+    signed char       (F_API *FSOUND_CD_GetPaused)(char drive);
+    int               (F_API *FSOUND_CD_GetTrack)(char drive);
+    int               (F_API *FSOUND_CD_GetNumTracks)(char drive);
+    int               (F_API *FSOUND_CD_GetVolume)(char drive);
+    int               (F_API *FSOUND_CD_GetTrackLength)(char drive, int track); 
+    int               (F_API *FSOUND_CD_GetTrackTime)(char drive);
+    FSOUND_DSPUNIT *  (F_API *FSOUND_DSP_Create)(FSOUND_DSPCALLBACK callback, int priority, void *userdata);
+    void              (F_API *FSOUND_DSP_Free)(FSOUND_DSPUNIT *unit);
+    void              (F_API *FSOUND_DSP_SetPriority)(FSOUND_DSPUNIT *unit, int priority);
+    int               (F_API *FSOUND_DSP_GetPriority)(FSOUND_DSPUNIT *unit);
+    void              (F_API *FSOUND_DSP_SetActive)(FSOUND_DSPUNIT *unit, signed char active);
+    signed char       (F_API *FSOUND_DSP_GetActive)(FSOUND_DSPUNIT *unit);
+    FSOUND_DSPUNIT *  (F_API *FSOUND_DSP_GetClearUnit)();
+    FSOUND_DSPUNIT *  (F_API *FSOUND_DSP_GetSFXUnit)();
+    FSOUND_DSPUNIT *  (F_API *FSOUND_DSP_GetMusicUnit)();
+    FSOUND_DSPUNIT *  (F_API *FSOUND_DSP_GetFFTUnit)();
+    FSOUND_DSPUNIT *  (F_API *FSOUND_DSP_GetClipAndCopyUnit)();
+    signed char       (F_API *FSOUND_DSP_MixBuffers)(void *destbuffer, void *srcbuffer, int len, int freq, int vol, int pan, unsigned int mode);
+    void              (F_API *FSOUND_DSP_ClearMixBuffer)();
+    int               (F_API *FSOUND_DSP_GetBufferLength)();      /* Length of each DSP update */
+    int               (F_API *FSOUND_DSP_GetBufferLengthTotal)(); /* Total buffer length due to FSOUND_SetBufferSize */
+    float *           (F_API *FSOUND_DSP_GetSpectrum)();          /* Array of 512 floats - call FSOUND_DSP_SetActive(FSOUND_DSP_GetFFTUnit(), TRUE)) for this to work. */
+    signed char       (F_API *FSOUND_Reverb_SetProperties)(FSOUND_REVERB_PROPERTIES *prop);
+    signed char       (F_API *FSOUND_Reverb_GetProperties)(FSOUND_REVERB_PROPERTIES *prop);
+    signed char       (F_API *FSOUND_Reverb_SetChannelProperties)(int channel, FSOUND_REVERB_CHANNELPROPERTIES *prop);
+    signed char       (F_API *FSOUND_Reverb_GetChannelProperties)(int channel, FSOUND_REVERB_CHANNELPROPERTIES *prop);
+    signed char       (F_API *FSOUND_Record_SetDriver)(int outputtype);
+    int               (F_API *FSOUND_Record_GetNumDrivers)();
+    signed char *     (F_API *FSOUND_Record_GetDriverName)(int id);
+    int               (F_API *FSOUND_Record_GetDriver)();
+    signed char       (F_API *FSOUND_Record_StartSample)(FSOUND_SAMPLE *sptr, signed char loop);
+    signed char       (F_API *FSOUND_Record_Stop)();
+    int               (F_API *FSOUND_Record_GetPosition)();  
+    FMUSIC_MODULE *   (F_API *FMUSIC_LoadSong)(const char *name);
+    FMUSIC_MODULE *   (F_API *FMUSIC_LoadSongEx)(const char *name_or_data, int offset, int length, unsigned int mode, int *samplelist, int samplelistnum);
+    int               (F_API *FMUSIC_GetOpenState)(FMUSIC_MODULE *mod);
+    signed char       (F_API *FMUSIC_FreeSong)(FMUSIC_MODULE *mod);
+    signed char       (F_API *FMUSIC_PlaySong)(FMUSIC_MODULE *mod);
+    signed char       (F_API *FMUSIC_StopSong)(FMUSIC_MODULE *mod);
+    void              (F_API *FMUSIC_StopAllSongs)();
+    signed char       (F_API *FMUSIC_SetZxxCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback);
+    signed char       (F_API *FMUSIC_SetRowCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int rowstep);
+    signed char       (F_API *FMUSIC_SetOrderCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int orderstep);
+    signed char       (F_API *FMUSIC_SetInstCallback)(FMUSIC_MODULE *mod, FMUSIC_CALLBACK callback, int instrument);
+    signed char       (F_API *FMUSIC_SetSample)(FMUSIC_MODULE *mod, int sampno, FSOUND_SAMPLE *sptr);
+    signed char       (F_API *FMUSIC_SetUserData)(FMUSIC_MODULE *mod, void *userdata);
+    signed char       (F_API *FMUSIC_OptimizeChannels)(FMUSIC_MODULE *mod, int maxchannels, int minvolume);
+    signed char       (F_API *FMUSIC_SetReverb)(signed char reverb);             /* MIDI only */
+    signed char       (F_API *FMUSIC_SetLooping)(FMUSIC_MODULE *mod, signed char looping);
+    signed char       (F_API *FMUSIC_SetOrder)(FMUSIC_MODULE *mod, int order);
+    signed char       (F_API *FMUSIC_SetPaused)(FMUSIC_MODULE *mod, signed char pause);
+    signed char       (F_API *FMUSIC_SetMasterVolume)(FMUSIC_MODULE *mod, int volume);
+    signed char       (F_API *FMUSIC_SetMasterSpeed)(FMUSIC_MODULE *mode, float speed);
+    signed char       (F_API *FMUSIC_SetPanSeperation)(FMUSIC_MODULE *mod, float pansep);
+    char *            (F_API *FMUSIC_GetName)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetType)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetNumOrders)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetNumPatterns)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetNumInstruments)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetNumSamples)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetNumChannels)(FMUSIC_MODULE *mod);
+    FSOUND_SAMPLE *   (F_API *FMUSIC_GetSample)(FMUSIC_MODULE *mod, int sampno);
+    int               (F_API *FMUSIC_GetPatternLength)(FMUSIC_MODULE *mod, int orderno);
+    signed char       (F_API *FMUSIC_IsFinished)(FMUSIC_MODULE *mod);
+    signed char       (F_API *FMUSIC_IsPlaying)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetMasterVolume)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetGlobalVolume)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetOrder)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetPattern)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetSpeed)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetBPM)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetRow)(FMUSIC_MODULE *mod);
+    signed char       (F_API *FMUSIC_GetPaused)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetTime)(FMUSIC_MODULE *mod);
+    int               (F_API *FMUSIC_GetRealChannel)(FMUSIC_MODULE *mod, int modchannel);
+    unsigned int      (F_API *FMUSIC_GetUserData)(FMUSIC_MODULE *mod);
+} FMOD_INSTANCE;
+
+
+static FMOD_INSTANCE *FMOD_CreateInstance(char *dllName)
+{
+    FMOD_INSTANCE *instance;
+
+    instance = (FMOD_INSTANCE *)calloc(sizeof(FMOD_INSTANCE), 1);
+    if (!instance)
+    {
+        return NULL;
+    }
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
+    instance->module = LoadLibrary(dllName);
+#else
+    instance->module = dlopen(dllName, RTLD_LAZY);
+#endif
+    if (!instance->module)
+    {
+        free(instance);
+        return NULL;
+    }
+
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
+    #define F_GETPROC(_x, _y)                                                                       \
+    {                                                                                             \
+        *((unsigned int *)&instance->_x) = (unsigned int)GetProcAddress((HMODULE)instance->module, _y);    \
+        if (!instance->_x)                                                                        \
+        {                                                                                         \
+            FreeLibrary((HMODULE)instance->module);                                                        \
+            free(instance);                                                                       \
+            return NULL;                                                                          \
+        }                                                                                         \
+    }
+#else
+    #define F_GETPROC(_x, _y)                                                                       \
+    {                                                                                             \
+        char tmp[] = _y;                                                                          \
+        *(strchr(tmp, '@')) = 0;                                                                  \
+        *((unsigned int *)&instance->_x) = (unsigned int)dlsym(instance->module, &tmp[1]);        \
+        if (!instance->_x)                                                                        \
+        {                                                                                         \
+            dlclose(instance->module);                                                            \
+            free(instance);                                                                       \
+            return NULL;                                                                          \
+        }                                                                                         \
+    }
+#endif
+
+    F_GETPROC(FSOUND_SetOutput, "_FSOUND_SetOutput@4");
+    F_GETPROC(FSOUND_SetDriver, "_FSOUND_SetDriver@4");
+    F_GETPROC(FSOUND_SetMixer, "_FSOUND_SetMixer@4");
+    F_GETPROC(FSOUND_SetBufferSize, "_FSOUND_SetBufferSize@4");
+    F_GETPROC(FSOUND_SetHWND, "_FSOUND_SetHWND@4");
+    F_GETPROC(FSOUND_SetMinHardwareChannels, "_FSOUND_SetMinHardwareChannels@4");
+    F_GETPROC(FSOUND_SetMaxHardwareChannels, "_FSOUND_SetMaxHardwareChannels@4");
+    F_GETPROC(FSOUND_SetMemorySystem, "_FSOUND_SetMemorySystem@20");
+    F_GETPROC(FSOUND_Init, "_FSOUND_Init@12");
+    F_GETPROC(FSOUND_Close, "_FSOUND_Close@0");
+    F_GETPROC(FSOUND_Update, "_FSOUND_Update@0");
+    F_GETPROC(FSOUND_SetSFXMasterVolume, "_FSOUND_SetSFXMasterVolume@4");
+    F_GETPROC(FSOUND_SetPanSeperation, "_FSOUND_SetPanSeperation@4");
+    F_GETPROC(FSOUND_SetSpeakerMode, "_FSOUND_SetSpeakerMode@4");
+    F_GETPROC(FSOUND_GetError, "_FSOUND_GetError@0");
+    F_GETPROC(FSOUND_GetVersion, "_FSOUND_GetVersion@0");
+    F_GETPROC(FSOUND_GetOutput, "_FSOUND_GetOutput@0");
+    F_GETPROC(FSOUND_GetOutputHandle, "_FSOUND_GetOutputHandle@0");
+    F_GETPROC(FSOUND_GetDriver, "_FSOUND_GetDriver@0");
+    F_GETPROC(FSOUND_GetMixer, "_FSOUND_GetMixer@0");
+    F_GETPROC(FSOUND_GetNumDrivers, "_FSOUND_GetNumDrivers@0");
+    F_GETPROC(FSOUND_GetDriverName, "_FSOUND_GetDriverName@4");
+    F_GETPROC(FSOUND_GetDriverCaps, "_FSOUND_GetDriverCaps@8");
+    F_GETPROC(FSOUND_GetOutputRate, "_FSOUND_GetOutputRate@0");
+    F_GETPROC(FSOUND_GetMaxChannels, "_FSOUND_GetMaxChannels@0");
+    F_GETPROC(FSOUND_GetMaxSamples, "_FSOUND_GetMaxSamples@0");
+    F_GETPROC(FSOUND_GetSFXMasterVolume, "_FSOUND_GetSFXMasterVolume@0");
+    F_GETPROC(FSOUND_GetNumHWChannels, "_FSOUND_GetNumHWChannels@12");
+    F_GETPROC(FSOUND_GetChannelsPlaying, "_FSOUND_GetChannelsPlaying@0");
+    F_GETPROC(FSOUND_GetCPUUsage, "_FSOUND_GetCPUUsage@0");
+    F_GETPROC(FSOUND_GetMemoryStats, "_FSOUND_GetMemoryStats@8");
+    F_GETPROC(FSOUND_Sample_Load, "_FSOUND_Sample_Load@20");
+    F_GETPROC(FSOUND_Sample_Alloc, "_FSOUND_Sample_Alloc@28");
+    F_GETPROC(FSOUND_Sample_Free, "_FSOUND_Sample_Free@4");
+    F_GETPROC(FSOUND_Sample_Upload, "_FSOUND_Sample_Upload@12");
+    F_GETPROC(FSOUND_Sample_Lock, "_FSOUND_Sample_Lock@28");
+    F_GETPROC(FSOUND_Sample_Unlock, "_FSOUND_Sample_Unlock@20");
+    F_GETPROC(FSOUND_Sample_SetMode, "_FSOUND_Sample_SetMode@8");
+    F_GETPROC(FSOUND_Sample_SetLoopPoints, "_FSOUND_Sample_SetLoopPoints@12");
+    F_GETPROC(FSOUND_Sample_SetDefaults, "_FSOUND_Sample_SetDefaults@20");
+    F_GETPROC(FSOUND_Sample_SetDefaultsEx, "_FSOUND_Sample_SetDefaultsEx@32");
+    F_GETPROC(FSOUND_Sample_SetMinMaxDistance, "_FSOUND_Sample_SetMinMaxDistance@12");
+    F_GETPROC(FSOUND_Sample_SetMaxPlaybacks, "_FSOUND_Sample_SetMaxPlaybacks@8");
+    F_GETPROC(FSOUND_Sample_Get, "_FSOUND_Sample_Get@4");
+    F_GETPROC(FSOUND_Sample_GetName, "_FSOUND_Sample_GetName@4");
+    F_GETPROC(FSOUND_Sample_GetLength, "_FSOUND_Sample_GetLength@4");
+    F_GETPROC(FSOUND_Sample_GetLoopPoints, "_FSOUND_Sample_GetLoopPoints@12");
+    F_GETPROC(FSOUND_Sample_GetDefaults, "_FSOUND_Sample_GetDefaults@20");
+    F_GETPROC(FSOUND_Sample_GetDefaultsEx, "_FSOUND_Sample_GetDefaultsEx@32");
+    F_GETPROC(FSOUND_Sample_GetMode, "_FSOUND_Sample_GetMode@4");
+    F_GETPROC(FSOUND_Sample_GetMinMaxDistance, "_FSOUND_Sample_GetMinMaxDistance@12");
+    F_GETPROC(FSOUND_PlaySound, "_FSOUND_PlaySound@8");
+    F_GETPROC(FSOUND_PlaySoundEx, "_FSOUND_PlaySoundEx@16");
+    F_GETPROC(FSOUND_StopSound, "_FSOUND_StopSound@4");
+    F_GETPROC(FSOUND_SetFrequency, "_FSOUND_SetFrequency@8");
+    F_GETPROC(FSOUND_SetVolume, "_FSOUND_SetVolume@8");
+    F_GETPROC(FSOUND_SetVolumeAbsolute, "_FSOUND_SetVolumeAbsolute@8");
+    F_GETPROC(FSOUND_SetPan, "_FSOUND_SetPan@8");
+    F_GETPROC(FSOUND_SetSurround, "_FSOUND_SetSurround@8");
+    F_GETPROC(FSOUND_SetMute, "_FSOUND_SetMute@8");
+    F_GETPROC(FSOUND_SetPriority, "_FSOUND_SetPriority@8");
+    F_GETPROC(FSOUND_SetReserved, "_FSOUND_SetReserved@8");
+    F_GETPROC(FSOUND_SetPaused, "_FSOUND_SetPaused@8");
+    F_GETPROC(FSOUND_SetLoopMode, "_FSOUND_SetLoopMode@8");
+    F_GETPROC(FSOUND_SetCurrentPosition, "_FSOUND_SetCurrentPosition@8");
+    F_GETPROC(FSOUND_3D_SetAttributes, "_FSOUND_3D_SetAttributes@12");
+    F_GETPROC(FSOUND_3D_SetMinMaxDistance, "_FSOUND_3D_SetMinMaxDistance@12");
+    F_GETPROC(FSOUND_IsPlaying, "_FSOUND_IsPlaying@4");
+    F_GETPROC(FSOUND_GetFrequency, "_FSOUND_GetFrequency@4");
+    F_GETPROC(FSOUND_GetVolume, "_FSOUND_GetVolume@4");
+    F_GETPROC(FSOUND_GetAmplitude, "_FSOUND_GetAmplitude@4");
+    F_GETPROC(FSOUND_GetPan, "_FSOUND_GetPan@4");
+    F_GETPROC(FSOUND_GetSurround, "_FSOUND_GetSurround@4");
+    F_GETPROC(FSOUND_GetMute, "_FSOUND_GetMute@4");
+    F_GETPROC(FSOUND_GetPriority, "_FSOUND_GetPriority@4");
+    F_GETPROC(FSOUND_GetReserved, "_FSOUND_GetReserved@4");
+    F_GETPROC(FSOUND_GetPaused, "_FSOUND_GetPaused@4");
+    F_GETPROC(FSOUND_GetLoopMode, "_FSOUND_GetLoopMode@4");
+    F_GETPROC(FSOUND_GetCurrentPosition, "_FSOUND_GetCurrentPosition@4");
+    F_GETPROC(FSOUND_GetCurrentSample, "_FSOUND_GetCurrentSample@4");
+    F_GETPROC(FSOUND_GetCurrentLevels, "_FSOUND_GetCurrentLevels@12");
+    F_GETPROC(FSOUND_GetNumSubChannels, "_FSOUND_GetNumSubChannels@4");
+    F_GETPROC(FSOUND_GetSubChannel, "_FSOUND_GetSubChannel@8");
+    F_GETPROC(FSOUND_3D_GetAttributes, "_FSOUND_3D_GetAttributes@12");
+    F_GETPROC(FSOUND_3D_GetMinMaxDistance, "_FSOUND_3D_GetMinMaxDistance@12");
+    F_GETPROC(FSOUND_3D_Listener_SetCurrent, "_FSOUND_3D_Listener_SetCurrent@8");
+    F_GETPROC(FSOUND_3D_Listener_SetAttributes, "_FSOUND_3D_Listener_SetAttributes@32");
+    F_GETPROC(FSOUND_3D_Listener_GetAttributes, "_FSOUND_3D_Listener_GetAttributes@32");
+    F_GETPROC(FSOUND_3D_SetDopplerFactor, "_FSOUND_3D_SetDopplerFactor@4");
+    F_GETPROC(FSOUND_3D_SetDistanceFactor, "_FSOUND_3D_SetDistanceFactor@4");
+    F_GETPROC(FSOUND_3D_SetRolloffFactor, "_FSOUND_3D_SetRolloffFactor@4");
+    F_GETPROC(FSOUND_FX_Enable, "_FSOUND_FX_Enable@8");
+    F_GETPROC(FSOUND_FX_Disable, "_FSOUND_FX_Disable@4");
+    F_GETPROC(FSOUND_FX_SetChorus, "_FSOUND_FX_SetChorus@32");
+    F_GETPROC(FSOUND_FX_SetCompressor, "_FSOUND_FX_SetCompressor@28");
+    F_GETPROC(FSOUND_FX_SetDistortion, "_FSOUND_FX_SetDistortion@24");
+    F_GETPROC(FSOUND_FX_SetEcho, "_FSOUND_FX_SetEcho@24");
+    F_GETPROC(FSOUND_FX_SetFlanger, "_FSOUND_FX_SetFlanger@32");
+    F_GETPROC(FSOUND_FX_SetGargle, "_FSOUND_FX_SetGargle@12");
+    F_GETPROC(FSOUND_FX_SetI3DL2Reverb, "_FSOUND_FX_SetI3DL2Reverb@52");
+    F_GETPROC(FSOUND_FX_SetParamEQ, "_FSOUND_FX_SetParamEQ@16");
+    F_GETPROC(FSOUND_FX_SetWavesReverb, "_FSOUND_FX_SetWavesReverb@20");
+    F_GETPROC(FSOUND_Stream_Open, "_FSOUND_Stream_Open@16");
+    F_GETPROC(FSOUND_Stream_Create, "_FSOUND_Stream_Create@20");
+    F_GETPROC(FSOUND_Stream_Play, "_FSOUND_Stream_Play@8");
+    F_GETPROC(FSOUND_Stream_PlayEx, "_FSOUND_Stream_PlayEx@16");
+    F_GETPROC(FSOUND_Stream_Stop, "_FSOUND_Stream_Stop@4");
+    F_GETPROC(FSOUND_Stream_Close, "_FSOUND_Stream_Close@4");
+    F_GETPROC(FSOUND_Stream_SetEndCallback, "_FSOUND_Stream_SetEndCallback@12");
+    F_GETPROC(FSOUND_Stream_SetSyncCallback, "_FSOUND_Stream_SetSyncCallback@12");
+    F_GETPROC(FSOUND_Stream_GetSample, "_FSOUND_Stream_GetSample@4");
+    F_GETPROC(FSOUND_Stream_CreateDSP, "_FSOUND_Stream_CreateDSP@16");
+    F_GETPROC(FSOUND_Stream_SetBufferSize, "_FSOUND_Stream_SetBufferSize@4");
+    F_GETPROC(FSOUND_Stream_SetPosition, "_FSOUND_Stream_SetPosition@8");
+    F_GETPROC(FSOUND_Stream_GetPosition, "_FSOUND_Stream_GetPosition@4");
+    F_GETPROC(FSOUND_Stream_SetTime, "_FSOUND_Stream_SetTime@8");
+    F_GETPROC(FSOUND_Stream_GetTime, "_FSOUND_Stream_GetTime@4");
+    F_GETPROC(FSOUND_Stream_GetLength, "_FSOUND_Stream_GetLength@4");
+    F_GETPROC(FSOUND_Stream_GetLengthMs, "_FSOUND_Stream_GetLengthMs@4");
+    F_GETPROC(FSOUND_Stream_SetMode, "_FSOUND_Stream_SetMode@8");
+    F_GETPROC(FSOUND_Stream_GetMode, "_FSOUND_Stream_GetMode@4");
+    F_GETPROC(FSOUND_Stream_SetSubStream, "_FSOUND_Stream_SetSubStream@8");
+    F_GETPROC(FSOUND_Stream_GetNumSubStreams, "_FSOUND_Stream_GetNumSubStreams@4");
+    F_GETPROC(FSOUND_Stream_SetSubStreamSentence, "_FSOUND_Stream_SetSubStreamSentence@12");
+    F_GETPROC(FSOUND_Stream_SetLoopPoints, "_FSOUND_Stream_SetLoopPoints@12");
+    F_GETPROC(FSOUND_Stream_SetLoopCount, "_FSOUND_Stream_SetLoopCount@8");
+    F_GETPROC(FSOUND_Stream_AddSyncPoint, "_FSOUND_Stream_AddSyncPoint@12");
+    F_GETPROC(FSOUND_Stream_DeleteSyncPoint, "_FSOUND_Stream_DeleteSyncPoint@4");
+    F_GETPROC(FSOUND_Stream_GetNumSyncPoints, "_FSOUND_Stream_GetNumSyncPoints@4");
+    F_GETPROC(FSOUND_Stream_GetSyncPoint, "_FSOUND_Stream_GetSyncPoint@8");
+    F_GETPROC(FSOUND_Stream_GetSyncPointInfo, "_FSOUND_Stream_GetSyncPointInfo@8");
+    F_GETPROC(FSOUND_Stream_GetOpenState, "_FSOUND_Stream_GetOpenState@4");
+    F_GETPROC(FSOUND_Stream_GetNumTagFields, "_FSOUND_Stream_GetNumTagFields@8");
+    F_GETPROC(FSOUND_Stream_GetTagField, "_FSOUND_Stream_GetTagField@24");
+    F_GETPROC(FSOUND_Stream_FindTagField, "_FSOUND_Stream_FindTagField@20");
+    F_GETPROC(FSOUND_Stream_Net_SetProxy, "_FSOUND_Stream_Net_SetProxy@4");
+    F_GETPROC(FSOUND_Stream_Net_GetLastServerStatus, "_FSOUND_Stream_Net_GetLastServerStatus@0");
+    F_GETPROC(FSOUND_Stream_Net_SetBufferProperties, "_FSOUND_Stream_Net_SetBufferProperties@12");
+    F_GETPROC(FSOUND_Stream_Net_GetBufferProperties, "_FSOUND_Stream_Net_GetBufferProperties@12");
+    F_GETPROC(FSOUND_Stream_Net_SetMetadataCallback, "_FSOUND_Stream_Net_SetMetadataCallback@12");
+    F_GETPROC(FSOUND_Stream_Net_GetStatus, "_FSOUND_Stream_Net_GetStatus@20");
+    F_GETPROC(FSOUND_CD_Play, "_FSOUND_CD_Play@8");
+    F_GETPROC(FSOUND_CD_SetPlayMode, "_FSOUND_CD_SetPlayMode@8");
+    F_GETPROC(FSOUND_CD_Stop, "_FSOUND_CD_Stop@4");
+    F_GETPROC(FSOUND_CD_SetPaused, "_FSOUND_CD_SetPaused@8");
+    F_GETPROC(FSOUND_CD_SetVolume, "_FSOUND_CD_SetVolume@8");
+    F_GETPROC(FSOUND_CD_SetTrackTime, "_FSOUND_CD_SetTrackTime@8");
+    F_GETPROC(FSOUND_CD_OpenTray, "_FSOUND_CD_OpenTray@8");
+    F_GETPROC(FSOUND_CD_GetPaused, "_FSOUND_CD_GetPaused@4");
+    F_GETPROC(FSOUND_CD_GetTrack, "_FSOUND_CD_GetTrack@4");
+    F_GETPROC(FSOUND_CD_GetNumTracks, "_FSOUND_CD_GetNumTracks@4");
+    F_GETPROC(FSOUND_CD_GetVolume, "_FSOUND_CD_GetVolume@4");
+    F_GETPROC(FSOUND_CD_GetTrackLength, "_FSOUND_CD_GetTrackLength@8");
+    F_GETPROC(FSOUND_CD_GetTrackTime, "_FSOUND_CD_GetTrackTime@4");
+    F_GETPROC(FSOUND_DSP_Create, "_FSOUND_DSP_Create@12");
+    F_GETPROC(FSOUND_DSP_Free, "_FSOUND_DSP_Free@4");
+    F_GETPROC(FSOUND_DSP_SetPriority, "_FSOUND_DSP_SetPriority@8");
+    F_GETPROC(FSOUND_DSP_GetPriority, "_FSOUND_DSP_GetPriority@4");
+    F_GETPROC(FSOUND_DSP_SetActive, "_FSOUND_DSP_SetActive@8");
+    F_GETPROC(FSOUND_DSP_GetActive, "_FSOUND_DSP_GetActive@4");
+    F_GETPROC(FSOUND_DSP_GetClearUnit, "_FSOUND_DSP_GetClearUnit@0");
+    F_GETPROC(FSOUND_DSP_GetSFXUnit, "_FSOUND_DSP_GetSFXUnit@0");
+    F_GETPROC(FSOUND_DSP_GetMusicUnit, "_FSOUND_DSP_GetMusicUnit@0");
+    F_GETPROC(FSOUND_DSP_GetClipAndCopyUnit, "_FSOUND_DSP_GetClipAndCopyUnit@0");
+    F_GETPROC(FSOUND_DSP_GetFFTUnit, "_FSOUND_DSP_GetFFTUnit@0");
+    F_GETPROC(FSOUND_DSP_MixBuffers, "_FSOUND_DSP_MixBuffers@28");
+    F_GETPROC(FSOUND_DSP_ClearMixBuffer, "_FSOUND_DSP_ClearMixBuffer@0");
+    F_GETPROC(FSOUND_DSP_GetBufferLength, "_FSOUND_DSP_GetBufferLength@0");
+    F_GETPROC(FSOUND_DSP_GetBufferLengthTotal, "_FSOUND_DSP_GetBufferLengthTotal@0");
+    F_GETPROC(FSOUND_DSP_GetSpectrum, "_FSOUND_DSP_GetSpectrum@0");
+    F_GETPROC(FSOUND_Reverb_SetProperties, "_FSOUND_Reverb_SetProperties@4");
+    F_GETPROC(FSOUND_Reverb_GetProperties, "_FSOUND_Reverb_GetProperties@4");
+    F_GETPROC(FSOUND_Reverb_SetChannelProperties, "_FSOUND_Reverb_SetChannelProperties@8");
+    F_GETPROC(FSOUND_Reverb_GetChannelProperties, "_FSOUND_Reverb_GetChannelProperties@8");
+    F_GETPROC(FSOUND_Record_SetDriver, "_FSOUND_Record_SetDriver@4");
+    F_GETPROC(FSOUND_Record_GetNumDrivers, "_FSOUND_Record_GetNumDrivers@0");
+    F_GETPROC(FSOUND_Record_GetDriverName, "_FSOUND_Record_GetDriverName@4");
+    F_GETPROC(FSOUND_Record_GetDriver, "_FSOUND_Record_GetDriver@0");
+    F_GETPROC(FSOUND_Record_StartSample, "_FSOUND_Record_StartSample@8");
+    F_GETPROC(FSOUND_Record_Stop, "_FSOUND_Record_Stop@0");
+    F_GETPROC(FSOUND_Record_GetPosition, "_FSOUND_Record_GetPosition@0");
+    F_GETPROC(FSOUND_File_SetCallbacks, "_FSOUND_File_SetCallbacks@20");
+    F_GETPROC(FMUSIC_LoadSong, "_FMUSIC_LoadSong@4");
+    F_GETPROC(FMUSIC_LoadSongEx, "_FMUSIC_LoadSongEx@24");
+    F_GETPROC(FMUSIC_GetOpenState, "_FMUSIC_GetOpenState@4");
+    F_GETPROC(FMUSIC_FreeSong, "_FMUSIC_FreeSong@4");
+    F_GETPROC(FMUSIC_PlaySong, "_FMUSIC_PlaySong@4");
+    F_GETPROC(FMUSIC_StopSong, "_FMUSIC_StopSong@4");
+    F_GETPROC(FMUSIC_StopAllSongs, "_FMUSIC_StopAllSongs@0");
+    F_GETPROC(FMUSIC_SetZxxCallback, "_FMUSIC_SetZxxCallback@8");
+    F_GETPROC(FMUSIC_SetRowCallback, "_FMUSIC_SetRowCallback@12");
+    F_GETPROC(FMUSIC_SetOrderCallback, "_FMUSIC_SetOrderCallback@12");
+    F_GETPROC(FMUSIC_SetInstCallback, "_FMUSIC_SetInstCallback@12");
+    F_GETPROC(FMUSIC_SetSample, "_FMUSIC_SetSample@12");
+    F_GETPROC(FMUSIC_SetUserData, "_FMUSIC_SetUserData@8");
+    F_GETPROC(FMUSIC_OptimizeChannels, "_FMUSIC_OptimizeChannels@12");
+    F_GETPROC(FMUSIC_SetReverb, "_FMUSIC_SetReverb@4");
+    F_GETPROC(FMUSIC_SetLooping, "_FMUSIC_SetLooping@8");
+    F_GETPROC(FMUSIC_SetOrder, "_FMUSIC_SetOrder@8");
+    F_GETPROC(FMUSIC_SetPaused, "_FMUSIC_SetPaused@8");
+    F_GETPROC(FMUSIC_SetMasterVolume, "_FMUSIC_SetMasterVolume@8");
+    F_GETPROC(FMUSIC_SetMasterSpeed, "_FMUSIC_SetMasterSpeed@8");
+    F_GETPROC(FMUSIC_SetPanSeperation, "_FMUSIC_SetPanSeperation@8");
+    F_GETPROC(FMUSIC_GetName, "_FMUSIC_GetName@4");
+    F_GETPROC(FMUSIC_GetType, "_FMUSIC_GetType@4");
+    F_GETPROC(FMUSIC_GetNumOrders, "_FMUSIC_GetNumOrders@4");
+    F_GETPROC(FMUSIC_GetNumPatterns, "_FMUSIC_GetNumPatterns@4");
+    F_GETPROC(FMUSIC_GetNumInstruments, "_FMUSIC_GetNumInstruments@4");
+    F_GETPROC(FMUSIC_GetNumSamples, "_FMUSIC_GetNumSamples@4");
+    F_GETPROC(FMUSIC_GetNumChannels, "_FMUSIC_GetNumChannels@4");
+    F_GETPROC(FMUSIC_GetSample, "_FMUSIC_GetSample@8");
+    F_GETPROC(FMUSIC_GetPatternLength, "_FMUSIC_GetPatternLength@8");
+    F_GETPROC(FMUSIC_IsFinished, "_FMUSIC_IsFinished@4");
+    F_GETPROC(FMUSIC_IsPlaying, "_FMUSIC_IsPlaying@4");
+    F_GETPROC(FMUSIC_GetMasterVolume, "_FMUSIC_GetMasterVolume@4");
+    F_GETPROC(FMUSIC_GetGlobalVolume, "_FMUSIC_GetGlobalVolume@4");
+    F_GETPROC(FMUSIC_GetOrder, "_FMUSIC_GetOrder@4");
+    F_GETPROC(FMUSIC_GetPattern, "_FMUSIC_GetPattern@4");
+    F_GETPROC(FMUSIC_GetSpeed, "_FMUSIC_GetSpeed@4");
+    F_GETPROC(FMUSIC_GetBPM, "_FMUSIC_GetBPM@4");
+    F_GETPROC(FMUSIC_GetRow, "_FMUSIC_GetRow@4");
+    F_GETPROC(FMUSIC_GetPaused, "_FMUSIC_GetPaused@4");
+    F_GETPROC(FMUSIC_GetTime, "_FMUSIC_GetTime@4");
+    F_GETPROC(FMUSIC_GetRealChannel, "_FMUSIC_GetRealChannel@8");
+    F_GETPROC(FMUSIC_GetUserData, "_FMUSIC_GetUserData@4");
+
+    return instance;
+}
+
+static void FMOD_FreeInstance(FMOD_INSTANCE *instance)
+{
+    if (instance)
+    {
+        if (instance->module)
+        {
+#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64)
+            FreeLibrary((HMODULE)instance->module);
+#else
+            dlclose(instance->module);
+#endif
+        }
+        free(instance);
+    }
+}
+
+#endif
+
diff --git a/Source/gl.h b/Source/gl.h
new file mode 100644 (file)
index 0000000..3d0a5f2
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef _LUGARU_GL_H_
+#define _LUGARU_GL_H_
+
+
+#include <cstring>
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+#include <map>
+#include <string>
+
+#ifndef WIN32
+
+#include <gl.h>
+#include <glu.h>
+#include <glext.h>
+
+#else
+
+#define WIN32_LEAN_AND_MEAN
+#define Polygon WinPolygon
+#include <windows.h>
+#undef Polygon
+#define GL_GLEXT_PROTOTYPES
+#include <gl/gl.h>
+#include <gl/glu.h>
+#include <gl/glaux.h>
+#include <gl/glext.h>
+#include "WinDefs.h"
+#include "il/ilut.h"
+
+#define glDeleteTextures( a, b) glDeleteTextures( (a), (const unsigned int *)(b) );
+
+struct RGBColor
+{
+       unsigned short red;
+       unsigned short green;
+       unsigned short blue;
+};
+typedef struct RGBColor RGBColor;
+typedef RGBColor * RGBColorPtr;
+
+#endif
+
+using namespace std;
+
+#include "logger/logger.h"
+
+#endif
\ No newline at end of file
diff --git a/Source/logger/Copy of logger.cpp b/Source/logger/Copy of logger.cpp
new file mode 100644 (file)
index 0000000..edd22e2
--- /dev/null
@@ -0,0 +1,448 @@
+// ---------------------------------------------------------------------------------------------------------------------------------
+//  _                                                  
+// | |                                                 
+// | | ___   __ _  __ _  ___ _ __      ___ _ __  _ __  
+// | |/ _ \ / _` |/ _` |/ _ \ '__|    / __| '_ \| '_ \ 
+// | | (_) | (_| | (_| |  __/ |    _ | (__| |_) | |_) |
+// |_|\___/ \__, |\__, |\___|_|   (_) \___| .__/| .__/ 
+//           __/ | __/ |                  | |   | |    
+//          |___/ |___/                   |_|   |_|    
+//
+// Generic informational logging class
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+//
+// Restrictions & freedoms pertaining to usage and redistribution of this software:
+//
+//  * This software is 100% free
+//  * If you use this software (in part or in whole) you must credit the author.
+//  * This software may not be re-distributed (in part or in whole) in a modified
+//    form without clear documentation on how to obtain a copy of the original work.
+//  * You may not use this software to directly or indirectly cause harm to others.
+//  * This software is provided as-is and without warrantee. Use at your own risk.
+//
+// For more information, visit HTTP://www.FluidStudios.com
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Originally created on 07/06/2000 by Paul Nettle
+//
+// Copyright 2000, Fluid Studios, Inc., all rights reserved.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+//#include "stdafx.h" // If this line gives you an error, comment it out
+#include <string>
+#include <list>
+#include <map>
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+//#include <strstream>
+#include <sstream>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctime>
+using namespace std;
+
+#include "logger.h"
+
+class LogFunc
+{
+public:
+       LogFunc(void) {}
+
+       void pushMessage(const std::string & str)
+       {
+               entries.push_back(str);
+       }
+
+       void dump(std::ostream & os)
+       {
+               std::list<std::string>::iterator it = entries.begin();
+               for (; it != entries.end(); ++it)
+               {
+                       os << *it;
+               }
+       }
+
+private:
+       std::list<std::string> entries;
+};
+
+class LogStack
+{
+public:
+       LogStack(void)
+       {
+               pushFunc();
+       }
+
+       void pushFunc(void)
+       {
+               entries.push_back(LogFunc());
+       }
+
+       void popFunc(void)
+       {
+               if (entries.size() > 1)
+               {
+                       entries.pop_back();
+               }
+       }
+
+       void logMessage(const std::string & str_)
+       {
+               entries.back().pushMessage(str_);
+       }
+
+       void dump(std::ostream & os)
+       {
+               std::list<LogFunc>::iterator it = entries.begin();
+               for (; it != entries.end(); ++it)
+               {
+                       it->dump(os);
+               }
+       }
+
+private:
+       std::list<LogFunc> entries;
+};
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// The global log stack object
+// ---------------------------------------------------------------------------------------------------------------------------------
+LogStack logStack;
+
+void pushFunc(void) {logStack.pushFunc();}
+void popFunc(void) {logStack.popFunc();}
+
+void dumpLog(void)
+{
+       ofstream of(logger.logFile().c_str(), ios::out | ios::trunc);
+       if (!of) return;
+       logStack.dump(of);
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// The global logger object
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+Logger logger;
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+#ifdef _DEBUG
+void   Logger::limitFileSize() const
+{
+       if (fileSizeLimit() < 0) return;
+       struct  _stat sbuf;
+       _stat(logFile().c_str(), &sbuf);
+       if (sbuf.st_size > fileSizeLimit())
+       {
+               unlink(logFile().c_str());
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   Logger::start(const bool reset)
+{
+       std::stringstream ss;
+
+       if (logStarted()) return;
+       _logStarted = true;
+
+       // Get the time
+
+       time_t  t = time(NULL);
+       string  ts = asctime(localtime(&t));
+       ts[ts.length() - 1] = 0;
+
+       // Start the log
+
+       //limitFileSize();
+       //ofstream of(logFile().c_str(), ios::out | (reset ? ios::trunc : ios::app));
+       //if (!of) return;
+
+       //of << "---------------------------------------------- Log begins on " << ts << " ----------------------------------------------" << endl;
+       ss << "---------------------------------------------- Log begins on " << ts << " ----------------------------------------------" << endl;
+       logStack.logMessage(ss.str());
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   Logger::stop()
+{
+       std::stringstream ss;
+
+       // Automatic One time only startup
+
+       if (!logStarted()) return;
+       _logStarted = false;
+
+       // Get the time
+
+       time_t  t = time(NULL);
+       string  ts = asctime(localtime(&t));
+       ts.erase(ts.length() - 1);
+
+       // Stop the log
+
+       limitFileSize();
+       ofstream of(logFile().c_str(), ios::out|ios::app);
+       if (!of) return;
+
+       //of << "----------------------------------------------- Log ends on " << ts << " -----------------------------------------------" << endl << endl;
+       ss << "----------------------------------------------- Log ends on " << ts << " -----------------------------------------------" << endl << endl;
+       logStack.logMessage(ss.str());
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   Logger::logTex(const string &s, const LogFlags logBits)
+{
+       std::stringstream ss;
+
+       // If the bits don't match the mask, then bail
+
+       if (!(logBits & logMask())) return;
+
+       // Open the file
+
+       limitFileSize();
+       ofstream of(logFile().c_str(), ios::out|ios::app);
+       if (!of) return;
+
+       // Output to the log file
+
+       //of << headerString(logBits) << s << endl;
+       ss << headerString(logBits) << s << endl;
+       logStack.logMessage(ss.str());
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   Logger::logRaw(const string &s)
+{
+       std::stringstream ss;
+
+       // Open the file
+
+       //limitFileSize();
+       //ofstream of(logFile().c_str(), ios::out|ios::app);
+       //if (!of) return;
+
+       // Log the output
+
+       //of << s << endl;
+       ss << s << endl;
+       logStack.logMessage(ss.str());
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   Logger::logHex(const char *buffer, const unsigned int count, const LogFlags logBits)
+{
+       std::stringstream ss;
+
+       // No input? No output
+
+       if (!buffer) return;
+
+       // If the bits don't match the mask, then bail
+
+       if (!(logBits & logMask())) return;
+
+       // Open the file
+
+       //limitFileSize();
+       //ofstream of(logFile().c_str(), ios::out|ios::app);
+       //if (!of) return;
+
+       // Log the output
+
+       unsigned int    logged = 0;
+       while(logged < count)
+       {
+               // One line at a time...
+
+               string          line;
+
+               // The number of characters per line
+
+               unsigned int    hexLength = 20;
+
+               // Default the buffer
+
+               unsigned int    i;
+               for (i = 0; i < hexLength; i++)
+               {
+                       line += "-- ";
+               }
+
+               for (i = 0; i < hexLength; i++)
+               {
+                       line += ".";
+               }
+
+               // Fill it in with real data
+
+               for (i = 0; i < hexLength && logged < count; i++, logged++)
+               {
+                       unsigned char   byte = buffer[logged];
+                       unsigned int    index = i * 3;
+
+                       // The hex characters
+
+                       const string    hexlist("0123456789ABCDEF");
+                       line[index+0] = hexlist[byte >> 4];
+                       line[index+1] = hexlist[byte & 0xf];
+
+                       // The ascii characters
+
+                       if (byte < 0x20 || byte > 0x7f) byte = '.';
+                       line[(hexLength*3)+i+0] = byte;
+               }
+
+               // Write it to the log file
+
+               //of << headerString(logBits) << line << endl;
+               ss << headerString(logBits) << line << endl;
+               logStack.logMessage(ss.str());
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   Logger::indent(const string &s, const LogFlags logBits)
+{
+       std::stringstream ss;
+
+       // If the bits don't match the mask, then bail
+
+       if (!(logBits & logMask())) return;
+
+       // Open the file
+
+       //limitFileSize();
+       //ofstream of(logFile().c_str(), ios::out|ios::app);
+       //if (!of) return;
+
+       // Log the output
+
+       //if (lineCharsFlag())  of << headerString(logBits) << "\xDA\xC4\xC4" << s << endl;
+       //else                  of << headerString(logBits) << "+-  " << s << endl;
+
+       if (lineCharsFlag())    ss << headerString(logBits) << "\xDA\xC4\xC4" << s << endl;
+       else                    ss << headerString(logBits) << "+-  " << s << endl;
+       logStack.logMessage(ss.str());
+
+       // Indent...
+
+       _indentCount += _indentChars;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   Logger::undent(const string &s, const LogFlags logBits)
+{
+       std::stringstream ss;
+
+       // If the bits don't match the mask, then bail
+
+       if (!(logBits & logMask())) return;
+
+       // Undo the indentation
+
+       _indentCount -= _indentChars;
+       if (_indentCount < 0) _indentCount = 0;
+
+       // Open the file
+
+       limitFileSize();
+       ofstream of(logFile().c_str(), ios::out|ios::app);
+       if (!of) return;
+
+       // Log the output
+
+       //if (lineCharsFlag())  of << headerString(logBits) << "\xC0\xC4\xC4" << s << endl;
+       //else                  of << headerString(logBits) << "+-  " << s << endl;
+
+       if (lineCharsFlag())    ss << headerString(logBits) << "\xC0\xC4\xC4" << s << endl;
+       else                    ss << headerString(logBits) << "+-  " << s << endl;
+       logStack.logMessage(ss.str());
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+const  string  &Logger::headerString(const LogFlags logBits) const
+{
+       static  string  headerString;
+       headerString.erase();
+
+       // Get the string that represents the bits
+
+       switch(logBits)
+       {
+               case LOG_INDENT : headerString += "> "; break;
+               case LOG_UNDENT : headerString += "< "; break;
+               case LOG_ALL    : headerString += "A "; break;
+               case LOG_CRIT   : headerString += "! "; break;
+               case LOG_DATA   : headerString += "D "; break;
+               case LOG_ERR    : headerString += "E "; break;
+               case LOG_FLOW   : headerString += "F "; break;
+               case LOG_INFO   : headerString += "I "; break;
+               case LOG_WARN   : headerString += "W "; break;
+               default:          headerString += "  "; break;
+       }
+
+       // File string (strip out the path)
+
+       char    temp[1024];
+       int     ix = sourceFile().rfind('\\');
+       ix = (ix == (int) string::npos ? 0: ix+1);
+       sprintf(temp, "%25s[%04d]", sourceFile().substr(ix).c_str(), sourceLine());
+       headerString += temp;
+
+       // Time string (specially formatted to save room)
+
+       time_t  t = time(NULL);
+       struct  tm *tme = localtime(&t);
+       sprintf(temp, "%02d/%02d %02d:%02d ", tme->tm_mon + 1, tme->tm_mday, tme->tm_hour, tme->tm_min);
+       headerString += temp;
+
+       // Spaces for indentation
+
+       memset(temp, ' ', sizeof(temp));
+       temp[_indentCount] = '\0';
+
+       // Add the indentation markers
+
+       int     count = 0;
+       while(count < _indentCount)
+       {
+               if (lineCharsFlag())    temp[count] = '\xB3';
+               else                    temp[count] = '|';
+               count += _indentChars;
+       }
+       headerString += temp;
+
+       return headerString;
+}
+
+#else /*Release Build*/
+       std::string release_Null;
+       void            Logger::limitFileSize() const {}
+       const   string          &Logger::headerString(const LogFlags logBits) const{return release_Null;}
+       void            Logger::start(const bool reset){}
+       void            Logger::stop(){}
+       void            Logger::logTex(const string &s, const LogFlags logBits /*= LOG_INFO*/){}
+       void            Logger::logRaw(const string &s){}
+       void            Logger::logHex(const char *buffer, const unsigned int count, const LogFlags logBits /*= LOG_INFO*/){}
+       void            Logger::indent(const string &s, const LogFlags logBits /*= LOG_INDENT*/){}
+       void            Logger::undent(const string &s, const LogFlags logBits /*= LOG_UNDENT*/){}
+#endif
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// logger.cpp - End of file
+// ---------------------------------------------------------------------------------------------------------------------------------
+
diff --git a/Source/logger/Copy of logger.h b/Source/logger/Copy of logger.h
new file mode 100644 (file)
index 0000000..4019bc0
--- /dev/null
@@ -0,0 +1,186 @@
+// ---------------------------------------------------------------------------------------------------------------------------------
+//  _                                 _     
+// | |                               | |    
+// | | ___   __ _  __ _  ___ _ __    | |__  
+// | |/ _ \ / _` |/ _` |/ _ \ '__|   | '_ \ 
+// | | (_) | (_| | (_| |  __/ |    _ | | | |
+// |_|\___/ \__, |\__, |\___|_|   (_)|_| |_|
+//           __/ | __/ |                    
+//          |___/ |___/                     
+//
+// Generic informational logging class
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+//
+// Restrictions & freedoms pertaining to usage and redistribution of this software:
+//
+//  * This software is 100% free
+//  * If you use this software (in part or in whole) you must credit the author.
+//  * This software may not be re-distributed (in part or in whole) in a modified
+//    form without clear documentation on how to obtain a copy of the original work.
+//  * You may not use this software to directly or indirectly cause harm to others.
+//  * This software is provided as-is and without warrantee. Use at your own risk.
+//
+// For more information, visit HTTP://www.FluidStudios.com
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Originally created on 07/06/2000 by Paul Nettle
+//
+// Copyright 2000, Fluid Studios, Inc., all rights reserved.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+#ifndef        _H_LOGGER
+#define _H_LOGGER
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// The global logger
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+class  Logger;
+extern Logger  logger;
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Macros (necessary evil to take advantage of __LINE__ and __FILE__)
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+#define        LOG             logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.logTex
+#define        HEX             logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.logHex
+#define        RAW             logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.logRaw
+#define        INDENT          logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.indent
+#define        UNDENT          logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.undent
+#define        LOGBLOCK        logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__;LogBlock __lb__
+
+// If you compiler supports __FUNCTION__, then replace the "#if 1" with "#if 0". Note that this will change the usage of the macro
+
+#if 0
+#define        LOGFUNC         logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__;LogFlow __lf__
+#else
+#define        LOGFUNC         logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__;LogFlow __lf__(__FUNCTION__)
+#endif
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// The logger class: does the actual logging
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+class  Logger
+{
+public:
+       // Enumerations
+
+       enum    LogFlags
+       {
+                               LOG_INDENT = 0x00000001,
+                               LOG_UNDENT = 0x00000002,
+                               LOG_FLOW   = 0x00000004,
+                               LOG_BLOK   = 0x00000008,
+                               LOG_DATA   = 0x00000010,
+                               LOG_INFO   = 0x00000012,
+                               LOG_WARN   = 0x00000014,
+                               LOG_ERR    = 0x00000018,
+                               LOG_CRIT   = 0x00000020,
+                               LOG_ALL    = 0xFFFFFFFF
+       };
+
+       // Construction/Destruction
+
+inline                         Logger()
+                               : _sourceLine(0), _indentCount(0), _indentChars(4), _fileSizeLimit(-1), _logMask(LOG_ALL),
+                                 _logStarted(false), _lineCharsFlag(false), _logFile("logger.log")
+                               {
+                               }
+
+virtual                                ~Logger()
+                               {
+                                       stop();
+                               }
+
+       // Operators
+
+inline         void            operator +=(const string &s)    {logTex(s);}
+
+       // Accessors
+
+inline const   bool            &lineCharsFlag() const  {return _lineCharsFlag;}
+inline         bool            &lineCharsFlag()        {return _lineCharsFlag;}
+
+inline const   int             &fileSizeLimit() const  {return _fileSizeLimit;}
+inline         int             &fileSizeLimit()        {return _fileSizeLimit;}
+
+inline const   unsigned int    &logMask() const        {return _logMask;}
+inline         unsigned int    &logMask()              {return _logMask;}
+
+inline const   string          &logFile() const        {return _logFile;}
+inline         string          &logFile()              {return _logFile;}
+
+inline const   unsigned int    &sourceLine() const     {return _sourceLine;}
+inline         unsigned int    &sourceLine()           {return _sourceLine;}
+
+inline const   string          &sourceFile() const     {return _sourceFile;}
+inline         string          &sourceFile()           {return _sourceFile;}
+
+inline         bool            logStarted() const      {return _logStarted;}
+
+       // Utilitarian (public)
+
+virtual                void            start(const bool reset);
+virtual                void            stop();
+virtual                void            logTex(const string &s, const LogFlags logBits = LOG_INFO);
+virtual                void            logRaw(const string &s);
+virtual                void            logHex(const char *buffer, const unsigned int count, const LogFlags logBits = LOG_INFO);
+virtual                void            indent(const string &s, const LogFlags logBits = LOG_INDENT);
+virtual                void            undent(const string &s, const LogFlags logBits = LOG_UNDENT);
+
+private:
+       // Utilitarian (private)
+
+virtual                void            limitFileSize() const;
+virtual        const   string          &headerString(const LogFlags logBits) const;
+
+       // Data
+
+               string          _logFile;
+               string          _sourceFile;
+               unsigned int    _sourceLine;
+               int             _indentCount;
+               int             _indentChars;
+               int             _fileSizeLimit;
+               unsigned int    _logMask;
+               bool            _logStarted;
+               bool            _lineCharsFlag;
+};
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// The LogBlock class: used for automatic indentation
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+class  LogBlock
+{
+public:
+inline                         LogBlock(const string &s)       {str = s;logger.indent("Begin block: " + str, Logger::LOG_INDENT);}
+inline                         ~LogBlock()                     {logger.undent("", Logger::LOG_UNDENT);}
+private:
+               string          str;
+};
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// The LogFlow class: used for logging code flow
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void pushFunc(void);
+void popFunc(void);
+void dumpLog(void);
+
+class  LogFlow
+{
+public:
+inline                         LogFlow(const string &function) {pushFunc(); str = function;logger.indent(str, Logger::LOG_FLOW);}
+inline                         ~LogFlow()                      {logger.undent("", Logger::LOG_FLOW); popFunc();}
+private:
+               string          str;
+};
+
+#endif // _H_LOGGER
+// ---------------------------------------------------------------------------------------------------------------------------------
+// logger.h - End of file
+// ---------------------------------------------------------------------------------------------------------------------------------
+
diff --git a/Source/logger/logger.cpp b/Source/logger/logger.cpp
new file mode 100644 (file)
index 0000000..3a67a07
--- /dev/null
@@ -0,0 +1,337 @@
+// ---------------------------------------------------------------------------------------------------------------------------------
+//  _                                                  
+// | |                                                 
+// | | ___   __ _  __ _  ___ _ __      ___ _ __  _ __  
+// | |/ _ \ / _` |/ _` |/ _ \ '__|    / __| '_ \| '_ \ 
+// | | (_) | (_| | (_| |  __/ |    _ | (__| |_) | |_) |
+// |_|\___/ \__, |\__, |\___|_|   (_) \___| .__/| .__/ 
+//           __/ | __/ |                  | |   | |    
+//          |___/ |___/                   |_|   |_|    
+//
+// Generic informational logging class
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+//
+// Restrictions & freedoms pertaining to usage and redistribution of this software:
+//
+//  * This software is 100% free
+//  * If you use this software (in part or in whole) you must credit the author.
+//  * This software may not be re-distributed (in part or in whole) in a modified
+//    form without clear documentation on how to obtain a copy of the original work.
+//  * You may not use this software to directly or indirectly cause harm to others.
+//  * This software is provided as-is and without warrantee. Use at your own risk.
+//
+// For more information, visit HTTP://www.FluidStudios.com
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Originally created on 07/06/2000 by Paul Nettle
+//
+// Copyright 2000, Fluid Studios, Inc., all rights reserved.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+//#include "stdafx.h" // If this line gives you an error, comment it out
+#include <string>
+#include <list>
+#include <map>
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <strstream>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctime>
+using namespace std;
+
+#include "logger.h"
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// The global logger object
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+Logger logger;
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+#ifdef _DEBUG
+void   Logger::limitFileSize() const
+{
+       if (fileSizeLimit() < 0) return;
+       struct  _stat sbuf;
+       _stat(logFile().c_str(), &sbuf);
+       if (sbuf.st_size > fileSizeLimit())
+       {
+               unlink(logFile().c_str());
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   Logger::start(const bool reset)
+{
+       if (logStarted()) return;
+       _logStarted = true;
+
+       // Get the time
+
+       time_t  t = time(NULL);
+       string  ts = asctime(localtime(&t));
+       ts[ts.length() - 1] = 0;
+
+       // Start the log
+
+       limitFileSize();
+       ofstream of(logFile().c_str(), ios::out | (reset ? ios::trunc : ios::app));
+       if (!of) return;
+
+       of << "---------------------------------------------- Log begins on " << ts << " ----------------------------------------------" << endl;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   Logger::stop()
+{
+       // Automatic One time only startup
+
+       if (!logStarted()) return;
+       _logStarted = false;
+
+       // Get the time
+
+       time_t  t = time(NULL);
+       string  ts = asctime(localtime(&t));
+       ts.erase(ts.length() - 1);
+
+       // Stop the log
+
+       limitFileSize();
+       ofstream of(logFile().c_str(), ios::out|ios::app);
+       if (!of) return;
+
+       of << "----------------------------------------------- Log ends on " << ts << " -----------------------------------------------" << endl << endl;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   Logger::logTex(const string &s, const LogFlags logBits)
+{
+       // If the bits don't match the mask, then bail
+
+       if (!(logBits & logMask())) return;
+
+       // Open the file
+
+       limitFileSize();
+       ofstream of(logFile().c_str(), ios::out|ios::app);
+       if (!of) return;
+
+       // Output to the log file
+
+       of << headerString(logBits) << s << endl;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   Logger::logRaw(const string &s)
+{
+       // Open the file
+
+       limitFileSize();
+       ofstream of(logFile().c_str(), ios::out|ios::app);
+       if (!of) return;
+
+       // Log the output
+
+       of << s << endl;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   Logger::logHex(const char *buffer, const unsigned int count, const LogFlags logBits)
+{
+       // No input? No output
+
+       if (!buffer) return;
+
+       // If the bits don't match the mask, then bail
+
+       if (!(logBits & logMask())) return;
+
+       // Open the file
+
+       limitFileSize();
+       ofstream of(logFile().c_str(), ios::out|ios::app);
+       if (!of) return;
+
+       // Log the output
+
+       unsigned int    logged = 0;
+       while(logged < count)
+       {
+               // One line at a time...
+
+               string          line;
+
+               // The number of characters per line
+
+               unsigned int    hexLength = 20;
+
+               // Default the buffer
+
+               unsigned int    i;
+               for (i = 0; i < hexLength; i++)
+               {
+                       line += "-- ";
+               }
+
+               for (i = 0; i < hexLength; i++)
+               {
+                       line += ".";
+               }
+
+               // Fill it in with real data
+
+               for (i = 0; i < hexLength && logged < count; i++, logged++)
+               {
+                       unsigned char   byte = buffer[logged];
+                       unsigned int    index = i * 3;
+
+                       // The hex characters
+
+                       const string    hexlist("0123456789ABCDEF");
+                       line[index+0] = hexlist[byte >> 4];
+                       line[index+1] = hexlist[byte & 0xf];
+
+                       // The ascii characters
+
+                       if (byte < 0x20 || byte > 0x7f) byte = '.';
+                       line[(hexLength*3)+i+0] = byte;
+               }
+
+               // Write it to the log file
+
+               of << headerString(logBits) << line << endl;
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   Logger::indent(const string &s, const LogFlags logBits)
+{
+       // If the bits don't match the mask, then bail
+
+       if (!(logBits & logMask())) return;
+
+       // Open the file
+
+       limitFileSize();
+       ofstream of(logFile().c_str(), ios::out|ios::app);
+       if (!of) return;
+
+       // Log the output
+
+       if (lineCharsFlag())    of << headerString(logBits) << "\xDA\xC4\xC4" << s << endl;
+       else                    of << headerString(logBits) << "+-  " << s << endl;
+
+       // Indent...
+
+       _indentCount += _indentChars;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   Logger::undent(const string &s, const LogFlags logBits)
+{
+       // If the bits don't match the mask, then bail
+
+       if (!(logBits & logMask())) return;
+
+       // Undo the indentation
+
+       _indentCount -= _indentChars;
+       if (_indentCount < 0) _indentCount = 0;
+
+       // Open the file
+
+       limitFileSize();
+       ofstream of(logFile().c_str(), ios::out|ios::app);
+       if (!of) return;
+
+       // Log the output
+
+       if (lineCharsFlag())    of << headerString(logBits) << "\xC0\xC4\xC4" << s << endl;
+       else                    of << headerString(logBits) << "+-  " << s << endl;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+const  string  &Logger::headerString(const LogFlags logBits) const
+{
+       static  string  headerString;
+       headerString.erase();
+
+       // Get the string that represents the bits
+
+       switch(logBits)
+       {
+               case LOG_INDENT : headerString += "> "; break;
+               case LOG_UNDENT : headerString += "< "; break;
+               case LOG_ALL    : headerString += "A "; break;
+               case LOG_CRIT   : headerString += "! "; break;
+               case LOG_DATA   : headerString += "D "; break;
+               case LOG_ERR    : headerString += "E "; break;
+               case LOG_FLOW   : headerString += "F "; break;
+               case LOG_INFO   : headerString += "I "; break;
+               case LOG_WARN   : headerString += "W "; break;
+               default:          headerString += "  "; break;
+       }
+
+       // File string (strip out the path)
+
+       char    temp[1024];
+       int     ix = sourceFile().rfind('\\');
+       ix = (ix == (int) string::npos ? 0: ix+1);
+       sprintf(temp, "%25s[%04d]", sourceFile().substr(ix).c_str(), sourceLine());
+       headerString += temp;
+
+       // Time string (specially formatted to save room)
+
+       time_t  t = time(NULL);
+       struct  tm *tme = localtime(&t);
+       sprintf(temp, "%02d/%02d %02d:%02d ", tme->tm_mon + 1, tme->tm_mday, tme->tm_hour, tme->tm_min);
+       headerString += temp;
+
+       // Spaces for indentation
+
+       memset(temp, ' ', sizeof(temp));
+       temp[_indentCount] = '\0';
+
+       // Add the indentation markers
+
+       int     count = 0;
+       while(count < _indentCount)
+       {
+               if (lineCharsFlag())    temp[count] = '\xB3';
+               else                    temp[count] = '|';
+               count += _indentChars;
+       }
+       headerString += temp;
+
+       return headerString;
+}
+
+#else /*Release Build*/
+       std::string release_Null;
+       void            Logger::limitFileSize() const {}
+       const   string          &Logger::headerString(const LogFlags logBits) const{return release_Null;}
+       void            Logger::start(const bool reset){}
+       void            Logger::stop(){}
+       void            Logger::logTex(const string &s, const LogFlags logBits /*= LOG_INFO*/){}
+       void            Logger::logRaw(const string &s){}
+       void            Logger::logHex(const char *buffer, const unsigned int count, const LogFlags logBits /*= LOG_INFO*/){}
+       void            Logger::indent(const string &s, const LogFlags logBits /*= LOG_INDENT*/){}
+       void            Logger::undent(const string &s, const LogFlags logBits /*= LOG_UNDENT*/){}
+#endif
+// ---------------------------------------------------------------------------------------------------------------------------------
+// logger.cpp - End of file
+// ---------------------------------------------------------------------------------------------------------------------------------
+
diff --git a/Source/logger/logger.h b/Source/logger/logger.h
new file mode 100644 (file)
index 0000000..f58b8f7
--- /dev/null
@@ -0,0 +1,182 @@
+// ---------------------------------------------------------------------------------------------------------------------------------
+//  _                                 _     
+// | |                               | |    
+// | | ___   __ _  __ _  ___ _ __    | |__  
+// | |/ _ \ / _` |/ _` |/ _ \ '__|   | '_ \ 
+// | | (_) | (_| | (_| |  __/ |    _ | | | |
+// |_|\___/ \__, |\__, |\___|_|   (_)|_| |_|
+//           __/ | __/ |                    
+//          |___/ |___/                     
+//
+// Generic informational logging class
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+//
+// Restrictions & freedoms pertaining to usage and redistribution of this software:
+//
+//  * This software is 100% free
+//  * If you use this software (in part or in whole) you must credit the author.
+//  * This software may not be re-distributed (in part or in whole) in a modified
+//    form without clear documentation on how to obtain a copy of the original work.
+//  * You may not use this software to directly or indirectly cause harm to others.
+//  * This software is provided as-is and without warrantee. Use at your own risk.
+//
+// For more information, visit HTTP://www.FluidStudios.com
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Originally created on 07/06/2000 by Paul Nettle
+//
+// Copyright 2000, Fluid Studios, Inc., all rights reserved.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+#ifndef        _H_LOGGER
+#define _H_LOGGER
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// The global logger
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+class  Logger;
+extern Logger  logger;
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Macros (necessary evil to take advantage of __LINE__ and __FILE__)
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+#define        LOG             logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.logTex
+#define        HEX             logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.logHex
+#define        RAW             logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.logRaw
+#define        INDENT          logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.indent
+#define        UNDENT          logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__,logger.undent
+#define        LOGBLOCK        logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__;LogBlock __lb__
+
+// If you compiler supports __FUNCTION__, then replace the "#if 1" with "#if 0". Note that this will change the usage of the macro
+
+#if 0
+#define        LOGFUNC         logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__;LogFlow __lf__
+#else
+#define        LOGFUNC         logger.sourceLine() = __LINE__, logger.sourceFile() = __FILE__;LogFlow __lf__(__FUNCTION__)
+#endif
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// The logger class: does the actual logging
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+class  Logger
+{
+public:
+       // Enumerations
+
+       enum    LogFlags
+       {
+                               LOG_INDENT = 0x00000001,
+                               LOG_UNDENT = 0x00000002,
+                               LOG_FLOW   = 0x00000004,
+                               LOG_BLOK   = 0x00000008,
+                               LOG_DATA   = 0x00000010,
+                               LOG_INFO   = 0x00000012,
+                               LOG_WARN   = 0x00000014,
+                               LOG_ERR    = 0x00000018,
+                               LOG_CRIT   = 0x00000020,
+                               LOG_ALL    = 0xFFFFFFFF
+       };
+
+       // Construction/Destruction
+
+inline                         Logger()
+                               : _sourceLine(0), _indentCount(0), _indentChars(4), _fileSizeLimit(-1), _logMask(LOG_ALL),
+                                 _logStarted(false), _lineCharsFlag(false), _logFile("logger.log")
+                               {
+                               }
+
+virtual                                ~Logger()
+                               {
+                                       stop();
+                               }
+
+       // Operators
+
+inline         void            operator +=(const string &s)    {logTex(s);}
+
+       // Accessors
+
+inline const   bool            &lineCharsFlag() const  {return _lineCharsFlag;}
+inline         bool            &lineCharsFlag()        {return _lineCharsFlag;}
+
+inline const   int             &fileSizeLimit() const  {return _fileSizeLimit;}
+inline         int             &fileSizeLimit()        {return _fileSizeLimit;}
+
+inline const   unsigned int    &logMask() const        {return _logMask;}
+inline         unsigned int    &logMask()              {return _logMask;}
+
+inline const   string          &logFile() const        {return _logFile;}
+inline         string          &logFile()              {return _logFile;}
+
+inline const   unsigned int    &sourceLine() const     {return _sourceLine;}
+inline         unsigned int    &sourceLine()           {return _sourceLine;}
+
+inline const   string          &sourceFile() const     {return _sourceFile;}
+inline         string          &sourceFile()           {return _sourceFile;}
+
+inline         bool            logStarted() const      {return _logStarted;}
+
+       // Utilitarian (public)
+
+virtual                void            start(const bool reset);
+virtual                void            stop();
+virtual                void            logTex(const string &s, const LogFlags logBits = LOG_INFO);
+virtual                void            logRaw(const string &s);
+virtual                void            logHex(const char *buffer, const unsigned int count, const LogFlags logBits = LOG_INFO);
+virtual                void            indent(const string &s, const LogFlags logBits = LOG_INDENT);
+virtual                void            undent(const string &s, const LogFlags logBits = LOG_UNDENT);
+
+private:
+       // Utilitarian (private)
+
+virtual                void            limitFileSize() const;
+virtual        const   string          &headerString(const LogFlags logBits) const;
+
+       // Data
+
+               string          _logFile;
+               string          _sourceFile;
+               unsigned int    _sourceLine;
+               int             _indentCount;
+               int             _indentChars;
+               int             _fileSizeLimit;
+               unsigned int    _logMask;
+               bool            _logStarted;
+               bool            _lineCharsFlag;
+};
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// The LogBlock class: used for automatic indentation
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+class  LogBlock
+{
+public:
+inline                         LogBlock(const string &s)       {str = s;logger.indent("Begin block: " + str, Logger::LOG_INDENT);}
+inline                         ~LogBlock()                     {logger.undent("", Logger::LOG_UNDENT);}
+private:
+               string          str;
+};
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// The LogFlow class: used for logging code flow
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+class  LogFlow
+{
+public:
+inline                         LogFlow(const string &function) {str = function;logger.indent(str, Logger::LOG_FLOW);}
+inline                         ~LogFlow()                      {logger.undent("", Logger::LOG_FLOW);}
+private:
+               string          str;
+};
+
+#endif // _H_LOGGER
+// ---------------------------------------------------------------------------------------------------------------------------------
+// logger.h - End of file
+// ---------------------------------------------------------------------------------------------------------------------------------
+
diff --git a/Source/md5.h b/Source/md5.h
new file mode 100644 (file)
index 0000000..9a0509b
--- /dev/null
@@ -0,0 +1,110 @@
+// MD5.CC - source code for the C++/object oriented translation and 
+//          modification of MD5.
+
+// Translation and modification (c) 1995 by Mordechai T. Abzug 
+
+// This translation/ modification is provided "as is," without express or 
+// implied warranty of any kind.
+
+// The translator/ modifier does not claim (1) that MD5 will do what you think 
+// it does; (2) that this translation/ modification is accurate; or (3) that 
+// this software is "merchantible."  (Language for this disclaimer partially 
+// copied from the disclaimer below).
+
+/* based on:
+
+   MD5.H - header file for MD5C.C
+   MDDRIVER.C - test driver for MD2, MD4 and MD5
+
+   Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+
+*/
+
+#include <stdio.h>
+#include <fstream>
+#include <iostream>
+
+using namespace std;
+class MD5 {
+
+public:
+// methods for controlled operation:
+  MD5              ();  // simple initializer
+  void  update     (unsigned char *input, unsigned int input_length);
+  void  update     (istream& stream);
+  void  update     (FILE *file);
+  void  update     (ifstream& stream);
+  void  finalize   ();
+
+// constructors for special circumstances.  All these constructors finalize
+// the MD5 context.
+  MD5              (unsigned char *string); // digest string, finalize
+  MD5              (istream& stream);       // digest stream, finalize
+  MD5              (FILE *file);            // digest file, close, finalize
+  MD5              (ifstream& stream);      // digest stream, close, finalize
+
+// methods to acquire finalized result
+  unsigned char    *raw_digest ();  // digest as a 16-byte binary array
+  char *            hex_digest ();  // digest as a 33-byte ascii-hex string
+  friend ostream&   operator<< (ostream&, MD5 context);
+
+
+
+private:
+
+// first, some types:
+  typedef unsigned       int uint4; // assumes integer is 4 words long
+  typedef unsigned short int uint2; // assumes short integer is 2 words long
+  typedef unsigned      char uint1; // assumes char is 1 word long
+
+// next, the private data:
+  uint4 state[4];
+  uint4 count[2];     // number of *bits*, mod 2^64
+  uint1 buffer[64];   // input buffer
+  uint1 digest[16];
+  uint1 finalized;
+
+// last, the private methods, mostly static:
+  void init             ();               // called by all constructors
+  void transform        (uint1 *buffer);  // does the real update work.  Note 
+                                          // that length is implied to be 64.
+
+  static void encode    (uint1 *dest, uint4 *src, uint4 length);
+  static void decode    (uint4 *dest, uint1 *src, uint4 length);
+  static void memcpy    (uint1 *dest, uint1 *src, uint4 length);
+  static void memset    (uint1 *start, uint1 val, uint4 length);
+
+  static inline uint4  rotate_left (uint4 x, uint4 n);
+  static inline uint4  F           (uint4 x, uint4 y, uint4 z);
+  static inline uint4  G           (uint4 x, uint4 y, uint4 z);
+  static inline uint4  H           (uint4 x, uint4 y, uint4 z);
+  static inline uint4  I           (uint4 x, uint4 y, uint4 z);
+  static inline void   FF  (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
+                           uint4 s, uint4 ac);
+  static inline void   GG  (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
+                           uint4 s, uint4 ac);
+  static inline void   HH  (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
+                           uint4 s, uint4 ac);
+  static inline void   II  (uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, 
+                           uint4 s, uint4 ac);
+
+};
\ No newline at end of file
diff --git a/Source/mmgr.cpp b/Source/mmgr.cpp
new file mode 100644 (file)
index 0000000..c45b42b
--- /dev/null
@@ -0,0 +1,1751 @@
+// ---------------------------------------------------------------------------------------------------------------------------------
+//                                                      
+//                                                      
+//  _ __ ___  _ __ ___   __ _ _ __      ___ _ __  _ __  
+// | '_ ` _ \| '_ ` _ \ / _` | '__|    / __| '_ \| '_ \ 
+// | | | | | | | | | | | (_| | |    _ | (__| |_) | |_) |
+// |_| |_| |_|_| |_| |_|\__, |_|   (_) \___| .__/| .__/ 
+//                       __/ |             | |   | |    
+//                      |___/              |_|   |_|    
+//
+// Memory manager & tracking software
+//
+// Best viewed with 8-character tabs and (at least) 132 columns
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+//
+// Restrictions & freedoms pertaining to usage and redistribution of this software:
+//
+//  * This software is 100% free
+//  * If you use this software (in part or in whole) you must credit the author.
+//  * This software may not be re-distributed (in part or in whole) in a modified
+//    form without clear documentation on how to obtain a copy of the original work.
+//  * You may not use this software to directly or indirectly cause harm to others.
+//  * This software is provided as-is and without warrantee. Use at your own risk.
+//
+// For more information, visit HTTP://www.FluidStudios.com
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Originally created on 12/22/2000 by Paul Nettle
+//
+// Copyright 2000, Fluid Studios, Inc., all rights reserved.
+// ---------------------------------------------------------------------------------------------------------------------------------
+//
+// !!IMPORTANT!!
+//
+// This software is self-documented with periodic comments. Before you start using this software, perform a search for the string
+// "-DOC-" to locate pertinent information about how to use this software.
+//
+// You are also encouraged to read the comment blocks throughout this source file. They will help you understand how this memory
+// tracking software works, so you can better utilize it within your applications.
+//
+// NOTES:
+//
+// 1. If you get compiler errors having to do with set_new_handler, then go through this source and search/replace
+//    "std::set_new_handler" with "set_new_handler".
+//
+// 2. This code purposely uses no external routines that allocate RAM (other than the raw allocation routines, such as malloc). We
+//    do this because we want this to be as self-contained as possible. As an example, we don't use assert, because when running
+//    under WIN32, the assert brings up a dialog box, which allocates RAM. Doing this in the middle of an allocation would be bad.
+//
+// 3. When trying to override new/delete under MFC (which has its own version of global new/delete) the linker will complain. In
+//    order to fix this error, use the compiler option: /FORCE, which will force it to build an executable even with linker errors.
+//    Be sure to check those errors each time you compile, otherwise, you may miss a valid linker error.
+//
+// 4. If you see something that looks odd to you or seems like a strange way of going about doing something, then consider that this
+//    code was carefully thought out. If something looks odd, then just assume I've got a good reason for doing it that way (an
+//    example is the use of the class MemStaticTimeTracker.)
+//
+// 5. With MFC applications, you will need to comment out any occurance of "#define new DEBUG_NEW" from all source files.
+//
+// 6. Include file dependencies are _very_important_ for getting the MMGR to integrate nicely into your application. Be careful if
+//    you're including standard includes from within your own project inclues; that will break this very specific dependency order. 
+//    It should look like this:
+//
+//             #include <stdio.h>   // Standard includes MUST come first
+//             #include <stdlib.h>  //
+//             #include <streamio>  //
+//
+//             #include "mmgr.h"    // mmgr.h MUST come next
+//
+//             #include "myfile1.h" // Project includes MUST come last
+//             #include "myfile2.h" //
+//             #include "myfile3.h" //
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+#include <iostream>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+#include <stdarg.h>
+#include <new>
+
+#ifndef        WIN32
+#include <unistd.h>
+#endif
+
+#include "mmgr.h"
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// -DOC- If you're like me, it's hard to gain trust in foreign code. This memory manager will try to INDUCE your code to crash (for
+// very good reasons... like making bugs obvious as early as possible.) Some people may be inclined to remove this memory tracking
+// software if it causes crashes that didn't exist previously. In reality, these new crashes are the BEST reason for using this
+// software!
+//
+// Whether this software causes your application to crash, or if it reports errors, you need to be able to TRUST this software. To
+// this end, you are given some very simple debugging tools.
+// 
+// The quickest way to locate problems is to enable the STRESS_TEST macro (below.) This should catch 95% of the crashes before they
+// occur by validating every allocation each time this memory manager performs an allocation function. If that doesn't work, keep
+// reading...
+//
+// If you enable the TEST_MEMORY_MANAGER #define (below), this memory manager will log an entry in the memory.log file each time it
+// enters and exits one of its primary allocation handling routines. Each call that succeeds should place an "ENTER" and an "EXIT"
+// into the log. If the program crashes within the memory manager, it will log an "ENTER", but not an "EXIT". The log will also
+// report the name of the routine.
+//
+// Just because this memory manager crashes does not mean that there is a bug here! First, an application could inadvertantly damage
+// the heap, causing malloc(), realloc() or free() to crash. Also, an application could inadvertantly damage some of the memory used
+// by this memory tracking software, causing it to crash in much the same way that a damaged heap would affect the standard
+// allocation routines.
+//
+// In the event of a crash within this code, the first thing you'll want to do is to locate the actual line of code that is
+// crashing. You can do this by adding log() entries throughout the routine that crashes, repeating this process until you narrow
+// in on the offending line of code. If the crash happens in a standard C allocation routine (i.e. malloc, realloc or free) don't
+// bother contacting me, your application has damaged the heap. You can help find the culprit in your code by enabling the
+// STRESS_TEST macro (below.)
+//
+// If you truely suspect a bug in this memory manager (and you had better be sure about it! :) you can contact me at
+// midnight@FluidStudios.com. Before you do, however, check for a newer version at:
+//
+//     http://www.FluidStudios.com/publications.html
+//
+// When using this debugging aid, make sure that you are NOT setting the alwaysLogAll variable on, otherwise the log could be
+// cluttered and hard to read.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+//#define      TEST_MEMORY_MANAGER
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// -DOC- Enable this sucker if you really want to stress-test your app's memory usage, or to help find hard-to-find bugs
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+//#define      STRESS_TEST
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// -DOC- Enable this sucker if you want to stress-test your app's error-handling. Set RANDOM_FAIL to the percentage of failures you
+//       want to test with (0 = none, >100 = all failures).
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+//#define      RANDOM_FAILURE 10.0
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// -DOC- Locals -- modify these flags to suit your needs
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+#ifdef STRESS_TEST
+static const   unsigned int    hashBits               = 12;
+static         bool            randomWipe             = true;
+static         bool            alwaysValidateAll      = true;
+static         bool            alwaysLogAll           = true;
+static         bool            alwaysWipeAll          = true;
+static         bool            cleanupLogOnFirstRun   = true;
+static const   unsigned int    paddingSize            = 1024; // An extra 8K per allocation!
+#else
+static const   unsigned int    hashBits               = 12;
+static         bool            randomWipe             = false;
+static         bool            alwaysValidateAll      = false;
+static         bool            alwaysLogAll           = false;
+static         bool            alwaysWipeAll          = true;
+static         bool            cleanupLogOnFirstRun   = true;
+static const   unsigned int    paddingSize            = 4;
+#endif
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// We define our own assert, because we don't want to bring up an assertion dialog, since that allocates RAM. Our new assert
+// simply declares a forced breakpoint.
+//
+// The BEOS assert added by Arvid Norberg <arvid@iname.com>.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+#ifdef WIN32
+       #ifdef  _DEBUG
+       #define m_assert(x) if ((x) == false) __asm { int 3 }
+       #else
+       #define m_assert(x) {}
+       #endif
+#elif defined(__BEOS__)
+       #ifdef DEBUG
+               extern void debugger(const char *message);
+               #define m_assert(x) if ((x) == false) debugger("mmgr: assert failed")
+       #else
+               #define m_assert(x) {}
+       #endif
+#else  // Linux uses assert, which we can use safely, since it doesn't bring up a dialog within the program.
+       #define m_assert(cond) assert(cond)
+#endif
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Here, we turn off our macros because any place in this source file where the word 'new' or the word 'delete' (etc.)
+// appear will be expanded by the macro. So to avoid problems using them within this source file, we'll just #undef them.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+#undef new
+#undef delete
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Defaults for the constants & statics in the MemoryManager class
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+const          unsigned int    m_alloc_unknown        = 0;
+const          unsigned int    m_alloc_new            = 1;
+const          unsigned int    m_alloc_new_array      = 2;
+const          unsigned int    m_alloc_malloc         = 3;
+const          unsigned int    m_alloc_calloc         = 4;
+const          unsigned int    m_alloc_realloc        = 5;
+const          unsigned int    m_alloc_delete         = 6;
+const          unsigned int    m_alloc_delete_array   = 7;
+const          unsigned int    m_alloc_free           = 8;
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// -DOC- Get to know these values. They represent the values that will be used to fill unused and deallocated RAM.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static         unsigned int    prefixPattern          = 0xbaadf00d; // Fill pattern for bytes preceeding allocated blocks
+static         unsigned int    postfixPattern         = 0xdeadc0de; // Fill pattern for bytes following allocated blocks
+static         unsigned int    unusedPattern          = 0xfeedface; // Fill pattern for freshly allocated blocks
+static         unsigned int    releasedPattern        = 0xdeadbeef; // Fill pattern for deallocated blocks
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Other locals
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static const   unsigned int    hashSize               = 1 << hashBits;
+static const   char            *allocationTypes[]     = {"Unknown",
+                                                         "new",     "new[]",  "malloc",   "calloc",
+                                                         "realloc", "delete", "delete[]", "free"};
+static         sAllocUnit      *hashTable[hashSize];
+static         sAllocUnit      *reservoir;
+static         unsigned int    currentAllocationCount = 0;
+static         unsigned int    breakOnAllocationCount = 0;
+static         sMStats         stats;
+static const   char            *sourceFile            = "??";
+static const   char            *sourceFunc            = "??";
+static         unsigned int    sourceLine             = 0;
+static         bool            staticDeinitTime       = false;
+static         sAllocUnit      **reservoirBuffer      = NULL;
+static         unsigned int    reservoirBufferSize    = 0;
+static const   char            *memoryLogFile         = "memory.log";
+static const   char            *memoryLeakLogFile     = "memleaks.log";
+static         void            doCleanupLogOnFirstRun();
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Local functions only
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static void    log(const char *format, ...)
+{
+       // Cleanup the log?
+
+       if (cleanupLogOnFirstRun) doCleanupLogOnFirstRun();
+
+       // Build the buffer
+
+       static char buffer[2048];
+       va_list ap;
+       va_start(ap, format);
+       vsprintf(buffer, format, ap);
+       va_end(ap);
+
+       // Open the log file
+
+       FILE    *fp = fopen(memoryLogFile, "ab");
+
+       // If you hit this assert, then the memory logger is unable to log information to a file (can't open the file for some
+       // reason.) You can interrogate the variable 'buffer' to see what was supposed to be logged (but won't be.)
+       m_assert(fp);
+
+       if (!fp) return;
+
+       // Spit out the data to the log
+
+       fprintf(fp, "%s\r\n", buffer);
+       fclose(fp);
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static void    doCleanupLogOnFirstRun()
+{
+       if (cleanupLogOnFirstRun)
+       {
+               unlink(memoryLogFile);
+               cleanupLogOnFirstRun = false;
+
+               // Print a header for the log
+
+               time_t  t = time(NULL);
+               log("--------------------------------------------------------------------------------");
+               log("");
+               log("      %s - Memory logging file created on %s", memoryLogFile, asctime(localtime(&t)));
+               log("--------------------------------------------------------------------------------");
+               log("");
+               log("This file contains a log of all memory operations performed during the last run.");
+               log("");
+               log("Interrogate this file to track errors or to help track down memory-related");
+               log("issues. You can do this by tracing the allocations performed by a specific owner");
+               log("or by tracking a specific address through a series of allocations and");
+               log("reallocations.");
+               log("");
+               log("There is a lot of useful information here which, when used creatively, can be");
+               log("extremely helpful.");
+               log("");
+               log("Note that the following guides are used throughout this file:");
+               log("");
+               log("   [!] - Error");
+               log("   [+] - Allocation");
+               log("   [~] - Reallocation");
+               log("   [-] - Deallocation");
+               log("   [I] - Generic information");
+               log("   [F] - Failure induced for the purpose of stress-testing your application");
+               log("   [D] - Information used for debugging this memory manager");
+               log("");
+               log("...so, to find all errors in the file, search for \"[!]\"");
+               log("");
+               log("--------------------------------------------------------------------------------");
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static const char      *sourceFileStripper(const char *sourceFile)
+{
+       char    *ptr = strrchr(sourceFile, '\\');
+       if (ptr) return ptr + 1;
+       ptr = strrchr(sourceFile, '/');
+       if (ptr) return ptr + 1;
+       return sourceFile;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static const char      *ownerString(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc)
+{
+       static  char    str[90];
+       memset(str, 0, sizeof(str));
+       sprintf(str, "%s(%05d)::%s", sourceFileStripper(sourceFile), sourceLine, sourceFunc);
+       return str;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static const char      *insertCommas(unsigned int value)
+{
+       static  char    str[30];
+       memset(str, 0, sizeof(str));
+
+       sprintf(str, "%u", value);
+       if (strlen(str) > 3)
+       {
+               memmove(&str[strlen(str)-3], &str[strlen(str)-4], 4);
+               str[strlen(str) - 4] = ',';
+       }
+       if (strlen(str) > 7)
+       {
+               memmove(&str[strlen(str)-7], &str[strlen(str)-8], 8);
+               str[strlen(str) - 8] = ',';
+       }
+       if (strlen(str) > 11)
+       {
+               memmove(&str[strlen(str)-11], &str[strlen(str)-12], 12);
+               str[strlen(str) - 12] = ',';
+       }
+
+       return str;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static const char      *memorySizeString(unsigned long size)
+{
+       static  char    str[90];
+            if (size > (1024*1024))    sprintf(str, "%10s (%7.2fM)", insertCommas(size), static_cast<float>(size) / (1024.0f * 1024.0f));
+       else if (size > 1024)           sprintf(str, "%10s (%7.2fK)", insertCommas(size), static_cast<float>(size) / 1024.0f);
+       else                            sprintf(str, "%10s bytes     ", insertCommas(size));
+       return str;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static sAllocUnit      *findAllocUnit(const void *reportedAddress)
+{
+       // Just in case...
+       m_assert(reportedAddress != NULL);
+
+       // Use the address to locate the hash index. Note that we shift off the lower four bits. This is because most allocated
+       // addresses will be on four-, eight- or even sixteen-byte boundaries. If we didn't do this, the hash index would not have
+       // very good coverage.
+
+       unsigned int    hashIndex = (reinterpret_cast<unsigned int>(const_cast<void *>(reportedAddress)) >> 4) & (hashSize - 1);
+       sAllocUnit      *ptr = hashTable[hashIndex];
+       while(ptr)
+       {
+               if (ptr->reportedAddress == reportedAddress) return ptr;
+               ptr = ptr->next;
+       }
+
+       return NULL;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static size_t  calculateActualSize(const size_t reportedSize)
+{
+       // We use DWORDS as our padding, and a long is guaranteed to be 4 bytes, but an int is not (ANSI defines an int as
+       // being the standard word size for a processor; on a 32-bit machine, that's 4 bytes, but on a 64-bit machine, it's
+       // 8 bytes, which means an int can actually be larger than a long.)
+
+       return reportedSize + paddingSize * sizeof(long) * 2;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static size_t  calculateReportedSize(const size_t actualSize)
+{
+       // We use DWORDS as our padding, and a long is guaranteed to be 4 bytes, but an int is not (ANSI defines an int as
+       // being the standard word size for a processor; on a 32-bit machine, that's 4 bytes, but on a 64-bit machine, it's
+       // 8 bytes, which means an int can actually be larger than a long.)
+
+       return actualSize - paddingSize * sizeof(long) * 2;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static void    *calculateReportedAddress(const void *actualAddress)
+{
+       // We allow this...
+
+       if (!actualAddress) return NULL;
+
+       // JUst account for the padding
+
+       return reinterpret_cast<void *>(const_cast<char *>(reinterpret_cast<const char *>(actualAddress) + sizeof(long) * paddingSize));
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static void    wipeWithPattern(sAllocUnit *allocUnit, unsigned long pattern, const unsigned int originalReportedSize = 0)
+{
+       // For a serious test run, we use wipes of random a random value. However, if this causes a crash, we don't want it to
+       // crash in a differnt place each time, so we specifically DO NOT call srand. If, by chance your program calls srand(),
+       // you may wish to disable that when running with a random wipe test. This will make any crashes more consistent so they
+       // can be tracked down easier.
+
+       if (randomWipe)
+       {
+               pattern = ((rand() & 0xff) << 24) | ((rand() & 0xff) << 16) | ((rand() & 0xff) << 8) | (rand() & 0xff);
+       }
+
+       // -DOC- We should wipe with 0's if we're not in debug mode, so we can help hide bugs if possible when we release the
+       // product. So uncomment the following line for releases.
+       //
+       // Note that the "alwaysWipeAll" should be turned on for this to have effect, otherwise it won't do much good. But we'll
+       // leave it this way (as an option) because this does slow things down.
+//     pattern = 0;
+
+       // This part of the operation is optional
+
+       if (alwaysWipeAll && allocUnit->reportedSize > originalReportedSize)
+       {
+               // Fill the bulk
+
+               long    *lptr = reinterpret_cast<long *>(reinterpret_cast<char *>(allocUnit->reportedAddress) + originalReportedSize);
+               int     length = static_cast<int>(allocUnit->reportedSize - originalReportedSize);
+               int     i;
+               for (i = 0; i < (length >> 2); i++, lptr++)
+               {
+                       *lptr = pattern;
+               }
+
+               // Fill the remainder
+
+               unsigned int    shiftCount = 0;
+               char            *cptr = reinterpret_cast<char *>(lptr);
+               for (i = 0; i < (length & 0x3); i++, cptr++, shiftCount += 8)
+               {
+                       *cptr = static_cast<char>((pattern & (0xff << shiftCount)) >> shiftCount);
+               }
+       }
+
+       // Write in the prefix/postfix bytes
+
+       long            *pre = reinterpret_cast<long *>(allocUnit->actualAddress);
+       long            *post = reinterpret_cast<long *>(reinterpret_cast<char *>(allocUnit->actualAddress) + allocUnit->actualSize - paddingSize * sizeof(long));
+       for (unsigned int i = 0; i < paddingSize; i++, pre++, post++)
+       {
+               *pre = prefixPattern;
+               *post = postfixPattern;
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static void    dumpAllocations(FILE *fp)
+{
+       fprintf(fp, "Alloc.   Addr       Size       Addr       Size                        BreakOn BreakOn              \r\n");
+       fprintf(fp, "Number Reported   Reported    Actual     Actual     Unused    Method  Dealloc Realloc Allocated by \r\n");
+       fprintf(fp, "------ ---------- ---------- ---------- ---------- ---------- -------- ------- ------- --------------------------------------------------- \r\n");
+
+
+       for (unsigned int i = 0; i < hashSize; i++)
+       {
+               sAllocUnit *ptr = hashTable[i];
+               while(ptr)
+               {
+                       fprintf(fp, "%06d 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X %-8s    %c       %c    %s\r\n",
+                               ptr->allocationNumber,
+                               reinterpret_cast<unsigned int>(ptr->reportedAddress), ptr->reportedSize,
+                               reinterpret_cast<unsigned int>(ptr->actualAddress), ptr->actualSize,
+                               m_calcUnused(ptr),
+                               allocationTypes[ptr->allocationType],
+                               ptr->breakOnDealloc ? 'Y':'N',
+                               ptr->breakOnRealloc ? 'Y':'N',
+                               ownerString(ptr->sourceFile, ptr->sourceLine, ptr->sourceFunc));
+                       ptr = ptr->next;
+               }
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static void    dumpLeakReport()
+{
+       // Open the report file
+
+       FILE    *fp = fopen(memoryLeakLogFile, "w+b");
+
+       // If you hit this assert, then the memory report generator is unable to log information to a file (can't open the file for
+       // some reason.)
+       m_assert(fp);
+       if (!fp) return;
+
+       // Any leaks?
+
+       // Header
+
+       static  char    timeString[25];
+       memset(timeString, 0, sizeof(timeString));
+       time_t  t = time(NULL);
+       struct  tm *tme = localtime(&t);
+       fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
+       fprintf(fp, "|                                          Memory leak report for:  %02d/%02d/%04d %02d:%02d:%02d                                            |\r\n", tme->tm_mon + 1, tme->tm_mday, tme->tm_year + 1900, tme->tm_hour, tme->tm_min, tme->tm_sec);
+       fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
+       fprintf(fp, "\r\n");
+       fprintf(fp, "\r\n");
+       if (stats.totalAllocUnitCount)
+       {
+               fprintf(fp, "%d memory leak%s found:\r\n", stats.totalAllocUnitCount, stats.totalAllocUnitCount == 1 ? "":"s");
+       }
+       else
+       {
+               fprintf(fp, "Congratulations! No memory leaks found!\r\n");
+
+               // We can finally free up our own memory allocations
+
+               if (reservoirBuffer)
+               {
+                       for (unsigned int i = 0; i < reservoirBufferSize; i++)
+                       {
+                               free(reservoirBuffer[i]);
+                       }
+                       free(reservoirBuffer);
+                       reservoirBuffer = 0;
+                       reservoirBufferSize = 0;
+                       reservoir = NULL;
+               }
+       }
+       fprintf(fp, "\r\n");
+
+       if (stats.totalAllocUnitCount)
+       {
+               dumpAllocations(fp);
+       }
+
+       fclose(fp);
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// We use a static class to let us know when we're in the midst of static deinitialization
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+class  MemStaticTimeTracker
+{
+public:
+       MemStaticTimeTracker() {doCleanupLogOnFirstRun();}
+       ~MemStaticTimeTracker() {staticDeinitTime = true; dumpLeakReport();}
+};
+static MemStaticTimeTracker    mstt;
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// -DOC- Flags & options -- Call these routines to enable/disable the following options
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+bool   &m_alwaysValidateAll()
+{
+       // Force a validation of all allocation units each time we enter this software
+       return alwaysValidateAll;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+bool   &m_alwaysLogAll()
+{
+       // Force a log of every allocation & deallocation into memory.log
+       return alwaysLogAll;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+bool   &m_alwaysWipeAll()
+{
+       // Force this software to always wipe memory with a pattern when it is being allocated/dallocated
+       return alwaysWipeAll;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+bool   &m_randomeWipe()
+{
+       // Force this software to use a random pattern when wiping memory -- good for stress testing
+       return randomWipe;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// -DOC- Simply call this routine with the address of an allocated block of RAM, to cause it to force a breakpoint when it is
+// reallocated.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+bool   &m_breakOnRealloc(void *reportedAddress)
+{
+       // Locate the existing allocation unit
+
+       sAllocUnit      *au = findAllocUnit(reportedAddress);
+
+       // If you hit this assert, you tried to set a breakpoint on reallocation for an address that doesn't exist. Interrogate the
+       // stack frame or the variable 'au' to see which allocation this is.
+       m_assert(au != NULL);
+
+       // If you hit this assert, you tried to set a breakpoint on reallocation for an address that wasn't allocated in a way that
+       // is compatible with reallocation.
+       m_assert(au->allocationType == m_alloc_malloc ||
+                au->allocationType == m_alloc_calloc ||
+                au->allocationType == m_alloc_realloc);
+
+       return au->breakOnRealloc;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// -DOC- Simply call this routine with the address of an allocated block of RAM, to cause it to force a breakpoint when it is
+// deallocated.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+bool   &m_breakOnDealloc(void *reportedAddress)
+{
+       // Locate the existing allocation unit
+
+       sAllocUnit      *au = findAllocUnit(reportedAddress);
+
+       // If you hit this assert, you tried to set a breakpoint on deallocation for an address that doesn't exist. Interrogate the
+       // stack frame or the variable 'au' to see which allocation this is.
+       m_assert(au != NULL);
+
+       return au->breakOnDealloc;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// -DOC- When tracking down a difficult bug, use this routine to force a breakpoint on a specific allocation count
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   m_breakOnAllocation(unsigned int count)
+{
+       breakOnAllocationCount = count;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Used by the macros
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   m_setOwner(const char *file, const unsigned int line, const char *func)
+{
+       // You're probably wondering about this...
+       //
+       // It's important for this memory manager to primarily work with global new/delete in their original forms (i.e. with
+       // no extra parameters.) In order to do this, we use macros that call this function prior to operators new & delete. This
+       // is fine... usually. Here's what actually happens when you use this macro to delete an object:
+       //
+       // m_setOwner(__FILE__, __LINE__, __FUNCTION__) --> object::~object() --> delete
+       //
+       // Note that the compiler inserts a call to the object's destructor just prior to calling our overridden operator delete.
+       // But what happens when we delete an object whose destructor deletes another object, whose desctuctor deletes another
+       // object? Here's a diagram (indentation follows stack depth):
+       //
+       // m_setOwner(...) -> ~obj1()                          // original call to delete obj1
+       //     m_setOwner(...) -> ~obj2()                      // obj1's destructor deletes obj2
+       //         m_setOwner(...) -> ~obj3()                  // obj2's destructor deletes obj3
+       //             ...                                     // obj3's destructor just does some stuff
+       //         delete                                      // back in obj2's destructor, we call delete
+       //     delete                                          // back in obj1's destructor, we call delete
+       // delete                                              // back to our original call, we call delete
+       //
+       // Because m_setOwner() just sets up some static variables (below) it's important that each call to m_setOwner() and
+       // successive calls to new/delete alternate. However, in this case, three calls to m_setOwner() happen in succession
+       // followed by three calls to delete in succession (with a few calls to destructors mixed in for fun.) This means that
+       // only the final call to delete (in this chain of events) will have the proper reporting, and the first two in the chain
+       // will not have ANY owner-reporting information. The deletes will still work fine, we just won't know who called us.
+       //
+       // "Then build a stack, my friend!" you might think... but it's a very common thing that people will be working with third-
+       // party libraries (including MFC under Windows) which is not compiled with this memory manager's macros. In those cases,
+       // m_setOwner() is never called, and rightfully should not have the proper trace-back information. So if one of the
+       // destructors in the chain ends up being a call to a delete from a non-mmgr-compiled library, the stack will get confused.
+       //
+       // I've been unable to find a solution to this problem, but at least we can detect it and report the data before we
+       // lose it. That's what this is all about. It makes it somewhat confusing to read in the logs, but at least ALL the
+       // information is present...
+       //
+       // There's a caveat here... The compiler is not required to call operator delete if the value being deleted is NULL.
+       // In this case, any call to delete with a NULL will sill call m_setOwner(), which will make m_setOwner() think that
+       // there is a destructor chain becuase we setup the variables, but nothing gets called to clear them. Because of this
+       // we report a "Possible destructor chain".
+       //
+       // Thanks to J. Woznack (from Kodiak Interactive Software Studios -- www.kodiakgames.com) for pointing this out.
+
+       if (sourceLine && alwaysLogAll)
+       {
+               log("[I] NOTE! Possible destructor chain: previous owner is %s", ownerString(sourceFile, sourceLine, sourceFunc));
+       }
+
+       // Okay... save this stuff off so we can keep track of the caller
+
+       sourceFile = file;
+       sourceLine = line;
+       sourceFunc = func;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+static void    resetGlobals()
+{
+       sourceFile = "??";
+       sourceLine = 0;
+       sourceFunc = "??";
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Global new/new[]
+//
+// These are the standard new/new[] operators. They are merely interface functions that operate like normal new/new[], but use our
+// memory tracking routines.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   *operator new(size_t reportedSize)
+{
+       #ifdef TEST_MEMORY_MANAGER
+       log("[D] ENTER: new");
+       #endif
+
+       // Save these off...
+
+       const   char            *file = sourceFile;
+       const   unsigned int    line = sourceLine;
+       const   char            *func = sourceFunc;
+
+       // ANSI says: allocation requests of 0 bytes will still return a valid value
+
+       if (reportedSize == 0) reportedSize = 1;
+
+       // ANSI says: loop continuously because the error handler could possibly free up some memory
+
+       for(;;)
+       {
+               // Try the allocation
+
+               void    *ptr = m_allocator(file, line, func, m_alloc_new, reportedSize);
+               if (ptr)
+               {
+                       #ifdef TEST_MEMORY_MANAGER
+                       log("[D] EXIT : new");
+                       #endif
+                       return ptr;
+               }
+
+               // There isn't a way to determine the new handler, except through setting it. So we'll just set it to NULL, then
+               // set it back again.
+
+               std::new_handler        nh = std::set_new_handler(0);
+               std::set_new_handler(nh);
+
+               // If there is an error handler, call it
+
+               if (nh)
+               {
+                       (*nh)();
+               }
+
+               // Otherwise, throw the exception
+
+               else
+               {
+                       #ifdef TEST_MEMORY_MANAGER
+                       log("[D] EXIT : new");
+                       #endif
+                       throw std::bad_alloc();
+               }
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   *operator new[](size_t reportedSize)
+{
+       #ifdef TEST_MEMORY_MANAGER
+       log("[D] ENTER: new[]");
+       #endif
+
+       // Save these off...
+
+       const   char            *file = sourceFile;
+       const   unsigned int    line = sourceLine;
+       const   char            *func = sourceFunc;
+
+       // The ANSI standard says that allocation requests of 0 bytes will still return a valid value
+
+       if (reportedSize == 0) reportedSize = 1;
+
+       // ANSI says: loop continuously because the error handler could possibly free up some memory
+
+       for(;;)
+       {
+               // Try the allocation
+
+               void    *ptr = m_allocator(file, line, func, m_alloc_new_array, reportedSize);
+               if (ptr)
+               {
+                       #ifdef TEST_MEMORY_MANAGER
+                       log("[D] EXIT : new[]");
+                       #endif
+                       return ptr;
+               }
+
+               // There isn't a way to determine the new handler, except through setting it. So we'll just set it to NULL, then
+               // set it back again.
+
+               std::new_handler        nh = std::set_new_handler(0);
+               std::set_new_handler(nh);
+
+               // If there is an error handler, call it
+
+               if (nh)
+               {
+                       (*nh)();
+               }
+
+               // Otherwise, throw the exception
+
+               else
+               {
+                       #ifdef TEST_MEMORY_MANAGER
+                       log("[D] EXIT : new[]");
+                       #endif
+                       throw std::bad_alloc();
+               }
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Other global new/new[]
+//
+// These are the standard new/new[] operators as used by Microsoft's memory tracker. We don't want them interfering with our memory
+// tracking efforts. Like the previous versions, these are merely interface functions that operate like normal new/new[], but use
+// our memory tracking routines.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   *operator new(size_t reportedSize, const char *sourceFile, int sourceLine)
+{
+       #ifdef TEST_MEMORY_MANAGER
+       log("[D] ENTER: new");
+       #endif
+
+       // The ANSI standard says that allocation requests of 0 bytes will still return a valid value
+
+       if (reportedSize == 0) reportedSize = 1;
+
+       // ANSI says: loop continuously because the error handler could possibly free up some memory
+
+       for(;;)
+       {
+               // Try the allocation
+
+               void    *ptr = m_allocator(sourceFile, sourceLine, "??", m_alloc_new, reportedSize);
+               if (ptr)
+               {
+                       #ifdef TEST_MEMORY_MANAGER
+                       log("[D] EXIT : new");
+                       #endif
+                       return ptr;
+               }
+
+               // There isn't a way to determine the new handler, except through setting it. So we'll just set it to NULL, then
+               // set it back again.
+
+               std::new_handler        nh = std::set_new_handler(0);
+               std::set_new_handler(nh);
+
+               // If there is an error handler, call it
+
+               if (nh)
+               {
+                       (*nh)();
+               }
+
+               // Otherwise, throw the exception
+
+               else
+               {
+                       #ifdef TEST_MEMORY_MANAGER
+                       log("[D] EXIT : new");
+                       #endif
+                       throw std::bad_alloc();
+               }
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   *operator new[](size_t reportedSize, const char *sourceFile, int sourceLine)
+{
+       #ifdef TEST_MEMORY_MANAGER
+       log("[D] ENTER: new[]");
+       #endif
+
+       // The ANSI standard says that allocation requests of 0 bytes will still return a valid value
+
+       if (reportedSize == 0) reportedSize = 1;
+
+       // ANSI says: loop continuously because the error handler could possibly free up some memory
+
+       for(;;)
+       {
+               // Try the allocation
+
+               void    *ptr = m_allocator(sourceFile, sourceLine, "??", m_alloc_new_array, reportedSize);
+               if (ptr)
+               {
+                       #ifdef TEST_MEMORY_MANAGER
+                       log("[D] EXIT : new[]");
+                       #endif
+                       return ptr;
+               }
+
+               // There isn't a way to determine the new handler, except through setting it. So we'll just set it to NULL, then
+               // set it back again.
+
+               std::new_handler        nh = std::set_new_handler(0);
+               std::set_new_handler(nh);
+
+               // If there is an error handler, call it
+
+               if (nh)
+               {
+                       (*nh)();
+               }
+
+               // Otherwise, throw the exception
+
+               else
+               {
+                       #ifdef TEST_MEMORY_MANAGER
+                       log("[D] EXIT : new[]");
+                       #endif
+                       throw std::bad_alloc();
+               }
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Global delete/delete[]
+//
+// These are the standard delete/delete[] operators. They are merely interface functions that operate like normal delete/delete[],
+// but use our memory tracking routines.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   operator delete(void *reportedAddress)
+{
+       #ifdef TEST_MEMORY_MANAGER
+       log("[D] ENTER: delete");
+       #endif
+
+       // ANSI says: delete & delete[] allow NULL pointers (they do nothing)
+
+       if (reportedAddress) m_deallocator(sourceFile, sourceLine, sourceFunc, m_alloc_delete, reportedAddress);
+       else if (alwaysLogAll) log("[-] ----- %8s of NULL                      by %s", allocationTypes[m_alloc_delete], ownerString(sourceFile, sourceLine, sourceFunc));
+
+       // Resetting the globals insures that if at some later time, somebody calls our memory manager from an unknown
+       // source (i.e. they didn't include our H file) then we won't think it was the last allocation.
+
+       resetGlobals();
+
+       #ifdef TEST_MEMORY_MANAGER
+       log("[D] EXIT : delete");
+       #endif
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   operator delete[](void *reportedAddress)
+{
+       #ifdef TEST_MEMORY_MANAGER
+       log("[D] ENTER: delete[]");
+       #endif
+
+       // ANSI says: delete & delete[] allow NULL pointers (they do nothing)
+
+       if (reportedAddress) m_deallocator(sourceFile, sourceLine, sourceFunc, m_alloc_delete_array, reportedAddress);
+       else if (alwaysLogAll)
+               log("[-] ----- %8s of NULL                      by %s", allocationTypes[m_alloc_delete_array], ownerString(sourceFile, sourceLine, sourceFunc));
+
+       // Resetting the globals insures that if at some later time, somebody calls our memory manager from an unknown
+       // source (i.e. they didn't include our H file) then we won't think it was the last allocation.
+
+       resetGlobals();
+
+       #ifdef TEST_MEMORY_MANAGER
+       log("[D] EXIT : delete[]");
+       #endif
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Allocate memory and track it
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   *m_allocator(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc, const unsigned int allocationType, const size_t reportedSize)
+{
+       try
+       {
+               #ifdef TEST_MEMORY_MANAGER
+               log("[D] ENTER: m_allocator()");
+               #endif
+
+               // Increase our allocation count
+
+               currentAllocationCount++;
+
+               // Log the request
+
+               if (alwaysLogAll) log("[+] %05d %8s of size 0x%08X(%08d) by %s", currentAllocationCount, allocationTypes[allocationType], reportedSize, reportedSize, ownerString(sourceFile, sourceLine, sourceFunc));
+
+               // If you hit this assert, you requested a breakpoint on a specific allocation count
+               m_assert(currentAllocationCount != breakOnAllocationCount);
+
+               // If necessary, grow the reservoir of unused allocation units
+
+               if (!reservoir)
+               {
+                       // Allocate 256 reservoir elements
+
+                       reservoir = (sAllocUnit *) malloc(sizeof(sAllocUnit) * 256);
+
+                       // If you hit this assert, then the memory manager failed to allocate internal memory for tracking the
+                       // allocations
+                       m_assert(reservoir != NULL);
+
+                       // Danger Will Robinson!
+
+                       if (reservoir == NULL) throw "Unable to allocate RAM for internal memory tracking data";
+
+                       // Build a linked-list of the elements in our reservoir
+
+                       memset(reservoir, 0, sizeof(sAllocUnit) * 256);
+                       for (unsigned int i = 0; i < 256 - 1; i++)
+                       {
+                               reservoir[i].next = &reservoir[i+1];
+                       }
+
+                       // Add this address to our reservoirBuffer so we can free it later
+
+                       sAllocUnit      **temp = (sAllocUnit **) realloc(reservoirBuffer, (reservoirBufferSize + 1) * sizeof(sAllocUnit *));
+                       m_assert(temp);
+                       if (temp)
+                       {
+                               reservoirBuffer = temp;
+                               reservoirBuffer[reservoirBufferSize++] = reservoir;
+                       }
+               }
+
+               // Logical flow says this should never happen...
+               m_assert(reservoir != NULL);
+
+               // Grab a new allocaton unit from the front of the reservoir
+
+               sAllocUnit      *au = reservoir;
+               reservoir = au->next;
+
+               // Populate it with some real data
+
+               memset(au, 0, sizeof(sAllocUnit));
+               au->actualSize        = calculateActualSize(reportedSize);
+               #ifdef RANDOM_FAILURE
+               double  a = rand();
+               double  b = RAND_MAX / 100.0 * RANDOM_FAILURE;
+               if (a > b)
+               {
+                       au->actualAddress = malloc(au->actualSize);
+               }
+               else
+               {
+                       log("[F] Random faiure");
+                       au->actualAddress = NULL;
+               }
+               #else
+               au->actualAddress     = malloc(au->actualSize);
+               #endif
+               au->reportedSize      = reportedSize;
+               au->reportedAddress   = calculateReportedAddress(au->actualAddress);
+               au->allocationType    = allocationType;
+               au->sourceLine        = sourceLine;
+               au->allocationNumber  = currentAllocationCount;
+               if (sourceFile) strncpy(au->sourceFile, sourceFileStripper(sourceFile), sizeof(au->sourceFile) - 1);
+               else            strcpy (au->sourceFile, "??");
+               if (sourceFunc) strncpy(au->sourceFunc, sourceFunc, sizeof(au->sourceFunc) - 1);
+               else            strcpy (au->sourceFunc, "??");
+
+               // We don't want to assert with random failures, because we want the application to deal with them.
+
+               #ifndef RANDOM_FAILURE
+               // If you hit this assert, then the requested allocation simply failed (you're out of memory.) Interrogate the
+               // variable 'au' or the stack frame to see what you were trying to do.
+               m_assert(au->actualAddress != NULL);
+               #endif
+
+               if (au->actualAddress == NULL)
+               {
+                       throw "Request for allocation failed. Out of memory.";
+               }
+
+               // If you hit this assert, then this allocation was made from a source that isn't setup to use this memory tracking
+               // software, use the stack frame to locate the source and include our H file.
+               m_assert(allocationType != m_alloc_unknown);
+
+               // Insert the new allocation into the hash table
+
+               unsigned int    hashIndex = (reinterpret_cast<unsigned int>(au->reportedAddress) >> 4) & (hashSize - 1);
+               if (hashTable[hashIndex]) hashTable[hashIndex]->prev = au;
+               au->next = hashTable[hashIndex];
+               au->prev = NULL;
+               hashTable[hashIndex] = au;
+
+               // Account for the new allocatin unit in our stats
+
+               stats.totalReportedMemory += static_cast<unsigned int>(au->reportedSize);
+               stats.totalActualMemory   += static_cast<unsigned int>(au->actualSize);
+               stats.totalAllocUnitCount++;
+               if (stats.totalReportedMemory > stats.peakReportedMemory) stats.peakReportedMemory = stats.totalReportedMemory;
+               if (stats.totalActualMemory   > stats.peakActualMemory)   stats.peakActualMemory   = stats.totalActualMemory;
+               if (stats.totalAllocUnitCount > stats.peakAllocUnitCount) stats.peakAllocUnitCount = stats.totalAllocUnitCount;
+               stats.accumulatedReportedMemory += static_cast<unsigned int>(au->reportedSize);
+               stats.accumulatedActualMemory += static_cast<unsigned int>(au->actualSize);
+               stats.accumulatedAllocUnitCount++;
+
+               // Prepare the allocation unit for use (wipe it with recognizable garbage)
+
+               wipeWithPattern(au, unusedPattern);
+
+               // calloc() expects the reported memory address range to be filled with 0's
+
+               if (allocationType == m_alloc_calloc)
+               {
+                       memset(au->reportedAddress, 0, au->reportedSize);
+               }
+
+               // Validate every single allocated unit in memory
+
+               if (alwaysValidateAll) m_validateAllAllocUnits();
+
+               // Log the result
+
+               if (alwaysLogAll) log("[+] ---->             addr 0x%08X", reinterpret_cast<unsigned int>(au->reportedAddress));
+
+               // Resetting the globals insures that if at some later time, somebody calls our memory manager from an unknown
+               // source (i.e. they didn't include our H file) then we won't think it was the last allocation.
+
+               resetGlobals();
+
+               // Return the (reported) address of the new allocation unit
+
+               #ifdef TEST_MEMORY_MANAGER
+               log("[D] EXIT : m_allocator()");
+               #endif
+
+               return au->reportedAddress;
+       }
+       catch(const char *err)
+       {
+               // Deal with the errors
+
+               log("[!] %s", err);
+               resetGlobals();
+
+               #ifdef TEST_MEMORY_MANAGER
+               log("[D] EXIT : m_allocator()");
+               #endif
+
+               return NULL;
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Reallocate memory and track it
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   *m_reallocator(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc, const unsigned int reallocationType, const size_t reportedSize, void *reportedAddress)
+{
+       try
+       {
+               #ifdef TEST_MEMORY_MANAGER
+               log("[D] ENTER: m_reallocator()");
+               #endif
+
+               // Calling realloc with a NULL should force same operations as a malloc
+
+               if (!reportedAddress)
+               {
+                       return m_allocator(sourceFile, sourceLine, sourceFunc, reallocationType, reportedSize);
+               }
+
+               // Increase our allocation count
+
+               currentAllocationCount++;
+
+               // If you hit this assert, you requested a breakpoint on a specific allocation count
+               m_assert(currentAllocationCount != breakOnAllocationCount);
+
+               // Log the request
+
+               if (alwaysLogAll) log("[~] %05d %8s of size 0x%08X(%08d) by %s", currentAllocationCount, allocationTypes[reallocationType], reportedSize, reportedSize, ownerString(sourceFile, sourceLine, sourceFunc));
+
+               // Locate the existing allocation unit
+
+               sAllocUnit      *au = findAllocUnit(reportedAddress);
+
+               // If you hit this assert, you tried to reallocate RAM that wasn't allocated by this memory manager.
+               m_assert(au != NULL);
+               if (au == NULL) throw "Request to reallocate RAM that was never allocated";
+
+               // If you hit this assert, then the allocation unit that is about to be reallocated is damaged. But you probably
+               // already know that from a previous assert you should have seen in validateAllocUnit() :)
+               m_assert(m_validateAllocUnit(au));
+
+               // If you hit this assert, then this reallocation was made from a source that isn't setup to use this memory
+               // tracking software, use the stack frame to locate the source and include our H file.
+               m_assert(reallocationType != m_alloc_unknown);
+
+               // If you hit this assert, you were trying to reallocate RAM that was not allocated in a way that is compatible with
+               // realloc. In other words, you have a allocation/reallocation mismatch.
+               m_assert(au->allocationType == m_alloc_malloc ||
+                        au->allocationType == m_alloc_calloc ||
+                        au->allocationType == m_alloc_realloc);
+
+               // If you hit this assert, then the "break on realloc" flag for this allocation unit is set (and will continue to be
+               // set until you specifically shut it off. Interrogate the 'au' variable to determine information about this
+               // allocation unit.
+               m_assert(au->breakOnRealloc == false);
+
+               // Keep track of the original size
+
+               unsigned int    originalReportedSize = static_cast<unsigned int>(au->reportedSize);
+
+               if (alwaysLogAll) log("[~] ---->             from 0x%08X(%08d)", originalReportedSize, originalReportedSize);
+
+               // Do the reallocation
+
+               void    *oldReportedAddress = reportedAddress;
+               size_t  newActualSize = calculateActualSize(reportedSize);
+               void    *newActualAddress = NULL;
+               #ifdef RANDOM_FAILURE
+               double  a = rand();
+               double  b = RAND_MAX / 100.0 * RANDOM_FAILURE;
+               if (a > b)
+               {
+                       newActualAddress = realloc(au->actualAddress, newActualSize);
+               }
+               else
+               {
+                       log("[F] Random faiure");
+               }
+               #else
+               newActualAddress = realloc(au->actualAddress, newActualSize);
+               #endif
+
+               // We don't want to assert with random failures, because we want the application to deal with them.
+
+               #ifndef RANDOM_FAILURE
+               // If you hit this assert, then the requested allocation simply failed (you're out of memory) Interrogate the
+               // variable 'au' to see the original allocation. You can also query 'newActualSize' to see the amount of memory
+               // trying to be allocated. Finally, you can query 'reportedSize' to see how much memory was requested by the caller.
+               m_assert(newActualAddress);
+               #endif
+
+               if (!newActualAddress) throw "Request for reallocation failed. Out of memory.";
+
+               // Remove this allocation from our stats (we'll add the new reallocation again later)
+
+               stats.totalReportedMemory -= static_cast<unsigned int>(au->reportedSize);
+               stats.totalActualMemory   -= static_cast<unsigned int>(au->actualSize);
+
+               // Update the allocation with the new information
+
+               au->actualSize        = newActualSize;
+               au->actualAddress     = newActualAddress;
+               au->reportedSize      = calculateReportedSize(newActualSize);
+               au->reportedAddress   = calculateReportedAddress(newActualAddress);
+               au->allocationType    = reallocationType;
+               au->sourceLine        = sourceLine;
+               au->allocationNumber  = currentAllocationCount;
+               if (sourceFile) strncpy(au->sourceFile, sourceFileStripper(sourceFile), sizeof(au->sourceFile) - 1);
+               else            strcpy (au->sourceFile, "??");
+               if (sourceFunc) strncpy(au->sourceFunc, sourceFunc, sizeof(au->sourceFunc) - 1);
+               else            strcpy (au->sourceFunc, "??");
+
+               // The reallocation may cause the address to change, so we should relocate our allocation unit within the hash table
+
+               unsigned int    hashIndex = static_cast<unsigned int>(-1);
+               if (oldReportedAddress != au->reportedAddress)
+               {
+                       // Remove this allocation unit from the hash table
+
+                       {
+                               unsigned int    hashIndex = (reinterpret_cast<unsigned int>(oldReportedAddress) >> 4) & (hashSize - 1);
+                               if (hashTable[hashIndex] == au)
+                               {
+                                       hashTable[hashIndex] = hashTable[hashIndex]->next;
+                               }
+                               else
+                               {
+                                       if (au->prev)   au->prev->next = au->next;
+                                       if (au->next)   au->next->prev = au->prev;
+                               }
+                       }
+
+                       // Re-insert it back into the hash table
+
+                       hashIndex = (reinterpret_cast<unsigned int>(au->reportedAddress) >> 4) & (hashSize - 1);
+                       if (hashTable[hashIndex]) hashTable[hashIndex]->prev = au;
+                       au->next = hashTable[hashIndex];
+                       au->prev = NULL;
+                       hashTable[hashIndex] = au;
+               }
+
+               // Account for the new allocatin unit in our stats
+
+               stats.totalReportedMemory += static_cast<unsigned int>(au->reportedSize);
+               stats.totalActualMemory   += static_cast<unsigned int>(au->actualSize);
+               if (stats.totalReportedMemory > stats.peakReportedMemory) stats.peakReportedMemory = stats.totalReportedMemory;
+               if (stats.totalActualMemory   > stats.peakActualMemory)   stats.peakActualMemory   = stats.totalActualMemory;
+               int     deltaReportedSize = static_cast<int>(reportedSize - originalReportedSize);
+               if (deltaReportedSize > 0)
+               {
+                       stats.accumulatedReportedMemory += deltaReportedSize;
+                       stats.accumulatedActualMemory += deltaReportedSize;
+               }
+
+               // Prepare the allocation unit for use (wipe it with recognizable garbage)
+
+               wipeWithPattern(au, unusedPattern, originalReportedSize);
+
+               // If you hit this assert, then something went wrong, because the allocation unit was properly validated PRIOR to
+               // the reallocation. This should not happen.
+               m_assert(m_validateAllocUnit(au));
+
+               // Validate every single allocated unit in memory
+
+               if (alwaysValidateAll) m_validateAllAllocUnits();
+
+               // Log the result
+
+               if (alwaysLogAll) log("[~] ---->             addr 0x%08X", reinterpret_cast<unsigned int>(au->reportedAddress));
+
+               // Resetting the globals insures that if at some later time, somebody calls our memory manager from an unknown
+               // source (i.e. they didn't include our H file) then we won't think it was the last allocation.
+
+               resetGlobals();
+
+               // Return the (reported) address of the new allocation unit
+
+               #ifdef TEST_MEMORY_MANAGER
+               log("[D] EXIT : m_reallocator()");
+               #endif
+
+               return au->reportedAddress;
+       }
+       catch(const char *err)
+       {
+               // Deal with the errors
+
+               log("[!] %s", err);
+               resetGlobals();
+
+               #ifdef TEST_MEMORY_MANAGER
+               log("[D] EXIT : m_reallocator()");
+               #endif
+
+               return NULL;
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Deallocate memory and track it
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   m_deallocator(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc, const unsigned int deallocationType, const void *reportedAddress)
+{
+       try
+       {
+               #ifdef TEST_MEMORY_MANAGER
+               log("[D] ENTER: m_deallocator()");
+               #endif
+
+               // Log the request
+
+               if (alwaysLogAll) log("[-] ----- %8s of addr 0x%08X           by %s", allocationTypes[deallocationType], reinterpret_cast<unsigned int>(const_cast<void *>(reportedAddress)), ownerString(sourceFile, sourceLine, sourceFunc));
+
+               // We should only ever get here with a null pointer if they try to do so with a call to free() (delete[] and delete will
+               // both bail before they get here.) So, since ANSI allows free(NULL), we'll not bother trying to actually free the allocated
+               // memory or track it any further.
+
+               if (reportedAddress)
+               {
+                       // Go get the allocation unit
+
+                       sAllocUnit      *au = findAllocUnit(reportedAddress);
+
+                       // If you hit this assert, you tried to deallocate RAM that wasn't allocated by this memory manager.
+                       m_assert(au != NULL);
+                       if (au == NULL) throw "Request to deallocate RAM that was never allocated";
+
+                       // If you hit this assert, then the allocation unit that is about to be deallocated is damaged. But you probably
+                       // already know that from a previous assert you should have seen in validateAllocUnit() :)
+                       m_assert(m_validateAllocUnit(au));
+
+                       // If you hit this assert, then this deallocation was made from a source that isn't setup to use this memory
+                       // tracking software, use the stack frame to locate the source and include our H file.
+                       m_assert(deallocationType != m_alloc_unknown);
+
+                       // If you hit this assert, you were trying to deallocate RAM that was not allocated in a way that is compatible with
+                       // the deallocation method requested. In other words, you have a allocation/deallocation mismatch.
+                       m_assert((deallocationType == m_alloc_delete       && au->allocationType == m_alloc_new      ) ||
+                               (deallocationType == m_alloc_delete_array && au->allocationType == m_alloc_new_array) ||
+                               (deallocationType == m_alloc_free         && au->allocationType == m_alloc_malloc   ) ||
+                               (deallocationType == m_alloc_free         && au->allocationType == m_alloc_calloc   ) ||
+                               (deallocationType == m_alloc_free         && au->allocationType == m_alloc_realloc  ) ||
+                               (deallocationType == m_alloc_unknown                                                ) );
+
+                       // If you hit this assert, then the "break on dealloc" flag for this allocation unit is set. Interrogate the 'au'
+                       // variable to determine information about this allocation unit.
+                       m_assert(au->breakOnDealloc == false);
+
+                       // Wipe the deallocated RAM with a new pattern. This doen't actually do us much good in debug mode under WIN32,
+                       // because Microsoft's memory debugging & tracking utilities will wipe it right after we do. Oh well.
+
+                       wipeWithPattern(au, releasedPattern);
+
+                       // Do the deallocation
+
+                       free(au->actualAddress);
+
+                       // Remove this allocation unit from the hash table
+
+                       unsigned int    hashIndex = (reinterpret_cast<unsigned int>(au->reportedAddress) >> 4) & (hashSize - 1);
+                       if (hashTable[hashIndex] == au)
+                       {
+                               hashTable[hashIndex] = au->next;
+                       }
+                       else
+                       {
+                               if (au->prev)   au->prev->next = au->next;
+                               if (au->next)   au->next->prev = au->prev;
+                       }
+
+                       // Remove this allocation from our stats
+
+                       stats.totalReportedMemory -= static_cast<unsigned int>(au->reportedSize);
+                       stats.totalActualMemory   -= static_cast<unsigned int>(au->actualSize);
+                       stats.totalAllocUnitCount--;
+
+                       // Add this allocation unit to the front of our reservoir of unused allocation units
+
+                       memset(au, 0, sizeof(sAllocUnit));
+                       au->next = reservoir;
+                       reservoir = au;
+               }
+
+               // Resetting the globals insures that if at some later time, somebody calls our memory manager from an unknown
+               // source (i.e. they didn't include our H file) then we won't think it was the last allocation.
+
+               resetGlobals();
+
+               // Validate every single allocated unit in memory
+
+               if (alwaysValidateAll) m_validateAllAllocUnits();
+
+               // If we're in the midst of static deinitialization time, track any pending memory leaks
+
+               if (staticDeinitTime) dumpLeakReport();
+       }
+       catch(const char *err)
+       {
+               // Deal with errors
+
+               log("[!] %s", err);
+               resetGlobals();
+       }
+
+       #ifdef TEST_MEMORY_MANAGER
+       log("[D] EXIT : m_deallocator()");
+       #endif
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// -DOC- The following utilitarian allow you to become proactive in tracking your own memory, or help you narrow in on those tough
+// bugs.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+bool   m_validateAddress(const void *reportedAddress)
+{
+       // Just see if the address exists in our allocation routines
+
+       return findAllocUnit(reportedAddress) != NULL;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+bool   m_validateAllocUnit(const sAllocUnit *allocUnit)
+{
+       // Make sure the padding is untouched
+
+       long    *pre = reinterpret_cast<long *>(allocUnit->actualAddress);
+       long    *post = reinterpret_cast<long *>((char *)allocUnit->actualAddress + allocUnit->actualSize - paddingSize * sizeof(long));
+       bool    errorFlag = false;
+       for (unsigned int i = 0; i < paddingSize; i++, pre++, post++)
+       {
+               if (*pre != (long) prefixPattern)
+               {
+                       log("[!] A memory allocation unit was corrupt because of an underrun:");
+                       m_dumpAllocUnit(allocUnit, "  ");
+                       errorFlag = true;
+               }
+
+               // If you hit this assert, then you should know that this allocation unit has been damaged. Something (possibly the
+               // owner?) has underrun the allocation unit (modified a few bytes prior to the start). You can interrogate the
+               // variable 'allocUnit' to see statistics and information about this damaged allocation unit.
+               m_assert(*pre == static_cast<long>(prefixPattern));
+
+               if (*post != static_cast<long>(postfixPattern))
+               {
+                       log("[!] A memory allocation unit was corrupt because of an overrun:");
+                       m_dumpAllocUnit(allocUnit, "  ");
+                       errorFlag = true;
+               }
+
+               // If you hit this assert, then you should know that this allocation unit has been damaged. Something (possibly the
+               // owner?) has overrun the allocation unit (modified a few bytes after the end). You can interrogate the variable
+               // 'allocUnit' to see statistics and information about this damaged allocation unit.
+               m_assert(*post == static_cast<long>(postfixPattern));
+       }
+
+       // Return the error status (we invert it, because a return of 'false' means error)
+
+       return !errorFlag;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+bool   m_validateAllAllocUnits()
+{
+       // Just go through each allocation unit in the hash table and count the ones that have errors
+
+       unsigned int    errors = 0;
+       unsigned int    allocCount = 0;
+       for (unsigned int i = 0; i < hashSize; i++)
+       {
+               sAllocUnit      *ptr = hashTable[i];
+               while(ptr)
+               {
+                       allocCount++;
+                       if (!m_validateAllocUnit(ptr)) errors++;
+                       ptr = ptr->next;
+               }
+       }
+
+       // Test for hash-table correctness
+
+       if (allocCount != stats.totalAllocUnitCount)
+       {
+               log("[!] Memory tracking hash table corrupt!");
+               errors++;
+       }
+
+       // If you hit this assert, then the internal memory (hash table) used by this memory tracking software is damaged! The
+       // best way to track this down is to use the alwaysLogAll flag in conjunction with STRESS_TEST macro to narrow in on the
+       // offending code. After running the application with these settings (and hitting this assert again), interrogate the
+       // memory.log file to find the previous successful operation. The corruption will have occurred between that point and this
+       // assertion.
+       m_assert(allocCount == stats.totalAllocUnitCount);
+
+       // If you hit this assert, then you've probably already been notified that there was a problem with a allocation unit in a
+       // prior call to validateAllocUnit(), but this assert is here just to make sure you know about it. :)
+       m_assert(errors == 0);
+
+       // Log any errors
+
+       if (errors) log("[!] While validting all allocation units, %d allocation unit(s) were found to have problems", errors);
+
+       // Return the error status
+
+       return errors != 0;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// -DOC- Unused RAM calculation routines. Use these to determine how much of your RAM is unused (in bytes)
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+unsigned int   m_calcUnused(const sAllocUnit *allocUnit)
+{
+       const unsigned long     *ptr = reinterpret_cast<const unsigned long *>(allocUnit->reportedAddress);
+       unsigned int            count = 0;
+
+       for (unsigned int i = 0; i < allocUnit->reportedSize; i += sizeof(long), ptr++)
+       {
+               if (*ptr == unusedPattern) count += sizeof(long);
+       }
+
+       return count;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+unsigned int   m_calcAllUnused()
+{
+       // Just go through each allocation unit in the hash table and count the unused RAM
+
+       unsigned int    total = 0;
+       for (unsigned int i = 0; i < hashSize; i++)
+       {
+               sAllocUnit      *ptr = hashTable[i];
+               while(ptr)
+               {
+                       total += m_calcUnused(ptr);
+                       ptr = ptr->next;
+               }
+       }
+
+       return total;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// -DOC- The following functions are for logging and statistics reporting.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   m_dumpAllocUnit(const sAllocUnit *allocUnit, const char *prefix)
+{
+       log("[I] %sAddress (reported): %010p",       prefix, allocUnit->reportedAddress);
+       log("[I] %sAddress (actual)  : %010p",       prefix, allocUnit->actualAddress);
+       log("[I] %sSize (reported)   : 0x%08X (%s)", prefix, static_cast<unsigned int>(allocUnit->reportedSize), memorySizeString(static_cast<unsigned int>(allocUnit->reportedSize)));
+       log("[I] %sSize (actual)     : 0x%08X (%s)", prefix, static_cast<unsigned int>(allocUnit->actualSize), memorySizeString(static_cast<unsigned int>(allocUnit->actualSize)));
+       log("[I] %sOwner             : %s(%d)::%s",  prefix, allocUnit->sourceFile, allocUnit->sourceLine, allocUnit->sourceFunc);
+       log("[I] %sAllocation type   : %s",          prefix, allocationTypes[allocUnit->allocationType]);
+       log("[I] %sAllocation number : %d",          prefix, allocUnit->allocationNumber);
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   m_dumpMemoryReport(const char *filename, const bool overwrite)
+{
+       // Open the report file
+
+       FILE    *fp = NULL;
+       
+       if (overwrite)  fp = fopen(filename, "w+b");
+       else            fp = fopen(filename, "ab");
+
+       // If you hit this assert, then the memory report generator is unable to log information to a file (can't open the file for
+       // some reason.)
+       m_assert(fp);
+       if (!fp) return;
+
+        // Header
+
+        static  char    timeString[25];
+        memset(timeString, 0, sizeof(timeString));
+        time_t  t = time(NULL);
+        struct  tm *tme = localtime(&t);
+       fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
+        fprintf(fp, "|                                             Memory report for: %02d/%02d/%04d %02d:%02d:%02d                                               |\r\n", tme->tm_mon + 1, tme->tm_mday, tme->tm_year + 1900, tme->tm_hour, tme->tm_min, tme->tm_sec);
+       fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
+       fprintf(fp, "\r\n");
+       fprintf(fp, "\r\n");
+
+       // Report summary
+
+       fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
+       fprintf(fp, "|                                                           T O T A L S                                                            |\r\n");
+       fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
+       fprintf(fp, "              Allocation unit count: %10s\r\n", insertCommas(stats.totalAllocUnitCount));
+       fprintf(fp, "            Reported to application: %s\r\n", memorySizeString(stats.totalReportedMemory));
+       fprintf(fp, "         Actual total memory in use: %s\r\n", memorySizeString(stats.totalActualMemory));
+       fprintf(fp, "           Memory tracking overhead: %s\r\n", memorySizeString(stats.totalActualMemory - stats.totalReportedMemory));
+       fprintf(fp, "\r\n");
+
+       fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
+       fprintf(fp, "|                                                            P E A K S                                                             |\r\n");
+       fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
+       fprintf(fp, "              Allocation unit count: %10s\r\n", insertCommas(stats.peakAllocUnitCount));
+       fprintf(fp, "            Reported to application: %s\r\n", memorySizeString(stats.peakReportedMemory));
+       fprintf(fp, "                             Actual: %s\r\n", memorySizeString(stats.peakActualMemory));
+       fprintf(fp, "           Memory tracking overhead: %s\r\n", memorySizeString(stats.peakActualMemory - stats.peakReportedMemory));
+       fprintf(fp, "\r\n");
+
+       fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
+       fprintf(fp, "|                                                      A C C U M U L A T E D                                                       |\r\n");
+       fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
+       fprintf(fp, "              Allocation unit count: %s\r\n", memorySizeString(stats.accumulatedAllocUnitCount));
+       fprintf(fp, "            Reported to application: %s\r\n", memorySizeString(stats.accumulatedReportedMemory));
+       fprintf(fp, "                             Actual: %s\r\n", memorySizeString(stats.accumulatedActualMemory));
+       fprintf(fp, "\r\n");
+
+       fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
+       fprintf(fp, "|                                                           U N U S E D                                                            |\r\n");
+       fprintf(fp, " ---------------------------------------------------------------------------------------------------------------------------------- \r\n");
+       fprintf(fp, "    Memory allocated but not in use: %s\r\n", memorySizeString(m_calcAllUnused()));
+       fprintf(fp, "\r\n");
+
+       dumpAllocations(fp);
+
+       fclose(fp);
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+sMStats        m_getMemoryStatistics()
+{
+       return stats;
+}
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// mmgr.cpp - End of file
+// ---------------------------------------------------------------------------------------------------------------------------------
diff --git a/Source/mmgr.h b/Source/mmgr.h
new file mode 100644 (file)
index 0000000..4e683a5
--- /dev/null
@@ -0,0 +1,165 @@
+// ---------------------------------------------------------------------------------------------------------------------------------
+//                                     _     
+//                                    | |    
+//  _ __ ___  _ __ ___   __ _ _ __    | |__  
+// | '_ ` _ \| '_ ` _ \ / _` | '__|   | '_ \ 
+// | | | | | | | | | | | (_| | |    _ | | | |
+// |_| |_| |_|_| |_| |_|\__, |_|   (_)|_| |_|
+//                       __/ |               
+//                      |___/                
+//
+// Memory manager & tracking software
+//
+// Best viewed with 8-character tabs and (at least) 132 columns
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+//
+// Restrictions & freedoms pertaining to usage and redistribution of this software:
+//
+//  * This software is 100% free
+//  * If you use this software (in part or in whole) you must credit the author.
+//  * This software may not be re-distributed (in part or in whole) in a modified
+//    form without clear documentation on how to obtain a copy of the original work.
+//  * You may not use this software to directly or indirectly cause harm to others.
+//  * This software is provided as-is and without warrantee. Use at your own risk.
+//
+// For more information, visit HTTP://www.FluidStudios.com
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Originally created on 12/22/2000 by Paul Nettle
+//
+// Copyright 2000, Fluid Studios, Inc., all rights reserved.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+#ifndef        _H_MMGR
+#define        _H_MMGR
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// For systems that don't have the __FUNCTION__ variable, we can just define it here
+// ---------------------------------------------------------------------------------------------------------------------------------
+#ifndef __FUNCTION__
+#define        __FUNCTION__ "??"
+#endif
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Types
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+typedef        struct tag_au
+{
+       size_t          actualSize;
+       size_t          reportedSize;
+       void            *actualAddress;
+       void            *reportedAddress;
+       char            sourceFile[40];
+       char            sourceFunc[40];
+       unsigned int    sourceLine;
+       unsigned int    allocationType;
+       bool            breakOnDealloc;
+       bool            breakOnRealloc;
+       unsigned int    allocationNumber;
+       struct tag_au   *next;
+       struct tag_au   *prev;
+} sAllocUnit;
+
+typedef        struct
+{
+       unsigned int    totalReportedMemory;
+       unsigned int    totalActualMemory;
+       unsigned int    peakReportedMemory;
+       unsigned int    peakActualMemory;
+       unsigned int    accumulatedReportedMemory;
+       unsigned int    accumulatedActualMemory;
+       unsigned int    accumulatedAllocUnitCount;
+       unsigned int    totalAllocUnitCount;
+       unsigned int    peakAllocUnitCount;
+} sMStats;
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// External constants
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+extern const   unsigned int    m_alloc_unknown;
+extern const   unsigned int    m_alloc_new;
+extern const   unsigned int    m_alloc_new_array;
+extern const   unsigned int    m_alloc_malloc;
+extern const   unsigned int    m_alloc_calloc;
+extern const   unsigned int    m_alloc_realloc;
+extern const   unsigned int    m_alloc_delete;
+extern const   unsigned int    m_alloc_delete_array;
+extern const   unsigned int    m_alloc_free;
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Used by the macros
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void           m_setOwner(const char *file, const unsigned int line, const char *func);
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Allocation breakpoints
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+bool           &m_breakOnRealloc(void *reportedAddress);
+bool           &m_breakOnDealloc(void *reportedAddress);
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// The meat of the memory tracking software
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void           *m_allocator(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc,
+                            const unsigned int allocationType, const size_t reportedSize);
+void           *m_reallocator(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc,
+                              const unsigned int reallocationType, const size_t reportedSize, void *reportedAddress);
+void           m_deallocator(const char *sourceFile, const unsigned int sourceLine, const char *sourceFunc,
+                             const unsigned int deallocationType, const void *reportedAddress);
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Utilitarian functions
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+bool           m_validateAddress(const void *reportedAddress);
+bool           m_validateAllocUnit(const sAllocUnit *allocUnit);
+bool           m_validateAllAllocUnits();
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Unused RAM calculations
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+unsigned int   m_calcUnused(const sAllocUnit *allocUnit);
+unsigned int   m_calcAllUnused();
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Logging and reporting
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void           m_dumpAllocUnit(const sAllocUnit *allocUnit, const char *prefix = "");
+void           m_dumpMemoryReport(const char *filename = "memreport.log", const bool overwrite = true);
+sMStats                m_getMemoryStatistics();
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Variations of global operators new & delete
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+void   *operator new(size_t reportedSize);
+void   *operator new[](size_t reportedSize);
+void   *operator new(size_t reportedSize, const char *sourceFile, int sourceLine);
+void   *operator new[](size_t reportedSize, const char *sourceFile, int sourceLine);
+void   operator delete(void *reportedAddress);
+void   operator delete[](void *reportedAddress);
+
+#endif // _H_MMGR
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Macros -- "Kids, please don't try this at home. We're trained professionals here." :)
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+#include "nommgr.h"
+#define        new             (m_setOwner  (__FILE__,__LINE__,__FUNCTION__),false) ? NULL : new
+#define        delete          (m_setOwner  (__FILE__,__LINE__,__FUNCTION__),false) ? m_setOwner("",0,"") : delete
+#define        malloc(sz)      m_allocator  (__FILE__,__LINE__,__FUNCTION__,m_alloc_malloc,sz)
+#define        calloc(sz)      m_allocator  (__FILE__,__LINE__,__FUNCTION__,m_alloc_calloc,sz)
+#define        realloc(ptr,sz) m_reallocator(__FILE__,__LINE__,__FUNCTION__,m_alloc_realloc,sz,ptr)
+#define        free(ptr)       m_deallocator(__FILE__,__LINE__,__FUNCTION__,m_alloc_free,ptr)
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// mmgr.h - End of file
+// ---------------------------------------------------------------------------------------------------------------------------------
diff --git a/Source/nommgr.h b/Source/nommgr.h
new file mode 100644 (file)
index 0000000..8356b89
--- /dev/null
@@ -0,0 +1,60 @@
+// ---------------------------------------------------------------------------------------------------------------------------------
+//                                                 _     
+//                                                | |    
+//  _ __   ___  _ __ ___  _ __ ___   __ _ _ __    | |__  
+// | '_ \ / _ \| '_ ` _ \| '_ ` _ \ / _` | '__|   | '_ \ 
+// | | | | (_) | | | | | | | | | | | (_| | |    _ | | | |
+// |_| |_|\___/|_| |_| |_|_| |_| |_|\__, |_|   (_)|_| |_|
+//                                   __/ |               
+//                                  |___/                
+//
+// Memory manager & tracking software
+//
+// Best viewed with 8-character tabs and (at least) 132 columns
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+//
+// Restrictions & freedoms pertaining to usage and redistribution of this software:
+//
+//  * This software is 100% free
+//  * If you use this software (in part or in whole) you must credit the author.
+//  * This software may not be re-distributed (in part or in whole) in a modified
+//    form without clear documentation on how to obtain a copy of the original work.
+//  * You may not use this software to directly or indirectly cause harm to others.
+//  * This software is provided as-is and without warrantee. Use at your own risk.
+//
+// For more information, visit HTTP://www.FluidStudios.com
+//
+// ---------------------------------------------------------------------------------------------------------------------------------
+// Originally created on 12/22/2000 by Paul Nettle
+//
+// Copyright 2000, Fluid Studios, Inc., all rights reserved.
+// ---------------------------------------------------------------------------------------------------------------------------------
+
+#ifdef new
+#undef new
+#endif
+
+#ifdef delete
+#undef delete
+#endif
+
+#ifdef malloc
+#undef malloc
+#endif
+
+#ifdef calloc
+#undef calloc
+#endif
+
+#ifdef realloc
+#undef realloc
+#endif
+
+#ifdef free
+#undef free
+#endif
+
+// ---------------------------------------------------------------------------------------------------------------------------------
+// nommgr.h - End of file
+// ---------------------------------------------------------------------------------------------------------------------------------
diff --git a/Source/nsp_network.c b/Source/nsp_network.c
new file mode 100644 (file)
index 0000000..28a8c43
--- /dev/null
@@ -0,0 +1,720 @@
+/*
+ * Copyright (c) 2002 Lane Roathe. All rights reserved.
+ *     Developed in cooperation with Freeverse, Inc.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * Portions Copyright (c) 1999-2002 Apple Computer, Inc.  All Rights
+ * Reserved.  This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.1 (the "License").  You may not use this file
+ * except in compliance with the License.  Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ *
+ * Modified: $Date: 2002/04/27 21:42:01 $
+ * Revision: $Id: nsp_network.c,v 1.1 2002/04/27 21:42:01 lane Exp $
+ */
+
+/* NOTES:
+
+       - This example is designed so that all networking code is in this one file. The purpose is to make
+               it easier for a programmer to study the basic use of OpenPlay's NetSprocket API and not to
+               demonstrate good programming style or OOP practices.
+
+       - This file is not game independent (hey, that's what OpenPlay is about!), it simply helped me keep
+               the example use of NetSprocket's more managable ... I hope :)
+
+       - I wanted the host (ie, server) to also be a player, and found it was pretty easy to do; I simply
+               made sure that I tracked whether I was a server or client (see the _server variable in main.h) and
+               then when sending all players a message I had to modify the "to" portion of the header and
+               resend it to the host. This means the host is sending itself messages, which works great.
+
+*/
+
+/* ----------------------------------------------------------- Includes */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "main.h"
+
+#include "network.h"
+
+/* ----------------------------------------------------------- Macro definitions */
+
+enum
+{
+       kMessageType_Question = 256,
+       kMessageType_Answer,
+
+       kMessageType_Information
+};
+
+#define kPlayerType 1234       /* just defines a way to allow/reject players of different types */
+
+
+/* ----------------------------------------------------------- Type definitions */
+
+/* Questions are sent out in message packets from server to players */
+
+/* NOTE        Message string is ZERO terminated!      */
+/*             This allows us to strcpy, strcmp, etc. on raw packet data       */
+/*             Meaning packet size = sizeof(packet_t) + strlen(string) */
+
+typedef struct
+{
+       NSpMessageHeader  header;
+
+       char            str[1];                 /* message (question, info, etc) string */
+
+}MessagePacket_t, *MessagePacketPtr;
+
+/* Answers are sent from the players to the server in this packet */
+
+typedef struct
+{
+       NSpMessageHeader  header;
+
+       char            answer;                 /* finally, the answer */
+
+}AnswerPacket_t, *AnswerPacketPtr;
+
+/* ----------------------------------------------------------- Local Variables */
+
+/* name of this version of the app*/
+char *GameNameStr = "OpenPlay NSp API Example 1";
+
+/* Local vars used to handle our interaction with OpenPlay's NetSprockets API */
+
+static NSpGameReference                        _gameReference = NULL;          /* general game info */
+static NSpProtocolListReference        _protocolListRef = NULL;        /* list of protocols we've started up */
+
+static NMBoolean _approved;            /* after requesting to join a new game, this tracks whether or not we were approved */
+static NMBoolean _response;            /* true if we get a response following a request to join a new game (else we time out */
+
+/*--------------------------------------------------------------------------------*/
+/*--------------------------------------------------------------------------------*/
+#if __MWERKS__
+       #pragma mark -
+       #pragma mark Ãˆ Local Routines
+       #pragma mark -
+#endif
+
+
+/*--------------------------------------------------------------------------------*/
+/*--------------------------------------------------------------------------------*/
+#if __MWERKS__
+       #pragma mark -
+       #pragma mark Ãˆ Global Routines
+       #pragma mark -
+#endif
+
+unsigned char *GameC2PStr
+(
+       char *s,                        /* source C string */
+       unsigned char *d        /* destination buffer for Pascal string */
+)
+{
+       int c = 0;
+
+       if( s && d )    /* make sure we got got inputs */
+       {
+               while( *s )
+                       d[++c] = (unsigned char)*s++;   /* no blockmove, copy & get length in one shot */
+       }
+       *d = (unsigned char)c;
+
+       return( d );
+}
+
+char *GameP2CStr
+(
+       unsigned char *s,       /* source Pascal string */
+       char *d                         /* buffer to hold converted C string */
+)
+{
+       if( s && d )
+       {
+               memcpy( d, s+1, *s );   /* pretty simple */
+               d[*s] = 0;
+       }
+       return( d );
+}
+
+/* ================================================================================
+       Handle all of the network messages that are sent to this application
+
+        EXIT:  0 == no error, else error code
+*/
+
+void NetworkHandleMessage( void )
+{
+       NSpMessageHeader *mhp;
+       char str[256];                          /* buffer for converted PStrings */
+
+       /* Ask NetSprocket to give us a message if any are waiting */
+
+       mhp = NSpMessage_Get( _gameReference );
+       if( mhp )
+       {
+               /* Print out the type of message received */
+
+               switch(mhp -> what)
+               {
+
+/* --- Handle NetSprocket's generic messages */
+
+                       case kNSpJoinApproved:
+                               printf( "Approved!\n\n", str );
+                               fflush(stdout);
+                               _response = true;
+                               _approved = true;       /* tell our waiting loop that we were approved */
+#if __USE_SIOUX__
+                               {
+                                       NMErr err;
+
+                                       err = NSpGame_GetInfo( _gameReference, &gameInfo );
+                                       if( !err )
+                                               SIOUXSetTitle( gameInfo.name );
+                               }
+#endif
+                               break;
+                       
+                       case kNSpJoinDenied:
+                               GameP2CStr( ((NSpJoinDeniedMessage *)mhp)->reason, str );
+                               printf( "Denied!\n   Reason: %s\n\n", str );
+                               fflush(stdout);
+                               //GameOver();
+
+                               _response = true;
+                               _approved = false;      /* tell our waiting loop we were denied */
+                               break;
+
+                       case kNSpError:
+                               printf( "*** ERROR *** (reported value: %d)\n\n", ((NSpErrorMessage *)mhp)->error );
+                               fflush(stdout);
+
+                               _response = true;
+                               _approved = false;
+                               break;
+                       
+                       case kNSpGameTerminated:
+                               printf( "--- Host Terminated Game ---\n\n" );
+                               fflush(stdout);
+                               //GameOver();
+
+                               _response = true;
+                               _approved = false;
+                               break;
+
+                       case kNSpPlayerJoined:
+                       {
+                               NSpGameInfo gameInfo;
+                               char gamename[256];
+                               NMErr err;
+
+                               err = NSpGame_GetInfo( _gameReference, &gameInfo );
+                               if( !err )
+                                       GameP2CStr( gameInfo.name, gamename );
+                               else
+                                       strcpy( gamename, "ERRROR" );
+
+                               GameP2CStr( ((NSpPlayerJoinedMessage *)mhp)->playerInfo.name, str );
+                               printf( "===> Player %s joined game '%s', %d players now!\n\n",
+                                               str, gamename, ((NSpPlayerJoinedMessage *)mhp)->playerCount );
+                               fflush(stdout);
+
+                               /* Lets go ahead and re-send the current question, as the new guy deserves a shot at it too */
+                               /*if( GameIsHost() )
+                               {
+                                       //QuestionPtr theQuestion = GameGetCurrentQuestion();
+                                       //if (theQuestion)
+                                       //      NetworkSendQuestion(theQuestion->question);
+                               }*/
+                       }
+                       break;
+
+                       case kNSpPlayerLeft:
+                               GameP2CStr( ((NSpPlayerLeftMessage *)mhp)->playerName, str );
+                               printf( "===> Player, %s, Left game, leaving %d players!\n\n",
+                                               str, ((NSpPlayerLeftMessage *)mhp)->playerCount );
+                               fflush(stdout);
+                               break;
+
+                       case kNSpHostChanged:
+                               printf( "===> ??? Host changed to player ID %d\n\n",
+                                               ((NSpHostChangedMessage *)mhp)->newHost );
+                               fflush(stdout);
+                               break;
+
+                       case kNSpGroupCreated:
+                               printf( "===> Player #%d created a new Group, ID %d\n\n",
+                                               ((NSpCreateGroupMessage *)mhp)->requestingPlayer, ((NSpCreateGroupMessage *)mhp)->groupID );
+                               fflush(stdout);
+                               break;
+
+                       case kNSpGroupDeleted:
+                               printf( "===> Player #%d deleted group #%d\n\n",
+                                               ((NSpDeleteGroupMessage *)mhp)->requestingPlayer, ((NSpDeleteGroupMessage *)mhp)->groupID );
+                               fflush(stdout);
+                               break;
+                       
+                       case kNSpPlayerAddedToGroup:
+                               printf( "===> Player %d was added to group %d\n\n",
+                                               ((NSpAddPlayerToGroupMessage *)mhp)->player, ((NSpAddPlayerToGroupMessage *)mhp)->group );
+                               fflush(stdout);
+                               break;
+
+                       case kNSpPlayerRemovedFromGroup:
+                               printf( "===> Player %d was removed from group %d\n\n",
+                                               ((NSpRemovePlayerFromGroupMessage *)mhp)->player, ((NSpRemovePlayerFromGroupMessage *)mhp)->group );
+                               fflush(stdout);
+                               break;
+
+                       case kNSpPlayerTypeChanged:
+                               printf( "===> Player %d changed to a new type, %d\n\n",
+                                               ((NSpPlayerTypeChangedMessage *)mhp)->player, ((NSpPlayerTypeChangedMessage *)mhp)->newType );
+                               break;
+
+
+/* --- Handle our game specific messages */
+
+
+                       /* Got a message, see if it is correct or not and let everyone know the results */
+
+                       case kMessageType_Answer:
+                       {
+                               NSpPlayerInfoPtr pip;
+                               char cname[kNSpStr32Len];
+                               NMErr err;
+
+                               err = NSpPlayer_GetInfo( _gameReference, mhp->from, &pip );
+                               if( !err )
+                               {               
+                                       GameP2CStr( pip->name, cname );
+
+                                       NSpPlayer_ReleaseInfo( _gameReference, pip );
+                               }
+                               else
+                                       strcpy( cname, "UNKOWN -- error!" );
+
+                               //sprintf( str, "Player #%d, %s, answered with '%c', which is %s", mhp->from, cname, ((AnswerPacketPtr)mhp)->answer,
+                                       //GameCheckAnswer( ((AnswerPacketPtr)mhp)->answer ) ? "Correct!" : "WRONG!" );
+
+                               NetworkSendInformation( str );
+                       }
+                       break;
+
+                       /* allow game to do any special processing needed when a question arrives */
+
+                       case kMessageType_Question:
+                               //GameDisplayQuestion( ((MessagePacketPtr)mhp)->str );
+                               break;
+
+                       /* pretty simple, just display the info message */
+
+                       case kMessageType_Information:
+                               printf( "%s\n\n", ((MessagePacketPtr)mhp)->str );
+                               fflush(stdout);
+                               break;
+
+                       default:
+                               break;
+               }
+
+               /* Once done with it, release the message */
+
+               NSpMessage_Release( _gameReference, mhp );
+       }
+}
+
+/* ================================================================================
+       Return the # of players in the current game
+
+        EXIT:  none
+*/
+
+NMUInt32 NetworkGetPlayerCount( void )
+{
+       NSpGameInfo gameInfo;
+       NMErr err;
+
+       err = NSpGame_GetInfo( _gameReference, &gameInfo );     /* player count is in the game info record */
+       if( !err )
+       {
+               return( gameInfo.currentPlayers );
+       }
+
+       return( 0 );
+}
+
+/* ================================================================================
+       Send an answer to the server
+
+        EXIT:  none
+*/
+
+NMErr NetworkSendAnswer
+(
+       char answer                     /* the answer to send (just a char!) */
+)
+{
+       AnswerPacket_t answerPacket;
+       NMErr err;
+
+       /* init the NetSprocket portion of the packet */
+
+       NSpClearMessageHeader( &answerPacket.header );
+
+       answerPacket.header.what = kMessageType_Answer;
+       answerPacket.header.to = kNSpHostOnly;
+       answerPacket.header.messageLen = sizeof(answerPacket);
+
+       /* fill in the data section */
+
+       answerPacket.answer = answer;
+
+       /* tell NetSprocket to send the message */
+
+       err = NSpMessage_Send( _gameReference, &answerPacket.header, kNSpSendFlag_Registered );
+       if( err )
+       {
+               printf( "*** ERROR *** Unable to send answer packet, error # %d\n\n", err );
+               fflush(stdout);
+       }
+
+       return( err );
+}
+
+/* ================================================================================
+       Send a message to all players
+
+        EXIT:  none
+*/
+
+NMErr NetworkSendPlayerMessage
+(
+       const char *message,            /* ptr to message string to send */
+       NMUInt32 messageType            /* type of message (question, info, etc. */
+)
+{
+       MessagePacketPtr qpp;
+       unsigned long messageLen, size;
+       NMErr err;
+
+       /* sanity checks */
+
+       if( !message )
+               return( kNSpInvalidParameterErr );
+
+       /* get size of message string & total size of network packet */
+
+       messageLen = strlen( message );
+       size = sizeof(MessagePacket_t) + messageLen + 1;        /* header + num_chars + terminator */
+
+       /* allocate the memory for the packet */
+
+       qpp = (MessagePacketPtr)malloc( size );
+       if( !qpp )
+       {
+               printf( " *** ERROR *** Unable to allocate message buffer!\n\n" );
+               fflush(stdout);
+               return( kNSpMemAllocationErr );
+       }
+
+       /* init the NetSprocket portion of the packet */
+
+       NSpClearMessageHeader( &qpp->header );
+
+       qpp->header.what = (NMSInt32)messageType;
+       qpp->header.to = kNSpAllPlayers;
+       qpp->header.messageLen = size;
+
+       /* fill in the data section */
+
+       strcpy( qpp->str, message );
+
+       /* tell NetSprocket to send the message */
+
+       err = NSpMessage_Send( _gameReference, &qpp->header, kNSpSendFlag_Registered );
+       if( !err )
+       {
+               qpp->header.to = kNSpHostOnly;          /* allow host to play as well! */
+
+               err = NSpMessage_Send( _gameReference, &qpp->header, kNSpSendFlag_Registered );
+       }
+
+       if( err )
+       {
+               printf( "*** ERROR *** Unable to send message packet, error # %d\n\n", err );
+               fflush(stdout);
+       }
+
+       /* clean up after ourselves! */
+
+       free( qpp );
+
+       return( err );
+}
+
+/* ================================================================================
+       Send a question to all players
+
+        EXIT:  none
+*/
+
+NMErr NetworkSendQuestion
+(
+       const char *question    /* ptr to question string to send */
+)
+{
+       return( NetworkSendPlayerMessage( question, kMessageType_Question ) );
+}
+
+/* ================================================================================
+       Send information to all players
+
+        EXIT:  none
+*/
+
+NMErr NetworkSendInformation
+(
+       const char *message             /* ptr to information string to send */
+)
+{
+       return( NetworkSendPlayerMessage( message, kMessageType_Information ) );
+}
+
+#if __MWERKS__
+       #pragma mark -
+#endif
+
+/* ================================================================================
+       Initialize server networking
+
+        EXIT:  0 == no error, else error code
+*/
+
+NMErr NetworkStartServer
+(
+       NMUInt16 port,                                  /* port clients will connect on */
+       NMUInt32 maxPlayers,                    /* max # of players to allow into game */
+       const unsigned char *gameName,  /* name of game (displayed to clients on connect) */
+       const unsigned char *playerName /* name of player on server computer */
+)
+{
+       NSpProtocolReference protocolRef;
+       NMErr err;
+
+       /* Create a new protocol list to store our IP protocol reference in */
+
+       err = NSpProtocolList_New( NULL, &_protocolListRef );
+       if( !err )
+       {
+               /* Create a protocol reference for our IP connection, on our specified port w/default maxRTT and throughput */
+
+               protocolRef = NSpProtocol_CreateIP( port, 0, 0 );
+               if( protocolRef )
+               {
+                       /* We got a good reference, append it to the list we created earlier */
+
+                       err = NSpProtocolList_Append( _protocolListRef, protocolRef );
+                       if( !err )
+                       {
+                               /* We got a protocol and it's in our reference list, now we can create the game
+                                       to host, using the parms sent in and defaulting rest of the "unused" hosting parms */
+
+                               err = NSpGame_Host( &_gameReference, _protocolListRef, maxPlayers, gameName,
+                                                                       "\pPassword", playerName, kPlayerType, kNSpClientServer, 0 );
+                       }
+               }
+               else
+                       err = kNSpInvalidProtocolRefErr;        /* assign somewhat meaningful error on failure to create protocol reference */
+       }
+
+       return( err );
+}
+
+
+/* ================================================================================
+       Shutdown the networking, release resources, etc.
+
+        EXIT:  0 == no error, else error code
+*/
+
+NMErr NetworkStartClient
+(
+       char *ipAddr,                                   /* IP address (or domain name) to look for server (host) on */
+       char *port,                                             /* Port to talk to server via */
+       const unsigned char *playerName /* name of player wanting to join */
+)
+{
+       NSpAddressReference addRef;
+       NMErr err;
+
+       /* Given our input strings, create an OpenPlay address reference for talking to server */
+
+       addRef = NSpCreateIPAddressReference( ipAddr, port );
+       if( addRef )
+       {
+               printf( "\nAttempting to join game..." );
+               fflush(stdout);
+
+               /* Now, look for a server on the IP/Port given and see if we can connect */
+
+               err = NSpGame_Join( &_gameReference, addRef, playerName, "\pPassword", kPlayerType, NULL, 0, 0 );
+               if( !err )
+               {
+                       NMUInt32 startTime, currentTime;
+                       time_t seconds;
+
+                       printf( "connected!\n\nWaiting for approval to join game (press 'q' to quit)..." );
+                       fflush(stdout);
+
+                       time(&seconds);
+                       startTime = seconds;
+
+                       _response = _approved = false;
+
+                       /* We connected, now we have to wait for the server to approve our join request */
+
+                       while( !_response )
+                       {
+                               /* Check for a time out in connecting to server */
+                               /* this is before the event handler so that we are not approved, but time out anyway (small chance, but...) */
+
+                               time(&seconds);
+                               currentTime = seconds;
+
+                               if( (currentTime - startTime > 60) && (!_response) )
+                               {
+                                       printf( "ERROR: Connection timed out!\n\n" );
+                                       fflush(stdout);
+
+                                       _response = true;
+                                       _approved = false;
+                               }
+
+                               /* Handle system messages and allow user to quit via 'q' */
+                               /* This also gets and handles network messages, like accept/deny */
+
+                               //GameHandleEvents();
+                       }
+
+                       /* if we were not approved, we must dispose of the game object here */
+
+                       if( !_approved )
+                       {
+                               err = NSpGame_Dispose( _gameReference, kNSpGameFlag_ForceTerminateGame );
+                               _gameReference = NULL;
+                       }
+                       else    /* let the user know that they were accepted to the game */
+                       {
+                               NSpGameInfo gameInfo;
+                               char str[256];
+
+                               err = NSpGame_GetInfo( _gameReference, &gameInfo );
+                               if( !err )
+                               {
+                                       GameP2CStr( gameInfo.name, str );
+
+                                       printf( "   Welcome to the game '%s', with %d players\n\n", str, (int)gameInfo.currentPlayers );
+                                       fflush(stdout);
+                               }
+                       }
+               }
+       }
+       else
+               err = kNMParameterErr;
+
+       return( err );
+}
+
+
+#if __MWERKS__
+       #pragma mark -
+#endif
+
+/* ================================================================================
+       Shutdown the networking, release resources, etc.
+
+        EXIT:  0 == no error, else error code
+*/
+
+NMErr NetworkShutdown( void )
+{
+       NMUInt32 refCount;
+       NMErr err = kNMNoError;
+
+       /* if we have a game object (we should!) dispose if it now */
+
+       if( _gameReference )
+               err = NSpGame_Dispose( _gameReference, kNSpGameFlag_ForceTerminateGame );
+
+       /* dispose of our protocol references & the list containing them */
+
+       if( _protocolListRef )
+       {
+               NSpProtocolReference pRef;
+
+               refCount = NSpProtocolList_GetCount( _protocolListRef );        /* get number of protocols */
+
+               while( refCount-- && !err )
+               {
+                       pRef = NSpProtocolList_GetIndexedRef( _protocolListRef, refCount );     /* get currect reference */
+
+                       err = NSpProtocolList_RemoveIndexed( _protocolListRef, refCount );      /* then remove it from the list */
+
+                       /* now, we can dispose of the reference safely */
+                       NSpProtocol_Dispose( pRef );    /* this should have an NMErr return, but has a void return... */
+               }
+
+               /* once all of the protocols are disposed, we can dispose of the containing reference list */
+               NSpProtocolList_Dispose( _protocolListRef );
+       }
+
+
+       /* Make sure we can't use old values */
+
+       _protocolListRef = NULL;
+       _gameReference = NULL;
+       
+       return( err );
+}
+
+/* ================================================================================
+       Startup the networking system (NetSprockets in this case)
+
+        EXIT:  0 == no error, else error code
+*/
+
+NMErr NetworkStartup( void )
+{
+       NMErr err;
+
+       /* First, make sure that NetSprockets is available (we weak linked to OpenPlayStubLib) */
+
+       if( NULL == NSpInitialize )     /*|| NULL == ProtocolAcceptConnection )*/
+               return( errModuleNotFound );
+
+       /* Initialize NetSprockets, 0 == use defaults & NSe1 stands for "NetSprocket Example 1" 
+                       It is an identifier for games of our type on the network */
+
+       err = NSpInitialize( 0, 0, 0, 'NSe1', 0 );
+
+       return( err );
+}
diff --git a/Source/pack.c b/Source/pack.c
new file mode 100644 (file)
index 0000000..14fc023
--- /dev/null
@@ -0,0 +1,53 @@
+#include <stdlib.h>
+
+#include "binio.h"
+#include "private.h"
+#include "pack_private.h"
+
+extern void packf(const char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    vfpackf(stdout, format, args);
+    va_end(args);
+}
+
+extern void spackf(void *buffer, const char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    vspackf(buffer, format, args);
+    va_end(args);
+}
+
+extern void fpackf(FILE *file, const char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    vfpackf(file, format, args);
+    va_end(args);
+}
+
+extern void vspackf(void *buffer, const char *format, va_list args)
+{
+    struct BinIOFormatCursor cursor;
+    struct BinIOPackContext context;
+
+    BinIOInitFormatCursor(&cursor, format);
+
+    context.buffer = (unsigned char *)buffer;
+    context.args = args;
+    
+    while (BinIONextChar(&context, &cursor, BinIOPack)) {}
+}
+
+extern void vfpackf(FILE *file, const char *format, va_list args)
+{
+    size_t n_bytes = BinIOFormatByteCount(format);
+    void* buffer = malloc(n_bytes);
+    
+    vspackf(buffer, format, args);
+    
+    fwrite(buffer, n_bytes, 1, file);
+    free(buffer);
+}
diff --git a/Source/pack_private.c b/Source/pack_private.c
new file mode 100644 (file)
index 0000000..480e2ae
--- /dev/null
@@ -0,0 +1,72 @@
+#include "pack_private.h"
+
+void BinIOPack(void *context, int type, int byte_order, int count)
+{
+    struct BinIOPackContext *ctx = (struct BinIOPackContext*)context;
+    if (count == -1)
+    {
+        switch (type)
+        {
+            case BinIO_TYPE_IGNORE_BYTE:
+                {
+                    ctx->buffer += 1;
+                }
+                break;
+            case BinIO_TYPE_BYTE:
+                {
+                    uint8_t value = va_arg(ctx->args, int);
+                    BinIOConvert1(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
+                    ctx->buffer += 1;
+                }
+                break;
+            case BinIO_TYPE_INT16:
+                {
+                    uint16_t value = va_arg(ctx->args, int);
+                    BinIOConvert2(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
+                    ctx->buffer += 2;
+                }
+                break;
+            case BinIO_TYPE_INT32:
+                {
+                    int value = va_arg(ctx->args, int);
+                    BinIOConvert4(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
+                    ctx->buffer += 4;
+                }
+                break;
+            case BinIO_TYPE_INT64:
+                {
+                    uint64_t value = va_arg(ctx->args, uint64_t);
+                    BinIOConvert8(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
+                    ctx->buffer += 8;
+                }
+                break;
+            case BinIO_TYPE_FLOAT32:
+                {
+                    float32_t value = (float32_t)va_arg(ctx->args, double);
+                    BinIOConvert4(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
+                    ctx->buffer += 4;
+                }
+                break;
+            case BinIO_TYPE_FLOAT64:
+                {
+                    float64_t value = va_arg(ctx->args, float64_t);
+                    BinIOConvert8(BinIO_HOST_BYTE_ORDER, byte_order, (const uint8_t *)&value, ctx->buffer, 1);
+                    ctx->buffer += 8;
+                }
+                break;
+        }
+    }
+    else
+    {
+        switch (type)
+        {
+            case BinIO_TYPE_IGNORE_BYTE:                                                                                                     ctx->buffer += 1 * count; break;
+            case BinIO_TYPE_BYTE:        BinIOConvert1(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count); ctx->buffer += 1 * count; break;
+            case BinIO_TYPE_INT16:       BinIOConvert2(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count); ctx->buffer += 2 * count; break;
+            case BinIO_TYPE_INT32:       BinIOConvert4(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count); ctx->buffer += 4 * count; break;
+            case BinIO_TYPE_INT64:       BinIOConvert8(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count); ctx->buffer += 8 * count; break;
+            case BinIO_TYPE_FLOAT32:     BinIOConvert4(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count); ctx->buffer += 4 * count; break;
+            case BinIO_TYPE_FLOAT64:     BinIOConvert8(BinIO_HOST_BYTE_ORDER, byte_order, va_arg(ctx->args, uint8_t *), ctx->buffer, count); ctx->buffer += 8 * count; break;
+        }
+    }
+}
diff --git a/Source/pack_private.h b/Source/pack_private.h
new file mode 100644 (file)
index 0000000..58d3753
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef pack_private_h
+#define pack_private_h
+
+#include "private.h"
+
+struct BinIOPackContext
+{
+    uint8_t *buffer;
+    va_list  args;
+};
+
+extern void BinIOPack(void *context, int type, int byte_order, int count);
+
+#endif
diff --git a/Source/private.c b/Source/private.c
new file mode 100644 (file)
index 0000000..e50c68a
--- /dev/null
@@ -0,0 +1,181 @@
+#include <string.h>
+
+#include "private.h"
+
+void BinIOConvert1(int from_byte_order, int to_byte_order,
+                   const uint8_t *src, uint8_t *dst,
+                   unsigned int count)
+{
+    if (BinIONormalizeByteOrder(from_byte_order) !=
+        BinIONormalizeByteOrder(to_byte_order))
+    {
+        unsigned int i;
+        for (i = 0; i < count; ++i)
+        {
+            BinIOSwap1(src, dst);
+            src += 1;
+            dst += 1;
+        }
+    }
+    else
+    {
+        memcpy(dst, src, 1 * count);
+    }
+}
+
+void BinIOConvert2(int from_byte_order, int to_byte_order,
+                   const uint8_t *src, uint8_t *dst,
+                   unsigned int count)
+{
+    if (BinIONormalizeByteOrder(from_byte_order) !=
+        BinIONormalizeByteOrder(to_byte_order))
+    {
+        unsigned int i;
+        for (i = 0; i < count; ++i)
+        {
+            BinIOSwap2(src, dst);
+            src += 2;
+            dst += 2;
+        }
+    }
+    else
+    {
+        memcpy(dst, src, 2 * count);
+    }
+}
+
+void BinIOConvert4(int from_byte_order, int to_byte_order,
+                   const uint8_t *src, uint8_t *dst,
+                   unsigned int count)
+{
+    if (BinIONormalizeByteOrder(from_byte_order) !=
+        BinIONormalizeByteOrder(to_byte_order))
+    {
+        unsigned int i;
+        for (i = 0; i < count; ++i)
+        {
+            BinIOSwap4(src, dst);
+            src += 4;
+            dst += 4;
+        }
+    }
+    else
+    {
+        memcpy(dst, src, 4 * count);
+    }
+}
+
+void BinIOConvert8(int from_byte_order, int to_byte_order,
+                   const uint8_t *src, uint8_t *dst,
+                   unsigned int count)
+{
+    if (BinIONormalizeByteOrder(from_byte_order) !=
+        BinIONormalizeByteOrder(to_byte_order))
+    {
+        unsigned int i;
+        for (i = 0; i < count; ++i)
+        {
+            BinIOSwap8(src, dst);
+            src += 8;
+            dst += 8;
+        }
+    }
+    else
+    {
+        memcpy(dst, src, 8 * count);
+    }
+}
+
+void BinIOInitFormatCursor(struct BinIOFormatCursor *cursor,
+                           const char               *format)
+{
+    cursor->cursor = format;
+    cursor->byte_order = BinIO_HOST_BYTE_ORDER;
+    cursor->count = -1;
+}
+
+int BinIONextChar(void                     *context,
+                  struct BinIOFormatCursor *cursor,
+                  BinIOProcessFunction      func)
+{
+    int count, value;
+    int c;
+    switch (c = *(cursor->cursor)++)
+    {
+        case BinIO_LITTLE_ENDIAN_BYTE_ORDER:
+        case BinIO_BIG_ENDIAN_BYTE_ORDER:
+        case BinIO_HOST_BYTE_ORDER:
+        case BinIO_NETWORK_BYTE_ORDER:
+            cursor->byte_order = c;
+            break;
+        
+        case '0': case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+            count = cursor->count;
+            value = c - '0';
+            if (count == -1)
+            {
+                cursor->count = value;
+            }
+            else
+            {
+                cursor->count = (count * 10) + value;
+            }
+            break;
+            
+        case BinIO_TYPE_IGNORE_BYTE:
+        case BinIO_TYPE_BYTE:
+        case BinIO_TYPE_INT16:
+        case BinIO_TYPE_INT32:
+        case BinIO_TYPE_INT64:
+        case BinIO_TYPE_FLOAT32:
+        case BinIO_TYPE_FLOAT64:
+            func(context, c, cursor->byte_order, cursor->count);
+            cursor->byte_order = BinIO_HOST_BYTE_ORDER;
+            cursor->count = -1;
+            break;
+            
+        case ' ': case '\t': case '\r': case '\n':
+            break;
+            
+        default:
+            return 0;
+    }
+    
+    return 1;
+}
+
+extern void BinIOCountBytes(void *context, int type, int byte_order, int count)
+{
+    size_t type_size = 0;
+    
+    if (count == -1)
+    {
+        count = 1;
+    }
+    
+    switch (type)
+    {
+        case BinIO_TYPE_IGNORE_BYTE: type_size = 1; break;
+        case BinIO_TYPE_BYTE:        type_size = 1; break;
+        case BinIO_TYPE_INT16:       type_size = 2; break;
+        case BinIO_TYPE_INT32:       type_size = 4; break;
+        case BinIO_TYPE_INT64:       type_size = 8; break;
+        case BinIO_TYPE_FLOAT32:     type_size = 4; break;
+        case BinIO_TYPE_FLOAT64:     type_size = 8; break;
+    }
+    
+    *(size_t*)context += type_size * count;
+}
+
+extern size_t BinIOFormatByteCount(const char *format)
+{
+    struct BinIOFormatCursor cursor;
+    size_t n_bytes = 0;
+
+    BinIOInitFormatCursor(&cursor, format);
+    
+    while (BinIONextChar(&n_bytes, &cursor, BinIOCountBytes)) {}
+    
+    return n_bytes;
+}
diff --git a/Source/private.h b/Source/private.h
new file mode 100644 (file)
index 0000000..a79c33d
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef private_h
+#define private_h
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#define BinIO_TYPE_IGNORE_BYTE         'x'
+#define BinIO_TYPE_BYTE                'b'
+#define BinIO_TYPE_INT16               's'
+#define BinIO_TYPE_INT32               'i'
+#define BinIO_TYPE_INT64               'l'
+#define BinIO_TYPE_FLOAT32             'f'
+#define BinIO_TYPE_FLOAT64             'd'
+
+#define BinIO_LITTLE_ENDIAN_BYTE_ORDER 'L'
+#define BinIO_BIG_ENDIAN_BYTE_ORDER    'B'
+#define BinIO_HOST_BYTE_ORDER          'H'
+#define BinIO_NETWORK_BYTE_ORDER       'N'
+
+#if defined(BinIO_STDINT_HEADER)
+#include BinIO_STDINT_HEADER
+typedef float              float32_t;
+typedef double             float64_t;
+#else
+typedef unsigned char      uint8_t;
+typedef unsigned short     uint16_t;
+typedef unsigned long      uint32_t;
+#ifdef WIN32
+       typedef unsigned __int64        uint64_t;
+#else
+       typedef unsigned long long uint64_t;
+#endif
+typedef float              float32_t;
+typedef double             float64_t;
+#endif
+
+#ifndef BinIO_INLINE
+#if defined(__GNUC__)
+#define BinIO_INLINE static inline
+#else
+#define BinIO_INLINE static
+#endif
+#endif
+
+#ifndef BinIO_BYTE_ORDER
+#if defined(__ppc__) || defined(__POWERPC__)
+#define BinIO_BYTE_ORDER BinIO_BIG_ENDIAN_BYTE_ORDER
+#else
+#define BinIO_BYTE_ORDER BinIO_LITTLE_ENDIAN_BYTE_ORDER
+#endif
+#endif
+
+BinIO_INLINE void BinIOSwap1(const uint8_t *src, uint8_t *dst)
+{
+    *dst = *src;
+}
+
+BinIO_INLINE void BinIOSwap2(const uint8_t *src, uint8_t *dst)
+{
+    *(dst + 1) = *(src + 0);
+    *(dst + 0) = *(src + 1);
+}
+
+BinIO_INLINE void BinIOSwap4(const uint8_t *src, uint8_t *dst)
+{
+    *(dst + 3) = *(src + 0);
+    *(dst + 2) = *(src + 1);
+    *(dst + 1) = *(src + 2);
+    *(dst + 0) = *(src + 3);
+}
+
+BinIO_INLINE void BinIOSwap8(const uint8_t *src, uint8_t *dst)
+{
+    *(dst + 7) = *(src + 0);
+    *(dst + 6) = *(src + 1);
+    *(dst + 5) = *(src + 2);
+    *(dst + 4) = *(src + 3);
+    *(dst + 3) = *(src + 4);
+    *(dst + 2) = *(src + 5);
+    *(dst + 1) = *(src + 6);
+    *(dst + 0) = *(src + 7);
+}
+
+BinIO_INLINE int BinIONormalizeByteOrder(int byte_order)
+{
+    if (byte_order == BinIO_HOST_BYTE_ORDER)
+    {
+        byte_order = BinIO_BYTE_ORDER;
+    }
+    else if (byte_order == BinIO_NETWORK_BYTE_ORDER)
+    {
+        byte_order = BinIO_BIG_ENDIAN_BYTE_ORDER;
+    }
+    
+    return byte_order;
+}
+
+extern void BinIOConvert1(int from_byte_order, int to_byte_order,
+                          const uint8_t *src, uint8_t *dst,
+                          unsigned int count);
+extern void BinIOConvert2(int from_byte_order, int to_byte_order,
+                          const uint8_t *src, uint8_t *dst,
+                          unsigned int count);
+extern void BinIOConvert4(int from_byte_order, int to_byte_order,
+                          const uint8_t *src, uint8_t *dst,
+                          unsigned int count);
+extern void BinIOConvert8(int from_byte_order, int to_byte_order,
+                          const uint8_t *src, uint8_t *dst,
+                          unsigned int count);
+
+struct BinIOFormatCursor
+{
+    const char *cursor;
+    int         byte_order;
+    int         count;
+};
+
+typedef void (*BinIOProcessFunction)(void *context,
+                                     int   type,
+                                     int   byte_order,
+                                     int   count);
+
+extern void BinIOInitFormatCursor(struct BinIOFormatCursor *cursor,
+                                  const char               *format);
+
+extern int BinIONextChar(void                     *context,
+                         struct BinIOFormatCursor *cursor,
+                         BinIOProcessFunction      func);
+
+extern void BinIOCountBytes(void *context, int type, int byte_order, int count);
+
+extern size_t BinIOFormatByteCount(const char *format);
+
+#endif
diff --git a/Source/res/Lugaru.aps b/Source/res/Lugaru.aps
new file mode 100644 (file)
index 0000000..91455a8
Binary files /dev/null and b/Source/res/Lugaru.aps differ
diff --git a/Source/res/Lugaru.png b/Source/res/Lugaru.png
new file mode 100644 (file)
index 0000000..1db3a89
Binary files /dev/null and b/Source/res/Lugaru.png differ
diff --git a/Source/res/Lugaru.psd b/Source/res/Lugaru.psd
new file mode 100644 (file)
index 0000000..e3802af
Binary files /dev/null and b/Source/res/Lugaru.psd differ
diff --git a/Source/res/Lugaru.rc b/Source/res/Lugaru.rc
new file mode 100644 (file)
index 0000000..dd30038
--- /dev/null
@@ -0,0 +1,72 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_LUGARU              ICON                    "lugaru.ico"
+#endif    // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
diff --git a/Source/res/Untitled-1.jpg b/Source/res/Untitled-1.jpg
new file mode 100644 (file)
index 0000000..8622136
Binary files /dev/null and b/Source/res/Untitled-1.jpg differ
diff --git a/Source/res/icon1.ico b/Source/res/icon1.ico
new file mode 100644 (file)
index 0000000..9d0e916
Binary files /dev/null and b/Source/res/icon1.ico differ
diff --git a/Source/res/icon2.ico b/Source/res/icon2.ico
new file mode 100644 (file)
index 0000000..659202e
Binary files /dev/null and b/Source/res/icon2.ico differ
diff --git a/Source/res/lugaru.ico b/Source/res/lugaru.ico
new file mode 100644 (file)
index 0000000..5a2895e
Binary files /dev/null and b/Source/res/lugaru.ico differ
diff --git a/Source/res/resource.h b/Source/res/resource.h
new file mode 100644 (file)
index 0000000..b07c562
--- /dev/null
@@ -0,0 +1,16 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Lugaru.rc
+//
+#define IDI_LUGARU                      104
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        105
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/Source/unpack.c b/Source/unpack.c
new file mode 100644 (file)
index 0000000..a2cc44d
--- /dev/null
@@ -0,0 +1,53 @@
+#include <stdlib.h>
+
+#include "binio.h"
+#include "private.h"
+#include "unpack_private.h"
+
+void unpackf(const char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    vfunpackf(stdin, format, args);
+    va_end(args);
+}
+
+void sunpackf(const void *buffer, const char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    vsunpackf(buffer, format, args);
+    va_end(args);
+}
+
+void funpackf(FILE *file, const char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+    vfunpackf(file, format, args);
+    va_end(args);
+}
+
+void vsunpackf(const void *buffer, const char *format, va_list args)
+{
+    struct BinIOFormatCursor cursor;
+    struct BinIOUnpackContext context;
+
+    BinIOInitFormatCursor(&cursor, format);
+    
+    context.data = (const unsigned char*)buffer;
+    context.args = args;
+    
+    while (BinIONextChar(&context, &cursor, BinIOUnpack)) {}
+}
+
+void vfunpackf(FILE *file, const char *format, va_list args)
+{
+    size_t n_bytes = BinIOFormatByteCount(format);
+    void* buffer = malloc(n_bytes);
+    fread(buffer, n_bytes, 1, file);
+    
+    vsunpackf(buffer, format, args);
+    
+    free(buffer);
+}
diff --git a/Source/unpack_private.c b/Source/unpack_private.c
new file mode 100644 (file)
index 0000000..b019e28
--- /dev/null
@@ -0,0 +1,21 @@
+#include "unpack_private.h"
+
+extern void BinIOUnpack(void *context, int type, int byte_order, int count)
+{
+    struct BinIOUnpackContext *ctx = (struct BinIOUnpackContext*)context;
+    if (count == -1)
+    {
+        count = 1;
+    }
+
+    switch (type)
+    {
+        case BinIO_TYPE_IGNORE_BYTE:                                                                                                   ctx->data += 1 * count; break;
+        case BinIO_TYPE_BYTE:        BinIOConvert1(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count); ctx->data += 1 * count; break;
+        case BinIO_TYPE_INT16:       BinIOConvert2(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count); ctx->data += 2 * count; break;
+        case BinIO_TYPE_INT32:       BinIOConvert4(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count); ctx->data += 4 * count; break;
+        case BinIO_TYPE_INT64:       BinIOConvert8(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count); ctx->data += 8 * count; break;
+        case BinIO_TYPE_FLOAT32:     BinIOConvert4(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count); ctx->data += 4 * count; break;
+        case BinIO_TYPE_FLOAT64:     BinIOConvert8(byte_order, BinIO_HOST_BYTE_ORDER, ctx->data, va_arg(ctx->args, uint8_t *), count); ctx->data += 8 * count; break;
+    }
+}
diff --git a/Source/unpack_private.h b/Source/unpack_private.h
new file mode 100644 (file)
index 0000000..92478b2
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef unpack_private_h
+#define unpack_private_h
+
+#include "private.h"
+
+struct BinIOUnpackContext
+{
+    const uint8_t *data;
+    va_list        args;
+};
+
+extern void BinIOUnpack(void *context, int type, int byte_order, int count);
+
+#endif
diff --git a/Source/wincompat.h b/Source/wincompat.h
new file mode 100644 (file)
index 0000000..3bdbc4f
--- /dev/null
@@ -0,0 +1,81 @@
+#if !defined(WINCOMPAT_INCLUDED) && !defined(PLATFORM_WINDOWS) && !defined(WIN32) && !defined(WINDOWS) && !defined(__WIN32__)
+#define WINCOMPAT_INCLUDED
+
+/**
+ * 
+ * Author: Magnus Naeslund (mag@fbab.net, mag@bahnhof.se)
+ * (c) 2000 Magnus Naeslund, all rights reserved
+ * 
+ */
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <termios.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifndef TRUE
+  #define TRUE 1
+#endif
+#ifndef FALSE
+  #define FALSE 0
+#endif
+
+#define _kbhit kbhit
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+
+#define Sleep(x) usleep((x)*1000)
+
+static int            inited=0;
+static struct termios ori;
+
+static void tcatexit(){
+   tcsetattr(0,0,&ori);
+}
+
+static void init_terminal(){
+   struct termios t;
+   tcgetattr(0,&t);
+   tcgetattr(0,&ori);
+   t.c_lflag &= ~(ICANON);
+   tcsetattr(0,0,&t);
+   atexit(tcatexit);
+}
+
+static inline int kbhit(){
+  fd_set rfds;
+  struct timeval tv;
+
+   if (!inited){
+         inited=1;
+         init_terminal();
+   }
+   
+   FD_ZERO(&rfds);
+   FD_SET(0, &rfds);
+   tv.tv_sec = 0;
+   tv.tv_usec = 10*1000;
+   return select(1, &rfds, NULL, NULL, &tv)>0;
+}
+
+static inline int getch(){
+   fd_set rfds;
+   
+   if (!inited){
+         inited=1;
+         init_terminal();
+   }
+   
+   FD_ZERO(&rfds);
+   FD_SET(0, &rfds);
+   if (select(1, &rfds, NULL, NULL, NULL)>0)
+        return getchar();
+   else{
+         printf("wincompat.h: select() on fd 0 failed\n");
+         return 0xDeadBeef;
+   }    
+}
+
+#endif