Browse Source

update: 1.26源代码

Dcr 2 months ago
parent
commit
3f2d91f715
100 changed files with 26458 additions and 0 deletions
  1. 106 0
      Scripts/1_core/constants.c
  2. 164 0
      Scripts/1_core/defines.c
  3. 357 0
      Scripts/1_core/param.c
  4. 94 0
      Scripts/1_core/proto/dbgui.c
  5. 9 0
      Scripts/1_core/proto/enaudio.c
  6. 653 0
      Scripts/1_core/proto/enconvert.c
  7. 341 0
      Scripts/1_core/proto/endebug.c
  8. 870 0
      Scripts/1_core/proto/enentity.c
  9. 739 0
      Scripts/1_core/proto/enmath.c
  10. 43 0
      Scripts/1_core/proto/enmath2d.c
  11. 497 0
      Scripts/1_core/proto/enmath3d.c
  12. 331 0
      Scripts/1_core/proto/enphysics.c
  13. 762 0
      Scripts/1_core/proto/enprofiler.c
  14. 1003 0
      Scripts/1_core/proto/enscript.c
  15. 529 0
      Scripts/1_core/proto/enstring.c
  16. 534 0
      Scripts/1_core/proto/ensystem.c
  17. 244 0
      Scripts/1_core/proto/envisual.c
  18. 281 0
      Scripts/1_core/proto/envrdevice.c
  19. 712 0
      Scripts/1_core/proto/enwidgets.c
  20. 439 0
      Scripts/1_core/proto/enworld.c
  21. 390 0
      Scripts/1_core/proto/proto.c
  22. 112 0
      Scripts/1_core/proto/serializer.c
  23. 12 0
      Scripts/1_core/script.c
  24. 151 0
      Scripts/1_core/workbenchapi.c
  25. 276 0
      Scripts/2_gamelib/components/gamelibcomponents.c
  26. 141 0
      Scripts/2_gamelib/entities/gamelibentities.c
  27. 79 0
      Scripts/2_gamelib/entities/rendertarget.c
  28. 172 0
      Scripts/2_gamelib/entities/scriptcamera.c
  29. 40 0
      Scripts/2_gamelib/entities/scriptlight.c
  30. 62 0
      Scripts/2_gamelib/entities/scriptmodel.c
  31. 97 0
      Scripts/2_gamelib/entities/worldsmenu.c
  32. 158 0
      Scripts/2_gamelib/gamelib.c
  33. 46 0
      Scripts/2_gamelib/inputmanager.c
  34. 95 0
      Scripts/2_gamelib/menumanager.c
  35. 38 0
      Scripts/2_gamelib/settings.c
  36. 216 0
      Scripts/2_gamelib/tools.c
  37. 8 0
      Scripts/3_game/ai/aiagent.c
  38. 15 0
      Scripts/3_game/ai/aigroup.c
  39. 32 0
      Scripts/3_game/ai/aigroupbehaviour.c
  40. 123 0
      Scripts/3_game/ai/aiworld.c
  41. 147 0
      Scripts/3_game/aibehaviour.c
  42. 17 0
      Scripts/3_game/ammocamparams.c
  43. 137 0
      Scripts/3_game/ammoeffects.c
  44. 180 0
      Scripts/3_game/analytics/analyticsmanagerclient.c
  45. 73 0
      Scripts/3_game/analytics/analyticsmanagerserver.c
  46. 176 0
      Scripts/3_game/analytics/scriptanalytics.c
  47. 35 0
      Scripts/3_game/anim/animcommand.c
  48. 134 0
      Scripts/3_game/anim/animphysagent.c
  49. 120 0
      Scripts/3_game/billboardset.c
  50. 131 0
      Scripts/3_game/bleedchancedata.c
  51. 90 0
      Scripts/3_game/canvas.c
  52. 768 0
      Scripts/3_game/ce/centraleconomy.c
  53. 354 0
      Scripts/3_game/cfggameplaydatajson.c
  54. 448 0
      Scripts/3_game/cfggameplayhandler.c
  55. 266 0
      Scripts/3_game/cfgplayerrestrictedareahandler.c
  56. 248 0
      Scripts/3_game/cfgplayerrestrictedareajsondata.c
  57. 131 0
      Scripts/3_game/client/clientdata.c
  58. 26 0
      Scripts/3_game/client/mods/modloader.c
  59. 68 0
      Scripts/3_game/client/mods/modstructure.c
  60. 14 0
      Scripts/3_game/client/notifications/notificationdata.c
  61. 320 0
      Scripts/3_game/client/notifications/notificationsystem.c
  62. 231 0
      Scripts/3_game/client/notifications/notificationui.c
  63. 747 0
      Scripts/3_game/client/onlineservices.c
  64. 6 0
      Scripts/3_game/client/syncdata.c
  65. 7 0
      Scripts/3_game/client/syncentitykill.c
  66. 12 0
      Scripts/3_game/client/syncplayer.c
  67. 69 0
      Scripts/3_game/client/syncplayerlist.c
  68. 76 0
      Scripts/3_game/colors.c
  69. 1066 0
      Scripts/3_game/constants.c
  70. 8 0
      Scripts/3_game/controlschememanager.c
  71. 157 0
      Scripts/3_game/damagesystem.c
  72. 238 0
      Scripts/3_game/dayzanimeventmaps.c
  73. 366 0
      Scripts/3_game/dayzanimevents.c
  74. 6 0
      Scripts/3_game/dayzcreature.c
  75. 4 0
      Scripts/3_game/dayzcreatureai.c
  76. 3825 0
      Scripts/3_game/dayzgame.c
  77. 1396 0
      Scripts/3_game/dayzplayer.c
  78. 17 0
      Scripts/3_game/debugweatherrpcdata.c
  79. 9 0
      Scripts/3_game/econtrolschemestate.c
  80. 619 0
      Scripts/3_game/effect.c
  81. 875 0
      Scripts/3_game/effectmanager.c
  82. 456 0
      Scripts/3_game/effects/backlit/backlit.c
  83. 160 0
      Scripts/3_game/effects/destructioneffects/destructioneffectbase.c
  84. 568 0
      Scripts/3_game/effects/effectparticle.c
  85. 15 0
      Scripts/3_game/effects/effectparticle/bleedingsource.c
  86. 7 0
      Scripts/3_game/effects/effectparticle/bloodsplatter.c
  87. 341 0
      Scripts/3_game/effects/effectparticle/bulletimpactbase.c
  88. 11 0
      Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_concrete.c
  89. 9 0
      Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_dirt.c
  90. 11 0
      Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_error.c
  91. 23 0
      Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_foliage.c
  92. 9 0
      Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_glass.c
  93. 9 0
      Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_glass_thin.c
  94. 11 0
      Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_grass.c
  95. 9 0
      Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_gravel.c
  96. 9 0
      Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_ice.c
  97. 201 0
      Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_meatbones.c
  98. 7 0
      Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_meatbones/hit_meatbones_meleefist.c
  99. 7 0
      Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_meatbones/hit_meatbones_meleepipewrench.c
  100. 7 0
      Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_meatbones/hit_meatbones_meleeshovel.c

+ 106 - 0
Scripts/1_core/constants.c

@@ -0,0 +1,106 @@
+/**
+ * \defgroup Constants Constants
+ * \desc static script constants
+ * @{
+ */
+
+
+/**
+ * \defgroup InputDevice InputDevice
+ * \desc constants for input device - inputInterfaceDef.h
+ * @{
+ */
+const int INPUT_MODULE_TYPE_MASK	= 0x00700000;
+const int INPUT_KEY_MASK			= 0x000000ff;
+const int INPUT_ACTION_TYPE_MASK	= 0x00000f00;
+const int INPUT_AXIS				= 0x00010000;
+const int INPUT_POV					= 0x00020000;
+const int INPUT_COMBO_MASK			= 0xff000000;
+const int INPUT_COMBO_AXIS			= 0x00800000;
+const int INPUT_COMBO_AXIS_OFFSET	= 0x00000080;
+const int INPUT_COMBO_KEY_OFFSET	= 0x01000000;
+
+const int INPUT_DEVICE_KEYBOARD   	= 0x00000000;
+const int INPUT_DEVICE_MOUSE      	= 0x00100000; // mouse button
+const int INPUT_DEVICE_STICK		= 0x00200000;
+const int INPUT_DEVICE_XINPUT     	= 0x00300000; // XInput device
+const int INPUT_DEVICE_TRACKIR		= 0x00400000;
+const int INPUT_DEVICE_GAMEPAD  	= 0x00500000;
+const int INPUT_DEVICE_CHEAT		= 0x00600000;
+
+const int INPUT_ACTION_TYPE_NONE			= 0x00000000;
+const int INPUT_ACTION_TYPE_STATE			= 0x00000100;
+const int INPUT_ACTION_TYPE_DOWN_EVENT		= 0x00000200;
+const int INPUT_ACTION_TYPE_UP_EVENT		= 0x00000300;
+const int INPUT_ACTION_TYPE_SHORTCLICK_EVENT= 0x00000400;
+const int INPUT_ACTION_TYPE_HOLD_EVENT		= 0x00000500;
+		
+const int INPUT_ACTION_TYPE_COMBO			= 0x00002000;
+const int INPUT_ACTION_TYPE_SPECIALCOMBO	= 0x00004000;
+const int INPUT_ACTION_TYPE_DOUBLETAP		= 0x00008000;
+
+const int INPUT_DEVICE_MOUSE_AXIS 		= (INPUT_DEVICE_MOUSE | INPUT_AXIS);
+const int INPUT_DEVICE_STICK_AXIS		= (INPUT_DEVICE_STICK | INPUT_AXIS);
+const int INPUT_DEVICE_STICK_POV		= (INPUT_DEVICE_STICK | INPUT_POV);
+const int INPUT_DEVICE_GAMEPAD_AXIS		= (INPUT_DEVICE_GAMEPAD | INPUT_AXIS);
+
+/** @}*/
+
+/**
+ * \defgroup StringConstants String constants
+ * \desc String constants
+ * @{
+ */
+const string STRING_EMPTY = "";
+/** @}*/
+
+
+/**
+
+ * \defgroup Colors Colors
+ * @{
+ */
+const int COLOR_WHITE = 0xFFFFFFFF;
+const int COLOR_RED = 0xFFF22613;
+const int COLOR_GREEN = 0xFF2ECC71;
+const int COLOR_BLUE = 0xFF4B77BE;
+const int COLOR_YELLOW = 0xFFF7CA18;
+
+const int COLOR_RED_A = 0x1fF22613;
+const int COLOR_GREEN_A = 0x1f2ECC71;
+const int COLOR_BLUE_A = 0x1f4B77BE;
+const int COLOR_YELLOW_A = 0x1fF7CA18;
+
+/** @}*/
+	
+/**
+
+ * \defgroup Materials Materials
+ * @{
+ */
+
+/****************************************************************************
+ *	MATERIALS LIST
+ *	
+ *	Note: If you add new materials here, don't forget to add physics
+ *	parameters to them in physics/materials.xml
+ ***************************************************************************/
+const int MATERIAL_DEFAULT			= 0;
+const int MATERIAL_METAL			= 1;	//full steel
+const int MATERIAL_IRON				= 2;	//iron
+const int MATERIAL_GLASS			= 3;	//glass pane
+const int MATERIAL_PLASTIC			= 4;	//plastic object
+const int MATERIAL_LIQUID			= 5;	//liquids, water
+const int MATERIAL_SLIME			= 6;	//slime, oil etc
+const int MATERIAL_BETON			= 7;	//concrete
+const int MATERIAL_RUBBER			= 8;	//rubber, linoeum
+const int MATERIAL_FLESH			= 9;	//flesh, humanoids
+const int MATERIAL_GRASS			= 10;	//grass
+const int MATERIAL_WOOD				= 11;	//wood
+const int MATERIAL_SNOW				= 12;	//snow
+const int MATERIAL_SAND				= 13;	//soft sand
+const int MATERIAL_DIRT				= 14;	//super-soft dirt
+const int MATERIAL_GRAVEL			= 15;	//gravel
+const int MATERIAL_STONE			= 16;	//rocks, cliffs
+
+/** @}*/

+ 164 - 0
Scripts/1_core/defines.c

@@ -0,0 +1,164 @@
+// All defines in this file are added from C++ side
+// It simply exists for documentation purposes
+#ifdef DOXYGEN
+
+/**
+ * \defgroup Defines Defines
+ * \desc static defines
+ * @{
+ */
+
+/*!
+	\brief Define filled in with the current Major and Minor version (e.g. DAYZ_1_16)
+*/
+#define DAYZ_X_XX
+
+/*!
+	\brief Enabled when game is in Buldozer mode
+*/
+#define BULDOZER
+
+/*!
+	\brief Enabled when script is compiled for Workbench
+*/
+#define WORKBENCH
+
+/*!
+	\note Present for server builds
+*/
+#define NO_GUI
+
+/*!
+	\note Present for server builds
+*/
+#define NO_GUI_INGAME
+
+/*!
+	\note Enabled via '-doScriptLogs=1' in launch parameters
+*/
+#define ENABLE_LOGGING
+
+/*!
+	\note Enabled via '-logToFile=1' in launch parameters. Default '1' on internal and '0' on retail
+*/
+#define LOG_TO_FILE
+
+/*!
+	\note Enabled via '-logToScript=1' in launch parameters. Default '1' on internal and '0' on retail
+*/
+#define LOG_TO_SCRIPT
+
+/*!
+	\note Enabled via '-logToRpt=1' in launch parameters. Default '0' on internal and '0' on retail
+*/
+#define LOG_TO_RPT
+
+/*!
+	\note Work in progress feature flag to prevent cursor from being hijacked by the game. Original intention was only DEVELOPER_DIAG but the fix later introduced problems in retail.
+*/
+#define FEATURE_CURSOR
+
+/*!
+	\note Work in progress feature flag for the new reconciliation for players.
+*/
+#define FEATURE_NETWORK_RECONCILIATION
+
+
+
+/**
+ * \defgroup BuildDefines Build defines
+ * \desc Defines for different builds
+ * @{
+ */
+
+	/*!
+		\brief Define present in Diag builds
+	*/
+	#define DIAG
+	
+	/*!
+		\note A build is always either DEVELOPER or RELEASE, one is always active
+	*/
+	#define DEVELOPER
+	
+	/*!
+		\note includes Diag
+	*/
+	#define RELEASE
+	
+	/*!
+		\brief DIAG || DEVELOPER
+	*/
+	#define DIAG_DEVELOPER
+	
+	/*!
+		\brief Define present in Experimental builds
+	*/
+	#define BUILD_EXPERIMENTAL
+
+/** @}*/
+
+
+
+/**
+ * \defgroup ServerDefines Server defines
+ * \desc Defines for dedicated server code
+ * \note Only defined when CGame.IsDedicatedServer equals true
+ * \note The platforms mentioned are the client platform, for game platform use PLATFORM defines
+ * @{
+ */
+
+	/*!
+		\brief Define always present on dedicated servers
+		\note Should be preferred over using CGame.IsDedicatedServer when possible
+	*/
+	#define SERVER
+	
+	/*!
+		\warning This is defined for Linux servers as well, as it targets Windows clients
+		\note A server is always either FOR_WINDOWS, FOR_X1 or FOR_PS4
+	*/
+	#define SERVER_FOR_WINDOWS
+	
+	/*!
+		\note A server is always either FOR_WINDOWS, FOR_X1 or FOR_PS4
+	*/
+	#define SERVER_FOR_X1
+	
+	/*!
+		\note A server is always either FOR_WINDOWS, FOR_X1 or FOR_PS4
+	*/
+	#define SERVER_FOR_PS4
+	
+	/*!
+		\brief SERVER_FOR_X1 || SERVER_FOR_PS4
+	*/
+	#define SERVER_FOR_CONSOLE
+
+/** @}*/
+
+
+
+/**
+ * \defgroup PlatformDefines Platform defines
+ * \desc Defines for platform the build is built for
+ * @{
+ */
+
+	#define PLATFORM_LINUX
+
+	#define PLATFORM_WINDOWS
+	
+	#define PLATFORM_XBOX
+	
+	#define PLATFORM_PS4
+	
+	/*!
+		\brief PLATFORM_XBOX || PLATFORM_PS4
+	*/
+	#define PLATFORM_CONSOLE
+
+/** @}*/
+
+/** @}*/
+#endif

+ 357 - 0
Scripts/1_core/param.c

@@ -0,0 +1,357 @@
+/**
+ * \defgroup Tools Tools
+ * \desc Helpful functions & classes
+ * @{
+ */
+
+//-----------------------------------------------------------------------------
+/**
+\brief Base Param Class with no parameters. Used as general purpose parameter overloaded with Param1 to Param4 templates
+ */
+class Param: Managed
+{
+	bool Serialize(Serializer ctx)
+	{
+		return false;
+	}
+		
+	bool Deserializer(Serializer ctx)
+	{
+		return false;
+	}
+};
+
+/**
+ \brief Param Class Template with one parameter.
+ \n usage:
+ @code
+ Param paramA = new Param1<int>(55); 
+ Param paramB = new Param1<string>("Hello");
+ @endcode
+ */
+class Param1<Class T1> extends Param
+{
+	T1 param1;
+
+	void Param1(T1 p1)
+	{
+		param1 = p1;
+	}
+		
+	override bool Serialize(Serializer ctx)
+	{
+		return ctx.Write(param1);
+	}
+		
+	override bool Deserializer(Serializer ctx)
+	{
+		return ctx.Read(param1);
+	}
+};
+
+/**
+ \brief Param Class Template with two parameters.
+ \n usage:
+ @code
+ Param param = new Param2<float, string>(3.14, "Pi");
+ @endcode
+ */
+class Param2<Class T1, Class T2> extends Param
+{
+	T1 param1;
+	T2 param2;
+
+	void Param2(T1 p1, T2 p2)
+	{
+		param1 = p1;
+		param2 = p2;
+	}
+		
+	override bool Serialize(Serializer ctx)
+	{
+		return ctx.Write(param1) && ctx.Write(param2);
+	}
+		
+	override bool Deserializer(Serializer ctx)
+	{
+		return ctx.Read(param1) && ctx.Read(param2);
+	}
+};
+
+/**
+ \brief Param Class Template with three parameters.
+ \n usage:
+ @code
+ Param param = new Param3<float, string, bool>(2.89, "Lala", true);
+ @endcode
+ */
+class Param3<Class T1, Class T2, Class T3> extends Param
+{
+	T1 param1;
+	T2 param2;
+	T3 param3;
+
+	void Param3(T1 p1, T2 p2, T3 p3)
+	{
+		param1 = p1;
+		param2 = p2;
+		param3 = p3;
+	}
+		
+	override bool Serialize(Serializer ctx)
+	{
+		return ctx.Write(param1) && ctx.Write(param2) && ctx.Write(param3);
+	}
+		
+	override bool Deserializer(Serializer ctx)
+	{
+		return ctx.Read(param1) && ctx.Read(param2) && ctx.Read(param3);
+	}
+};
+
+/**
+ \brief Param Class Template with four parameters.
+ \n usage:
+ @code
+ Param param = new Param4<int, bool, float, string>(100, false, 79.9, "Test");
+ @endcode
+ */
+class Param4<Class T1, Class T2, Class T3, Class T4> extends Param
+{
+	T1 param1;
+	T2 param2;
+	T3 param3;
+	T4 param4;
+
+	void Param4(T1 p1, T2 p2, T3 p3, T4 p4)
+	{
+		param1 = p1;
+		param2 = p2;
+		param3 = p3;
+		param4 = p4;
+	}
+		
+	override bool Serialize(Serializer ctx)
+	{
+		return ctx.Write(param1) && ctx.Write(param2) && ctx.Write(param3) && ctx.Write(param4);
+	}
+		
+	override bool Deserializer(Serializer ctx)
+	{
+		return ctx.Read(param1) && ctx.Read(param2) && ctx.Read(param3) && ctx.Read(param4);
+	}
+};
+
+/**
+ \brief Param Class Template with five parameters.
+ */
+class Param5<Class T1, Class T2, Class T3, Class T4, Class T5> extends Param
+{
+	T1 param1;
+	T2 param2;
+	T3 param3;
+	T4 param4;
+	T5 param5;
+
+	void Param5(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5)
+	{
+		param1 = p1;
+		param2 = p2;
+		param3 = p3;
+		param4 = p4;
+		param5 = p5;
+	}
+		
+	override bool Serialize(Serializer ctx)
+	{
+		return ctx.Write(param1) && ctx.Write(param2) && ctx.Write(param3) && ctx.Write(param4) && ctx.Write(param5);
+	}
+		
+	override bool Deserializer(Serializer ctx)
+	{
+		return ctx.Read(param1) && ctx.Read(param2) && ctx.Read(param3) && ctx.Read(param4) && ctx.Read(param5);
+	}
+};
+
+/**
+ \brief Param Class Template with six parameters.
+ */
+class Param6<Class T1, Class T2, Class T3, Class T4, Class T5, Class T6> extends Param
+{
+	T1 param1;
+	T2 param2;
+	T3 param3;
+	T4 param4;
+	T5 param5;
+	T6 param6;
+
+	void Param6(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6)
+	{
+		param1 = p1;
+		param2 = p2;
+		param3 = p3;
+		param4 = p4;
+		param5 = p5;
+		param6 = p6;
+	}
+		
+	override bool Serialize(Serializer ctx)
+	{
+		return ctx.Write(param1) && ctx.Write(param2) && ctx.Write(param3) && ctx.Write(param4) && ctx.Write(param5) && ctx.Write(param6);
+	}
+		
+	override bool Deserializer(Serializer ctx)
+	{
+		return ctx.Read(param1) && ctx.Read(param2) && ctx.Read(param3) && ctx.Read(param4) && ctx.Read(param5) && ctx.Read(param6);
+	}
+};
+
+/**
+ \brief Param Class Template with seven parameters.
+ */
+class Param7<Class T1, Class T2, Class T3, Class T4, Class T5, Class T6, Class T7>: Param
+{
+    T1 param1;
+    T2 param2;
+    T3 param3;
+    T4 param4;
+    T5 param5;
+    T6 param6;
+    T7 param7;
+
+    void Param7(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7)
+    {
+        param1 = p1;
+        param2 = p2;
+        param3 = p3;
+        param4 = p4;
+        param5 = p5;
+        param6 = p6;
+        param7 = p7;
+    }
+        
+    override bool Serialize(Serializer ctx)
+    {
+        return ctx.Write(param1) && ctx.Write(param2) && ctx.Write(param3) && ctx.Write(param4) && ctx.Write(param5) && ctx.Write(param6) && ctx.Write(param7);
+    }
+        
+    override bool Deserializer(Serializer ctx)
+    {
+        return ctx.Read(param1) && ctx.Read(param2) && ctx.Read(param3) && ctx.Read(param4) && ctx.Read(param5) && ctx.Read(param6) && ctx.Read(param7);
+    }
+};
+/**
+ \brief Param Class Template with eight parameters.
+ */
+class Param8<Class T1, Class T2, Class T3, Class T4, Class T5, Class T6, Class T7, Class T8>: Param
+{
+    T1 param1;
+    T2 param2;
+    T3 param3;
+    T4 param4;
+    T5 param5;
+    T6 param6;
+    T7 param7;
+    T8 param8;
+
+    void Param8(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8)
+    {
+        param1 = p1;
+        param2 = p2;
+        param3 = p3;
+        param4 = p4;
+        param5 = p5;
+        param6 = p6;
+        param7 = p7;
+        param8 = p8;
+    }
+        
+    override bool Serialize(Serializer ctx)
+    {
+        return ctx.Write(param1) && ctx.Write(param2) && ctx.Write(param3) && ctx.Write(param4) && ctx.Write(param5) && ctx.Write(param6) && ctx.Write(param7) && ctx.Write(param8);
+    }
+        
+    override bool Deserializer(Serializer ctx)
+    {
+        return ctx.Read(param1) && ctx.Read(param2) && ctx.Read(param3) && ctx.Read(param4) && ctx.Read(param5) && ctx.Read(param6) && ctx.Read(param7) && ctx.Read(param8);
+    }
+};
+/**
+ \brief Param Class Template with nine parameters.
+ */
+class Param9<Class T1, Class T2, Class T3, Class T4, Class T5, Class T6, Class T7, Class T8, Class T9>: Param
+{
+    T1 param1;
+    T2 param2;
+    T3 param3;
+    T4 param4;
+    T5 param5;
+    T6 param6;
+    T7 param7;
+    T8 param8;
+    T9 param9;
+
+    void Param9(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9)
+    {
+        param1 = p1;
+        param2 = p2;
+        param3 = p3;
+        param4 = p4;
+        param5 = p5;
+        param6 = p6;
+        param7 = p7;
+        param8 = p8;
+        param9 = p9;
+    }
+        
+    override bool Serialize(Serializer ctx)
+    {
+        return ctx.Write(param1) && ctx.Write(param2) && ctx.Write(param3) && ctx.Write(param4) && ctx.Write(param5) && ctx.Write(param6) && ctx.Write(param7) && ctx.Write(param8) && ctx.Write(param9);
+    }
+        
+    override bool Deserializer(Serializer ctx)
+    {
+        return ctx.Read(param1) && ctx.Read(param2) && ctx.Read(param3) && ctx.Read(param4) && ctx.Read(param5) && ctx.Read(param6) && ctx.Read(param7) && ctx.Read(param8) && ctx.Read(param9);
+    }
+};
+/**
+ \brief Param Class Template with ten parameters.
+ */
+class Param10<Class T1, Class T2, Class T3, Class T4, Class T5, Class T6, Class T7, Class T8, Class T9, Class T10>: Param
+{
+    T1 param1;
+    T2 param2;
+    T3 param3;
+    T4 param4;
+    T5 param5;
+    T6 param6;
+    T7 param7;
+    T8 param8;
+    T9 param9;
+	T10 param10;
+
+    void Param10(T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7, T8 p8, T9 p9, T10 p10)
+    {
+        param1 = p1;
+        param2 = p2;
+        param3 = p3;
+        param4 = p4;
+        param5 = p5;
+        param6 = p6;
+        param7 = p7;
+        param8 = p8;
+        param9 = p9;
+        param10 = p10;
+    }
+        
+    override bool Serialize(Serializer ctx)
+    {
+        return ctx.Write(param1) && ctx.Write(param2) && ctx.Write(param3) && ctx.Write(param4) && ctx.Write(param5) && ctx.Write(param6) && ctx.Write(param7) && ctx.Write(param8) && ctx.Write(param9) && ctx.Write(param10);
+    }
+        
+    override bool Deserializer(Serializer ctx)
+    {
+        return ctx.Read(param1) && ctx.Read(param2) && ctx.Read(param3) && ctx.Read(param4) && ctx.Read(param5) && ctx.Read(param6) && ctx.Read(param7) && ctx.Read(param8) && ctx.Read(param9) && ctx.Read(param10);
+    }
+};
+/** @}*/

+ 94 - 0
Scripts/1_core/proto/dbgui.c

@@ -0,0 +1,94 @@
+/** @addtogroup Debug
+@{*/
+
+/**
+ * \defgroup DebugUI Debug UI API
+	\brief Immediate mode debug UI API
+ * @{
+	Per frame usage example:
+	@code
+	bool m_ShowDbgUI = false;
+	int m_DbgListSelection = 0;
+	float m_DbgSliderValue = 0.0;
+	autoptr array<string> m_DbgOptions = {"jedna", "dva", "tri"};
+	
+	void OnUpdate(float timeslice)
+	{	
+		DbgUI.Begin("Test");
+		DbgUI.Check("Show DbgUI", m_ShowDbgUI);
+		if (m_ShowDbgUI)
+		{
+			DbgUI.Text("DbgUI Test");		
+	
+			string name = "";
+			DbgUI.InputText("name", name);		
+			
+			if (DbgUI.Button("Print name"))
+			{
+				Print(name);		
+			}
+			
+			DbgUI.List("test list", m_DbgListSelection, m_DbgOptions);
+			
+			DbgUI.Text("Choice = " + m_DbgListSelection.ToString());	
+			
+			DbgUI.Spacer(10);
+			DbgUI.SliderFloat("slider", m_DbgSliderValue, 0, 100);
+			DbgUI.Text("Slider value = " + ftoa(m_DbgSliderValue));	
+		}
+		DbgUI.End();
+	}
+	@endcode
+
+	For non-per frame usage example:
+	@code
+	int m_DbgEventCount = 0;
+	void OnEvent(EventType eventTypeId, Param params)
+	{
+		m_DbgEventCount++;
+
+		DbgUI.BeginCleanupScope();		
+		DbgUI.Begin("events", 300, 0);
+		DbgUI.Text("Events count = " + m_DbgEventCount.ToString());
+		DbgUI.End();
+		DbgUI.EndCleanupScope();
+	}
+	@endcode
+*/
+
+class DbgUI
+{
+	private void DbgUI() {}
+	private void ~DbgUI() {}
+	
+	static proto native void DoUnitTest(); ///< Creates all possible DbgUI widgets. Just for the testing purposes.
+	static proto native void Text(string label);
+	static proto native void ColoredText(int color, string label);
+	static proto void Check(string label, out bool checked);
+	static proto void Combo(string label, out int selection, TStringArray elems);
+	static proto void List(string label, out int selection, TStringArray elems);
+	static proto void SliderFloat(string label, out float value, float min, float max, int pxWidth = 150);
+	static proto native void Spacer(int height);
+	static proto native void Panel(string label, int width, int height, int color = 0xaa555555);
+	static proto native bool Button(string txt, int minWidth = 0);
+	static proto void InputText(string txt, out string value, int pxWidth = 150);
+	static proto void InputInt(string txt, out int value, int pxWidth = 150);
+	static proto void InputFloat(string txt, out float value, int pxWidth = 150);
+			
+	static proto native void PlotLive(string label, int sizeX, int sizeY, float val, int timeStep = 100, int historySize = 30, int color = 0xFFFFFFFF);
+	
+	static proto native void SameLine();
+	static proto native void SameSpot();
+	
+	static proto native void PushID_Int(int int_id);
+	static proto native void PushID_Str(string str_id);
+	static proto native void PopID();
+	
+	static proto void BeginCleanupScope();
+    static proto native void EndCleanupScope();
+	
+	static proto native void Begin(string windowTitle, float x = 0, float y = 0);
+    static proto native void End();
+};
+//@}
+//@}

+ 9 - 0
Scripts/1_core/proto/enaudio.c

@@ -0,0 +1,9 @@
+typedef int[] AudioHandle;
+
+class AudioSystem
+{
+	proto native static AudioHandle BankLoad(string path);
+	proto native static AudioHandle ShaderLoad(string path);
+	proto native static AudioHandle SoundPlay(AudioHandle bank, AudioHandle shader);
+	proto native static void SoundDestroy(AudioHandle handle);
+};

+ 653 - 0
Scripts/1_core/proto/enconvert.c

@@ -0,0 +1,653 @@
+class bool
+{
+	string ToString()
+	{
+		if (value) return "true";
+		else return "false";
+	}
+};
+
+class func
+{
+	//! For internal usage of VM 
+	private proto void SetInstance(Class inst);
+};
+
+enum EBool
+{
+	NO = 0,
+	YES = 1	
+}
+
+class int
+{
+	protected const int ZERO_PAD_SIZE = 8;
+	protected static string m_ZeroPad[ZERO_PAD_SIZE] = {"", "0", "00", "000", "0000", "00000", "000000", "0000000"};
+	
+	const int MAX = 2147483647;
+	const int MIN = -2147483648;
+	
+	proto string ToString();
+	
+	/**
+	\brief Converts ASCII code to string
+		\param ascii ASCII code for convert to \p string.
+		\return \p string - Converted \p int.
+		@code
+			int ascii_code = 77;
+			string str = ascii_code.AsciiToString();
+			Print(str);
+
+			>> str = 'M'
+		@endcode
+	*/
+	proto string AsciiToString();
+	
+	/**
+	\brief Integer to string with fixed length, padded with zeroes
+		\param num \p int integer to convert
+		\param len \p int fixed length
+		\return \p vector Converted s as vector
+		@code
+			int num = 123;
+			string s = num.ToStringLen(5);
+			Print(s);
+
+			>> s = '00123'
+		@endcode
+	*/
+	string ToStringLen(int len)
+	{
+		string str = value.ToString();
+
+		int l = len - str.Length();
+
+		if (l > 0 && l < ZERO_PAD_SIZE )
+			return m_ZeroPad[l] + str;
+
+		return str;
+	}
+	
+	/**
+	\brief Check whether integer falls into an inclusive range
+		\param min \p int low end of range
+		\param max \p int high end of range
+		\return \p bool True if this value is withing the set range
+		@code
+			int num = 123;
+			bool test = num.InRange( 100, 150 );
+			Print(test);
+
+			>> s = true
+		@endcode
+	*/
+	bool InRange( int min, int max, bool inclusive_min = true, bool inclusive_max = true )
+	{
+		if( ( !inclusive_min && value <= min ) || value < min )
+			return false;
+		
+		if( ( !inclusive_max && value >= max ) || value > max )
+			return false;
+		
+		return true;
+	}
+};
+
+class float
+{
+	const float MIN = FLT_MIN;
+	const float MAX = FLT_MAX;
+	const float LOWEST = -FLT_MAX;
+	
+	proto string ToString();
+};
+
+class vector
+{
+	static const vector Up = "0 1 0";
+	static const vector Aside = "1 0 0";
+	static const vector Forward = "0 0 1";
+	static const vector Zero = "0 0 0";
+	
+	/**
+	\brief Vector to  string
+		\param beautify If true verbose vector in more human readable form "<1, 1, 1>" instead of simple form "1 1 1"
+		\return \p string Converted vector as parsed string
+		@code
+			vector v = "1 0 1";
+			Print( v.ToString() );
+			Print( v.ToString(false) );
+
+			>> '<1, 0, 1>'
+			>> '1 0 1'
+		@endcode
+	*/
+	proto string ToString(bool beautify = true);
+	
+	/**
+	\brief Normalizes vector. Returns length
+		\return \p float Length of origin vector
+		@code
+			vector vec = "1 0 1";
+			float length = vec.Normalize();
+			Print( vec );
+			Print( length );
+
+			>> vec = <0.707107,0,0.707107>
+			>> length = 1.41421
+		@endcode
+	*/
+	proto float Normalize();
+
+	//! return normalized vector (keeps orginal vector untouched)
+	proto vector Normalized();
+	
+	/**
+	\brief Returns length of vector (magnitude)
+		\return \p float Length of vector
+		@code
+			vector vec = "1 0 1";
+			float length = vec.Length();
+			Print( length );
+
+			>> length = 1.41421
+		@endcode
+	*/
+	proto native float Length();
+
+	/**
+	\brief Returns squared length (magnitudeSqr)
+		\return \p float Length of vector
+		@code
+			vector vec = "1 1 0";
+			float length = vec.LengthSq();
+			Print( length );
+
+			>> length = 2
+		@endcode
+	*/
+	proto native float LengthSq();
+	
+	/**
+	\brief Returns the distance between tips of two 3D vectors.
+		\param v1 \p vector 3D Vector 1
+		\param v2 \p vector 3D Vector 2
+		\return \p float Distance
+		@code
+			float dist = vector.Distance( "1 2 3", "4 5 6" );
+			Print( dist );
+
+			>> dist = 5.19615
+		@endcode
+	*/
+	proto static native float Distance(vector v1, vector v2);
+	
+	/**
+	\brief Returns the square distance between tips of two 3D vectors.
+		\param v1 \p vector 3D Vector 1
+		\param v2 \p vector 3D Vector 2
+		\return \p float Squere distance
+		@code
+			float dist = vector.DistanceSq( "0 0 0", "0 5 0" );
+			Print( dist );
+
+			>> dist = 25
+		@endcode
+	*/
+	proto static native float DistanceSq(vector v1, vector v2);
+
+	/**
+	\brief Returns perpendicular vector. Perpendicular vector is computed as cross product between input vector and up vector (0, 1, 0).
+	    \return \p vector perpendicular vector
+		@code
+			vector vec = "1 0 0";
+			Print( vec.Perpend() );
+
+			>> <0,0,1>
+		@endcode
+	*/
+	vector Perpend()
+	{
+		return value * vector.Up;
+	}
+	
+	/**
+	\brief Returns direction vector from point p1 to point p2
+	    \param p1 \p vector point from
+		\param p2 \p vector point to
+		\return \p vector direction vector
+	*/
+	static vector Direction(vector p1, vector p2)
+	{
+		vector dir_vec;
+		
+		dir_vec[0] = p2[0] - p1[0];
+		dir_vec[1] = p2[1] - p1[1];
+		dir_vec[2] = p2[2] - p1[2];
+		
+		return dir_vec;
+	}
+	
+	/**
+	\brief Returns randomly generated unit vector
+	    \return \p randomly generated unit vector
+		@code
+			vector vec = vector.RandomDir();
+			Print(vec);
+			Print(vec.Length());
+
+			>> <-0.179424,0.966825,0.181816>
+			>> 1
+		@endcode
+	*/
+	static vector RandomDir()
+	{
+		return Vector(Math.RandomFloatInclusive(-1,1),Math.RandomFloatInclusive(-1,1),Math.RandomFloatInclusive(-1,1)).Normalized();
+	}
+
+	/**
+	\brief Returns randomly generated XZ unit vector with the Y(up) axis set to 0
+	    \return \p randomly generated XZ unit vector
+		@code
+			vector vec = vector.RandomDir();
+			Print(vec);
+			Print(vec.Length());
+
+			>> <0.631697,0,0.775216>
+			>> 1
+		@endcode
+	*/
+	static vector RandomDir2D()
+	{
+		return Vector(Math.RandomFloatInclusive(-1,1),0,Math.RandomFloatInclusive(-1,1)).Normalized();
+	}
+	
+	/**
+	\brief Returns Dot product of vector v1 and vector v2
+	    \param v1 \p vector input vector
+		\param v2 \p vector input vector
+		\return \p vector direction vector
+	*/
+	static float Dot(vector v1, vector v2)
+	{
+		return ((v1[0] * v2[0]) + (v1[1] * v2[1]) + (v1[2] * v2[2]));
+	}
+
+	/**
+	\brief Returns relative angles between -180 and 180, not 0 to 360
+		\return \p float Relative angles
+		@code
+			vector angles = "-45 190 160";
+			Print( angles.GetRelAngles() );
+	
+			>> <-45,-170,160>
+		@endcode
+	*/
+	vector GetRelAngles()
+	{
+		for(int i = 0; i < 3; i++) {
+			if(value[i] > 180)
+				value[i] = value[i] - 360;
+			if(value[i] < -180)
+				value[i] = value[i] + 360;
+		}
+		return value;
+	}
+	
+	/**
+	\brief Returns yaw of vector
+		\param vec \p vector Vector to convert yaw
+		\return \p float Yaw of vector
+		@code
+			vector v1 = "0 1 0";
+			vector v2 = "0.7 0.7 0";
+			Print( v1.ToYaw() );
+			Print( v2.ToYaw() );
+
+			>> 90
+			>> 45
+		@endcode
+	*/
+	proto float VectorToYaw();
+
+	/**
+	\brief Returns vector of yaw
+		\param yaw \p float Value of yaw
+		\return \p vector Yaw converted in vector
+		@code
+			Print( vector.Yaw2Vector(90) );
+			Print( vector.Yaw2Vector(45) );
+
+			>> <0,1,0>
+			>> <0.707107,0.707107,0>
+		@endcode
+	*/
+	proto native static vector YawToVector(float yaw);
+
+	/**
+	\brief Converts vector to spherical coordinates with radius = 1
+		\return \p vector spherical coordinates (yaw, pitch, roll in degrees)
+		@code
+			vector v1 = "1 0 1";
+			vector v2 = "1 1 1";
+			Print( v1.VectorToAngles() );
+			Print( v2.VectorToAngles() );
+
+			>> <45,-0,0>
+			>> <45,35.2644,0>
+		@endcode
+	*/
+	proto vector VectorToAngles();
+
+	/**
+	\brief Converts spherical coordinates (yaw, pitch, roll in degrees) to unit length vector
+		\return \p normalized direction vector
+		@code
+			vector v1 = "45 0 0";
+			vector v2 = "15 60 0";
+			Print( v1.AnglesToVector() );
+			Print( v2.AnglesToVector() );
+
+			>> <0.707107,0,0.707107>
+			>> <0.12941,0.866025,0.482963>
+		@endcode
+	*/
+	proto vector AnglesToVector();
+
+	/**
+	\brief Creates rotation matrix from angles
+		\param ang \p vector which contains angles
+	    \param[out] mat \p vector created rotation matrix
+		@code
+	        vector mat[3];
+			vector ang = "70 15 45";
+	    	ang.RotationMatrixFromAngles( mat );
+	    	Print( mat );
+
+			>> <0.330366,0.0885213,-0.939693>,<0.458809,0.854988,0.241845>,<0.824835,-0.511037,0.241845>
+		@endcode
+	*/
+	proto void RotationMatrixFromAngles(out vector mat[3]);
+	
+	/**
+	\brief Transforms position
+		\param mat \p vector[4] transformation matrix
+		\param vec \p vector position to transform
+		\return \p vector transformed position
+		@code
+			vector mat[4] = { "1 0 0 0", "0 1 0 0", "0 0 1 1", "3 1 2 1" }; // translation matrix
+			vector pos = "1 1 1";
+			Print( pos.Multiply4(mat) );
+
+			>> <4,2,3>
+		@endcode
+	*/
+	proto vector Multiply4(vector mat[4]);
+
+	/**
+	\brief Transforms vector
+		\param mat \p vector[3] transformation matrix
+		\param vec \p vector vector to transform
+		\return \p vector transformed vector
+		@code
+			vector mat[3] = { "2 0 0", "0 3 0", "0 0 1" }; // scale matrix
+			vector vec = "1 1 1";
+			Print( vec.Multiply3(mat) );
+
+			>> <2,3,1>
+		@endcode
+	*/
+	proto vector Multiply3(vector mat[3]);
+
+	/**
+	\brief Invert-transforms position
+		\param mat \p vector[4] transformation matrix
+		\param vec \p vector position to transform
+		\return \p vector transformed position
+		@code
+			vector mat[4] = { "1 0 0 0", "0 1 0 0", "0 0 1 1", "3 1 2 1" }; // translation matrix
+			vector pos = "1 1 1";
+			Print( pos.InvMultiply4(mat) );
+
+			>> <-2,0,-1>
+		@endcode
+	*/
+	proto vector InvMultiply4(vector mat[4]);
+
+	/**
+	\brief Invert-transforms vector
+		\param mat \p vector[3] transformation matrix
+		\param vec \p vector vector to transform
+		\return \p vector transformed vector
+		@code
+			vector mat[3] = { "1.5 2.5 0", "0.1 1.3 0", "0 0 1" }; // rotation matrix
+			vector vec = "1 1 1";
+			Print( vec.InvMultiply3(mat) );
+
+			>> <4,1.4,1>
+		@endcode
+	*/
+	proto vector InvMultiply3(vector mat[3]);
+	
+	/**
+	\brief Lerp between two vectors
+		@code
+			vector v1 = Vector(0,0,0);
+			vector v2 = Vector(5,6,1);
+			Print( vector.Lerp(v1, v2, 0.5) );
+		@endcode
+	*/
+	proto static native vector Lerp(vector v1, vector v2, float t);
+	
+	/**
+	\brief Rotate a vector around 0,0,0 by an angle in degrees
+		\param vec \p vector to rotate
+		\param axis \p axis to rotate around
+		\param cosAngle \p angle in degrees
+		\return \p vector transformed vector
+	*/
+	
+	static vector RotateAroundZeroDeg(vector vec, vector axis, float angle)
+	{
+		return (vec * Math.Cos(angle * Math.DEG2RAD)) + ((axis * vec) * Math.Sin(angle * Math.DEG2RAD)) + (axis * vector.Dot(axis, vec)) * (1 - Math.Cos(angle * Math.DEG2RAD));
+	}
+	
+	/**
+	\brief Rotate a vector around 0,0,0 by an angle in radians
+		\param vec \p vector to rotate
+		\param axis \p axis to rotate around
+		\param cosAngle \p angle in radians
+		\return \p vector transformed vector
+	*/
+	
+	static vector RotateAroundZeroRad(vector vec, vector axis, float angle)
+	{
+		return (vec * Math.Cos(angle)) + ((axis * vec) * Math.Sin(angle)) + (axis * vector.Dot(axis, vec)) * (1 - Math.Cos(angle));
+	}
+	
+	/**
+	\brief Rotate a vector around 0,0,0
+		\param pos \p vector to rotate
+		\param axis \p axis to rotate around
+		\param cosAngle \p cos of angle
+		\param sinAngle \p sin of angle
+		\return \p vector transformed vector
+	*/
+	
+	static vector RotateAroundZero(vector pos, vector axis, float cosAngle, float sinAngle)
+	{
+		return (pos * cosAngle) + ((axis * pos) * sinAngle) + (axis * vector.Dot(axis, pos)) * (1 - cosAngle);
+	}
+	
+	/**
+	\brief Rotate a vector around point
+		\param point \p point to rotate around
+		\param pos \p vector to rotate
+		\param axis \p axis to rotate around
+		\param cosAngle \p cos of angle
+		\param sinAngle \p sin of angle
+		\return \p vector transformed vector
+	*/
+	static vector RotateAroundPoint(vector point, vector pos, vector axis, float cosAngle, float sinAngle)
+	{
+		vector offsetPos = pos - point;
+		return RotateAroundZero(offsetPos, axis, cosAngle, sinAngle) + point;
+	}
+	
+	/**
+	\brief Convert static array of floats into a vector
+	    \param arr \p vector in array format
+		\return \p vector resulting vector
+	*/
+	static vector ArrayToVec(float arr[])
+	{
+		return Vector(arr[0], arr[1], arr[2]);
+	}
+};
+
+class typename
+{
+	/**
+	\brief Dynamic variant to 'new' keyword. It creates new instance of class
+		\returns \p volatile instance of class
+		@code
+			???
+		@endcode
+	*/
+	proto volatile Class Spawn();
+	
+	/**
+	\brief Get the name of the module the typename belongs to
+		\returns \p string Name of parent module (1_Core)
+	*/
+	proto owned string GetModule();
+	
+	//!Returns type name of variable as string
+	proto native owned string ToString();
+	
+	/**
+	\brief Returns true when type is the same as 'baseType', or inherited one.
+		\param baseType typename
+		\returns \p bool true when type is the same as 'baseType', or inherited one.
+		@code
+			???
+		@endcode
+	*/
+	proto native bool IsInherited(typename baseType);
+	
+	proto native int GetVariableCount();
+	proto native owned string GetVariableName(int vIdx);
+	proto native typename GetVariableType(int vIdx);
+	proto bool GetVariableValue(Class var, int vIdx, out void val);
+	
+	/**
+	\brief Return string name of enum value
+	@code
+		DialogPriority prio = DialogPriority.WARNING;
+		Print( typename.EnumToString(DialogPriority, prio) );
+	@endcode
+	*/
+	static string EnumToString(typename e, int enumValue)
+	{
+		int cnt = e.GetVariableCount();
+		int val;
+
+		for (int i = 0; i < cnt; i++)
+		{
+			if (e.GetVariableType(i) == int && e.GetVariableValue(null, i, val) && val == enumValue)
+			{
+				return e.GetVariableName(i);
+			}
+		}
+				
+		return "unknown";
+	}
+	
+	/**
+	\brief Return enum value from string name
+	@code
+		Print( typename.StringToEnum(DialogPriority, "WARNING") );
+	@endcode
+	*/
+	static int StringToEnum(typename e, string enumName)
+	{
+	    int count = e.GetVariableCount();
+	    int value;
+	   
+	    for (int i = 0; i < count; i++)
+	    {
+	        if (e.GetVariableType(i) == int && e.GetVariableValue(null, i, value) && e.GetVariableName(i) == enumName)
+	        {
+	            return value;
+	        }
+	    }
+		
+	    return -1;
+	}
+};
+
+class EnumTools
+{
+	private void EnumTools();
+	private void ~EnumTools();
+	
+	/**
+	\brief Return string name of enum value
+	@code
+		DialogPriority prio = DialogPriority.WARNING;
+		Print( EnumTools.EnumToString(DialogPriority, prio) );
+	@endcode
+	*/
+	static string EnumToString(typename e, int enumValue)
+	{
+		return typename.EnumToString(e, enumValue);
+	}
+	
+	/**
+	\brief Return enum value from string name
+	@code
+		Print( EnumTools.StringToEnum(DialogPriority, "WARNING") );
+	@endcode
+	*/
+	static int StringToEnum(typename e, string enumName)
+	{
+		return typename.StringToEnum(e, enumName);
+	}
+	
+	/**
+	\brief Return amount of values in enum
+	@code
+		Print( EnumTools.GetEnumSize(DialogPriority) );
+	@endcode
+	*/
+	static int GetEnumSize(typename e)
+	{
+		return e.GetVariableCount();
+	}
+	
+	/**
+	\brief Return the nth value in the enum
+	@code
+		Print( EnumTools.GetEnumValue(DialogPriority, 1) );
+	@endcode
+	*/
+	static int GetEnumValue(typename e, int idx)
+	{
+		int value;
+		e.GetVariableValue(null, idx, value);		
+		return value;
+	}
+	
+	/**
+	\brief Return amount of values in enum
+	@code
+		Print( EnumTools.GetLastEnumValue(DialogPriority) );
+	@endcode
+	*/
+	static int GetLastEnumValue(typename e)
+	{
+		int lastValue;
+		e.GetVariableValue(null, e.GetVariableCount() - 1, lastValue);		
+		return lastValue;
+	}
+}

+ 341 - 0
Scripts/1_core/proto/endebug.c

@@ -0,0 +1,341 @@
+/**
+ * \defgroup Debug Debug utilities
+ * @{
+ */
+
+/**
+\brief Prints current call stack (stack trace)
+	\return \p void
+	@code
+		DumpStack();
+
+	@endcode
+
+	\verbatim
+	Output:
+		-- Stack trace --
+	   SaveFile() Scripts\Entities\Modules\ModuleBase\ModuleFileHandler.c : 51
+	   SaveConfigToFile() Scripts\Entities\Modules\ModuleBase\ModuleFileHandler\ModuleLocalProfile.c : 114
+	   SaveParameterArray() Scripts\Entities\Modules\ModuleBase\ModuleFileHandler\ModuleLocalProfile.c : 133
+	   SetParameterArray() Scripts\Entities\Modules\ModuleBase\ModuleFileHandler\ModuleLocalProfile.c : 231
+	   PresetAdd() Scripts\Entities\Modules\ModuleBase\ModuleFileHandler\ModuleLocalProfile\ModuleLocalProfileUI.h : 46
+	   OnKeyPress() Scripts/mission/missionGameplay.c : 215
+	   OnKeyPress() Scripts/DayZGame.c : 334
+	   -----------------
+	\endverbatim
+*/
+proto void DumpStack();
+
+/**
+\brief Prints current call stack (stack trace) to given output
+	\return \p void
+	@code
+    string tmp;
+		DumpStackString(tmp);
+    Print(tmp);
+
+	@endcode
+
+	\verbatim
+	Output:
+	  SaveFile() Scripts\Entities\Modules\ModuleBase\ModuleFileHandler.c : 51
+	  SaveConfigToFile() Scripts\Entities\Modules\ModuleBase\ModuleFileHandler\ModuleLocalProfile.c : 114
+	  SaveParameterArray() Scripts\Entities\Modules\ModuleBase\ModuleFileHandler\ModuleLocalProfile.c : 133
+	  SetParameterArray() Scripts\Entities\Modules\ModuleBase\ModuleFileHandler\ModuleLocalProfile.c : 231
+	  PresetAdd() Scripts\Entities\Modules\ModuleBase\ModuleFileHandler\ModuleLocalProfile\ModuleLocalProfileUI.h : 46
+	  OnKeyPress() Scripts/mission/missionGameplay.c : 215
+	  OnKeyPress() Scripts/DayZGame.c : 334
+	\endverbatim
+*/
+proto void DumpStackString(out string stack);
+
+//! Triggers breakpoint in C++ in run time(when app is running in debug enviroment)
+proto void DebugBreak(bool condition = true, void param1 = NULL, void param2 = NULL, void param3 = NULL, void param4 = NULL, void param5 = NULL, void param6 = NULL, void param7 = NULL, void param8 = NULL, void param9 = NULL);
+
+//! Triggers breakpoint in C++ in compile time(when app is running in debug enviroment)
+void CompileBreak();
+
+//! Prints content of variable to console/log. Should be used for critical messages so it will appear in debug log
+proto void DPrint(string var);
+
+enum ErrorExSeverity
+{
+	INFO,
+	WARNING,
+	ERROR,
+}
+
+/**
+\brief Error message, prefixed by method name, above 'INFO' will show a messagebox
+	\note Format: [%className%::%methodName%] :: [%severity%] :: %errString%
+	\param \p string Error message to use
+	@code
+	class ErrorExTest
+	{
+		void ThrowWarning()
+		{
+			// [ErrorExTest::ThrowWarning] :: [WARNING] :: This is a warning.
+			ErrorEx("This is a warning.", ErrorExSeverity.WARNING);		
+		}
+	}
+	@endcode
+*/
+proto void ErrorEx(string err, ErrorExSeverity severity = ErrorExSeverity.ERROR);
+proto void ErrorExString(string err, out string str, ErrorExSeverity severity = ErrorExSeverity.ERROR);
+
+//! Messagebox with error message
+proto native void Error2(string title, string err);
+
+//! Messagebox with error message
+void Error(string err)
+{
+	Error2("", err);
+}
+
+//!Prints content of variable to console/log
+proto void Print(void var);
+
+//!Prints content of variable to RPT file (performance warning - each write means fflush! use with care)
+proto void PrintToRPT(void var);
+	
+/**
+\brief Prints formated text to console/log
+	@code
+		string c = "Peter";
+		PrintFormat("Hello %1, how are you?", c); // prints "Hello 'Peter', how are you?"
+	@endcode
+*/	
+proto void PrintFormat(string fmt, void param1 = NULL, void param2 = NULL, void param3 = NULL, void param4 = NULL, void param5 = NULL, void param6 = NULL, void param7 = NULL, void param8 = NULL, void param9 = NULL);
+
+	//------------------------------------------
+/**
+ * \defgroup DebugShape Debug Shape API definition
+ * @{
+ */
+enum ShapeType
+{
+	BBOX,			//<	Just box
+	LINE,			//<	One or more lines
+	SPHERE,		//<	Sphere represented by triangle mesh
+	CYLINDER,	//<	Cylinder represented by triangle mesh
+	DIAMOND,	//< Eight faced pyramid. Defined by bound-box, where middle part is  equal to horizontal extents of box and top/bottom apogees lies on top/bottom side of box.
+	PYRAMID	//< Four sided pyramid. Defined by bound-box, where base is equal to bottom side of box.
+};
+
+enum ShapeFlags
+{
+	NOZBUFFER,	//< Do not compare z-buffer when render
+	NOZWRITE,		//< Do not update z-buffer when render
+	WIREFRAME,	//< Render just wire-frame outline. No solid faces
+	TRANSP,			//< Is translucent
+	DOUBLESIDE,	//< Double-sided (do not cull back-faces)
+	ONCE,				//< Rendered just once and then it's automatically destroyed. Do not keep pointer to these!!
+	NOOUTLINE,	//< Render just solid faces. No wire-frame outline.
+	BACKFACE,		//< Render just back faces
+	NOCULL,			//< Do not cull shapes by view frustum
+	VISIBLE,		//< Make it visible. Set by default
+	ADDITIVE		//< Additive blending (works with ShapeFlags.TRANSP)
+};
+
+enum CollisionFlags
+{
+	FIRSTCONTACT,	//<In many cases only collided=true/false is enough
+	NEARESTCONTACT	//<We want only one, the nearest contact
+	ONLYSTATIC		//<Only static objects
+	ONLYDYNAMIC		//<Only dynamic objects
+	ONLYWATER		//<Only water components (legacy support for "walk on geometry")
+	ALLOBJECTS		//<Valid when CF_FIRST_CONTACT, we get first contact for each object
+}
+		
+/*!
+Instance of created debug visualizer
+*/
+class Shape
+{
+	//!don't call destructor directly. Use Destroy() instead
+	proto private void ~Shape();
+
+	proto native void GetMatrix(out vector mat[4]);
+	proto native void SetMatrix(vector mat[4]);
+	proto native void SetDirection(vector direction);
+	proto native void SetPosition(vector position);
+	proto native void SetColor(int color);
+	proto native void SetFlags(ShapeFlags flags);
+	proto native void Destroy();
+
+	proto static native Shape Create(ShapeType type, int color, ShapeFlags flags, vector p1, vector p2);
+	proto static native Shape CreateLines(int color, ShapeFlags flags, vector p[], int num);
+	proto static native Shape CreateTris(int color, ShapeFlags flags, vector p[], int num);
+	proto static native Shape CreateSphere(int color, ShapeFlags flags, vector origin, float radius);
+	proto static native Shape CreateFrustum(float horizontalAngle, float verticalAngle, float length, int color, ShapeFlags flags);
+	proto static native Shape CreateCylinder(int color, ShapeFlags flags, vector origin, float radius, float length);
+
+	static Shape CreateArrow(vector from, vector to, float size, int color, ShapeFlags flags)
+	{
+		vector dir = to - from;
+		dir.Normalize();
+		vector dir1 = dir * size;
+		size = size * 0.5;
+	
+		vector dir2 = dir.Perpend() * size;
+	
+		vector pts[5];
+		pts[0] = from;
+		pts[1] = to;
+		pts[2] = to - dir1 - dir2;
+		pts[3] = to - dir1 + dir2;
+		pts[4] = to;
+	
+		return CreateLines(color, flags, pts, 5);
+	}
+
+	static Shape CreateBridgeArrow(vector from, vector to, float size, int color, ShapeFlags flags)
+	{
+		vector dir = to - from;
+		dir.Normalize();
+	
+		vector dir1 = Vector(0, 0, -size);
+		size = size * 0.5;
+	
+		vector dir2 = dir.Perpend() * size;
+	
+		vector pts[7];
+		pts[0] = from;
+		pts[1] = from + "0 0 1";
+		pts[2] = to + "0 0 1";
+		pts[3] = to;
+		pts[4] = to - dir1 - dir2;
+		pts[5] = to - dir1 + dir2;
+		pts[6] = to;
+	
+		return CreateLines(color, flags, pts, 7);
+	}
+
+	static void CreateMatrix(vector mat[4])
+	{
+		vector org = mat[3];
+		int flags = ShapeFlags.NOZWRITE|ShapeFlags.DOUBLESIDE|ShapeFlags.TRANSP|ShapeFlags.ONCE;
+		Create(ShapeType.LINE, 0xffff0000, flags, org, mat[0] * 0.5 + org);
+		Create(ShapeType.LINE, 0xff00ff00, flags, org, mat[1] * 0.5 + org);
+		Create(ShapeType.LINE, 0xff0000ff, flags, org, mat[2] * 0.5 + org);
+	}
+};
+
+//@}
+
+
+//------------------------------------------
+/**
+ * \defgroup DiagMenu Diag menu API definition
+ * @{
+ */
+class DiagMenu
+{
+	//! Checks if DiagMenu is initialized
+	static proto bool IsInitialized();
+	
+	//! To be used before registering scripted diags
+	static proto void InitScriptDiags();
+	//! To be used when scripted diags should not be present
+	static proto void ClearScriptDiags();
+	
+	/**
+	\brief Register a new menu
+		\param id \p int The unique ID of the menu in the range [0,512]
+		\param name \p string The name of the menu
+		\param parent \p int The index of the parent of the menu
+	*/
+	static proto void RegisterMenu(int id, string name, int parent);
+	
+	/**
+	\brief Register a new item
+		\param id \p int The unique ID of the item in the range [0,512]
+		\param shortcut \p string The keyboard shortcut of the item
+		\param name \p string The name of the item
+		\param parent \p int The index of the parent of the item
+		\param values \p string The values of the item separated by commas, internally this will be an int starting at 0 for the first item
+		\param callback \p func Callback to call when the value is changed (OPTIONAL) (Also read BindCallback)
+	*/
+	static proto void RegisterItem(int id, string shortcut, string name, int parent, string values, func callback = null);
+	
+	/**
+	\brief Register a new bool item
+	\note This is just a RegisterItem with value="true,false" or when reversed value="false,true"
+		\param id \p int The unique ID of the item in the range [0,512]
+		\param shortcut \p string The keyboard shortcut of the item
+		\param name \p string The name of the item
+		\param parent \p string The index of the parent of the item
+		\param values \p string The values of the item, separated by commas
+		\param reverse \p bool Whether to reverse the bool (OPTIONAL)
+		\param callback \p func Callback to call when the value is changed (OPTIONAL) (Also read BindCallback)
+	*/
+	static proto void RegisterBool(int id, string shortcut, string name, int parent, bool reverse = false, func callback = null);
+
+	/**
+	\brief Register a new range item
+		\param id \p int The unique ID of the item in the range [0,512]
+		\param shortcut \p string The keyboard shortcut of the item
+		\param name \p string The name of the item
+		\param parent \p int The index of the parent of the item
+		\param values \p string Range specification in format "min,max,startValue,step"
+		\param callback \p func Callback to call when the value is changed (OPTIONAL) (Also read BindCallback)
+	*/
+	static proto void RegisterRange(int id, string shortcut, string name, int parent, string valuenames, func callback = null);
+	
+	//! Unregister the item at given id
+	static proto void Unregister(int id);
+	
+	//! Check if the item at given id has been registered
+	static proto bool IsRegistered(int id);
+	
+	/**
+	*\brief Bind a callback to the given id
+	*	\note Only one callback can be registered, so when attempting to registering multiple, only the last one will be present
+	*	\note The callbacks are required to have one of following signatures
+	*		- All Register... support:
+	*			o static void Callback();
+	*		- RegisterItem & RegisterBool:
+	*			o static void Callback(int value);
+	*			o static void Callback(int value, int id);
+	*			o static void Callback(bool value);
+	*			o static void Callback(bool value, int id);
+	*		- RegisterRange:
+	*			o static void Callback(float value);
+	*			o static void Callback(float value, int id);
+	*			o static void Callback(int value);
+	*			o static void Callback(int value, int id);
+	*	\note Keep in mind that bool and int are interchangeable, so 'bool value' is possible for RegisterRange too
+	*/
+	static proto bool BindCallback(int id, func callback);
+	//! Unbind the callback from the given id
+	static proto void UnbindCallback(int id);
+	
+	//! Get value as bool from the given script id
+	static proto bool GetBool(int id, bool reverse = false);
+	//! Get value as int from the given script id
+	static proto int GetValue(int id);
+	//! Set value at the given script id
+	static proto void SetValue(int id, int value);
+	
+	//! Get range value at the given script id 
+	static proto float GetRangeValue(int id);
+	//! Set range value at the given script id
+	static proto void SetRangeValue(int id, float value);
+	
+	//! Get value at the given engine id
+	static proto int GetEngineValue(int id);
+	//! Set value at the given engine id
+	static proto void SetEngineValue(int id, int value);
+	
+	//! Get range value at the given engine id
+	static proto float GetEngineRangeValue(int id);
+	//! Set range value at the given engine id
+	static proto void SetEngineRangeValue(int id, float value);
+	
+	//! Check if a menu with supplied name already exists
+	static proto bool MenuExists(string name);	
+};
+
+//@}
+
+//@}

+ 870 - 0
Scripts/1_core/proto/enentity.c

@@ -0,0 +1,870 @@
+typedef int[] BaseContainer;		
+typedef int[] IEntitySource;
+typedef int[] WidgetSource;
+	
+class BaseContainer	
+{
+	proto native owned string GetClassName();
+	proto native owned string GetName();
+	proto native int VarIndex(string varName);
+	proto native bool IsVariableSet(int varIndex);
+	proto bool IsType(int varIndex, typename type);
+	proto bool Get(int varIndex, out void val);
+};
+
+class IEntitySource: BaseContainer
+{
+	proto native IEntitySource GetChildren();
+	proto native IEntitySource GetSibling();
+	proto native IEntitySource GetParent();
+};
+
+class WidgetSource: BaseContainer
+{
+	proto native WidgetSource GetChildren();
+	proto native WidgetSource GetSibling();
+	proto native WidgetSource GetParent();
+};
+
+/**
+ * \defgroup EntityAPI Entity system
+ * @{
+ */
+
+/**
+ * \defgroup EntityAttributes Entity editor attribute system
+ * @{
+ */
+
+		
+		
+//@}
+	
+ //!Entity events for event-mask, or throwing event from code
+enum EntityEvent
+{
+	//! entity was touched by other entity
+	TOUCH,
+
+	/*!
+	entity is visible, so part of the rendering
+	other		WorldClass
+	extra		frame index
+	result	false should be rendered, true shoudn't be rendered
+	*/
+	VISIBLE, 
+	
+	/*!
+	entity is not visible, will not be part of rendering
+	other		WorldClass
+	extra		frame index
+	*/
+	NOTVISIBLE, 
+
+	/*!
+	new frame event, called each frame
+	other		WorldClass
+	extra		frame index
+	*/
+	FRAME,
+
+	/*!
+	event at the end of each frame or when entity is moved during the frame
+	other		WorldClass
+	*/
+	POSTFRAME,
+
+	/*!
+	event called after the world is created, including all entities
+	other		WorldClass
+	*/
+	INIT,      	
+
+//Only with MeshObject
+//ANIMEND	- End of AF_ONCE animation, extra = slot number 0...11
+//ANIMBLEND - Animation blended from previous one, extra = slot number 0...11
+
+
+//SOUNDEND	- playing of SFL_ONCE sound has ended
+// extra		= pointer to a sound handle
+
+//USER
+
+	JOINTBREAK,
+	SIMULATE,
+	POSTSIMULATE,
+	PHYSICSMOVE,
+	CONTACT,
+	EXTRA,
+	ANIMEVENT,
+	SOUNDEVENT,
+	PHYSICSSTEADY,
+	USER,
+	
+	//! Object entered Trigger
+	ENTER,
+	//! Object left Trigger
+	LEAVE,
+	
+	//!Mask of all events
+	ALL
+};
+
+//!Entity flags
+enum EntityFlags
+{
+/*!
+Entity is visible. Is rendered if there is some attached object
+and event EntityEvent.VISIBLE is invoked, when event mask is set.
+*/
+	VISIBLE,
+
+
+	SOLID,	///<Is collidable by various trace methods
+	TRIGGER,	///<Is not collidable, but invokes touch events.
+	TOUCHTRIGGERS,	///<Interacts with triggers
+	SYNCHRONIZATION_DIRTY,	///<Entity wants to synchronize (network)
+
+	FEATURE,	///<Scene rendering hint for dominant objects that are not culled by standard way
+/*!
+Used by tracing methods. When tracing with TraceFlags.PASSTRANSLUCENT,
+then this entity is ignored. Used for glass for example.
+*/
+	TRANSLUCENT,
+
+//!Used by tracing methods. Traceable only with flag TraceFlags.WATER
+	WATER,
+
+/*!
+Tells that this entity has to be actively updated by engine, its
+EntityEvent.FRAME has to be called etc.
+*/
+	ACTIVE,
+
+/*!
+Tells that this entity will represent mostly static object, so
+we can use more precise but slower methods for scene-tree linking.
+Also it tells to scene tree that he can count with this entity as
+tree-split hint.
+*/
+	STATIC,
+
+//!Flags for custom usage and filterings.
+	USER1,
+	USER2,
+	USER3,
+	USER4,
+	USER5,
+	USER6
+};
+
+/*!
+Internal ancestor of all Entity implementations.
+*/
+class IEntity: Managed
+{
+//DO NOT INSERT ANYTHING BELOW - order of event methods matters!
+/** \name Event methods
+ Event method stubs. Reimplement these in inherited entities to receive event calls			
+*/
+//@{
+	event protected void EOnTouch(IEntity other, int extra) //!EntityEvent.TOUCH
+	{
+	}
+	event protected void EOnInit(IEntity other, int extra) //!EntityEvent.INIT
+	{
+	}
+	event protected void EOnExtra(IEntity other, int extra)	//!EntityEvent.EXTRA
+	{
+	}
+	event protected void EOnNotVisible(IEntity other, int extra) //!EntityEvent.NOTVISIBLE
+	{
+	}
+	event protected void EOnFrame(IEntity other, float timeSlice) //!EntityEvent.FRAME
+	{
+	}
+	event protected int  EOnVisible(IEntity other, int extra) //!EntityEvent.VISIBLE
+	{
+	}
+	event protected void EOnPostFrame(IEntity other, int extra) //!EntityEvent.POSTFRAME
+	{
+	}
+	event protected void EOnWorldProcess(IEntity other, int extra) //!EntityEvent.WORLDPROCESS
+	{
+	}
+	event protected void EOnAnimEvent(IEntity other, AnimEvent extra) //!EntityEvent.ANIMEVENT
+	{
+	}
+	event protected void EOnSoundEvent(IEntity other, SoundEvent extra) //!EntityEvent.SOUNDEVENT
+	{
+	}
+	event protected void EOnSimulate(IEntity other, float dt) //!EntityEvent.SIMULATE
+	{
+	}
+	event protected void EOnPostSimulate(IEntity other, float timeSlice)	//!EntityEvent.POSTSIMULATE
+	{
+	}
+	event protected void EOnJointBreak(IEntity other, int extra) //!EntityEvent.JOINTBREAK
+	{
+	}
+	event protected void EOnPhysicsMove(IEntity other, int extra) //!EntityEvent.PHYSICSMOVE
+	{
+	}
+	event protected void EOnContact(IEntity other, Contact extra) //!EntityEvent.CONTACT
+	{
+	}
+	protected void EOnUser0(IEntity other, int extra) //!EntityEvent.EV_USER+0
+	{
+	}
+	protected void EOnUser1(IEntity other, int extra) //!EntityEvent.EV_USER+1
+	{
+	}
+	event protected void EOnEnter(IEntity other, int extra) //!EntityEvent.ENTER
+	{
+	}
+	event protected void EOnLeave(IEntity other, int extra) //!EntityEvent.LEAVE
+	{
+	}
+	protected void EOnUser4(IEntity other, int extra) //!EntityEvent.EV_USER+4
+	{
+	}
+	protected void EOnDummy020(IEntity other, int extra)	//!Placeholder
+	{
+	}
+	protected void EOnDummy021(IEntity other, int extra)	//!Placeholder
+	{
+	}
+	protected void EOnDummy022(IEntity other, int extra)	//!Placeholder
+	{
+	}
+	protected void EOnDummy023(IEntity other, int extra)	//!Placeholder
+	{
+	}
+	protected void EOnDummy024(IEntity other, int extra)	//!Placeholder
+	{
+	}
+	protected void EOnDummy025(IEntity other, int extra)	//!Placeholder
+	{
+	}
+	protected void EOnDummy026(IEntity other, int extra)	//!Placeholder
+	{
+	}
+	protected void EOnDummy027(IEntity other, int extra)	//!Placeholder
+	{
+	}
+	protected void EOnDummy028(IEntity other, int extra)	//!Placeholder
+	{
+	}
+	protected void EOnDummy029(IEntity other, int extra)	//!Placeholder
+	{
+	}
+	protected void EOnDummy030(IEntity other, int extra)	//!Placeholder
+	{
+	}
+	protected void EOnDummy031(IEntity other, int extra)	//!Placeholder
+	{
+	}
+//@}
+//DO NOT INSERT ANYTHING ABOVE - order of event methods matters!
+
+	/** \name Transformation methods
+		Setting and getting of entity transformation
+	*/
+	//@{
+
+	/**
+	\brief Returns transformation of Entity. It returns only so much vectors as array is big
+		\param mat \p vector[1...4] matrix to be get
+		@code
+			Man player = g_Game.GetPlayer();
+	
+			vector mat[4];
+			player.GetTransform(mat);
+			Print( mat );
+	
+			>> <0.989879,-0,0.141916>,<0,1,0>,<-0.141916,0,0.989879>,<2545.08,15.6754,2867.49>
+		@endcode
+	*/
+	proto external void GetTransform(out vector mat[]);
+
+	/**
+	\brief Returns render transformation of Entity. Must pass in vector array size of 4
+		\param mat \p vector[4] matrix to be get
+		@code
+			Man player = g_Game.GetPlayer();
+	
+			vector mat[4];
+			player.GetRenderTransform(mat);
+			Print( mat );
+	
+			>> <0.989879,-0,0.141916>,<0,1,0>,<-0.141916,0,0.989879>,<2545.08,15.6754,2867.49>
+		@endcode
+	*/
+	proto external void GetRenderTransform(out vector mat[]);
+
+	/**
+	\brief Returns local transformation of Entity. It returns only so much vectors as array is big
+		\param mat \p vector[1...4] matrix to be get
+		@code
+			Man player = g_Game.GetPlayer();
+	
+			vector mat[4];
+			player.GetTransform(mat);
+			Print( mat );
+	
+			>> <0.989879,-0,0.141916>,<0,1,0>,<-0.141916,0,0.989879>,<2545.08,15.6754,2867.49>
+		@endcode
+	*/
+	proto external void GetLocalTransform(out vector mat[]);
+
+	/**
+	\brief Returns one row of Entity transformation matrix
+		\param axis \p int matrix axis. Can be 0..3
+		\return \p vector axis row of Entity matrix
+		@code
+			Man player = g_Game.GetPlayer();
+			Print( player.GetTransformAxis(0) );
+			Print( player.GetTransformAxis(1) );
+			Print( player.GetTransformAxis(2) );
+			Print( player.GetTransformAxis(3) );
+	
+			>> <-0.386781,0,0.922171>
+			>> <0,1,0>
+			>> <-0.922171,0,-0.386782>
+			>> <2551.34,15.6439,2856.72>
+		@endcode
+	*/
+	proto native external vector GetTransformAxis(int axis);
+
+	/**
+	\brief Sets entity transformation
+		\param mat \p vector[4] matrix to be set
+		@code
+			vector mat[4];
+			Math3D.MatrixIdentity( mat )
+	
+			Man player = g_Game.GetPlayer();
+			player.SetTransform( mat );
+	
+			vector outmat[4];
+			player.GetTransform(outmat );
+			Print( outmat );
+	
+			>> <1,0,0>,<0,1,0>,<0,0,1>,<0,0,0>
+		@endcode
+	*/
+	proto native external void SetTransform(vector mat[4]);
+
+	/**
+	\brief Returns origin of Entity
+		\return \p vector entity origin
+		@code
+			Man player = g_Game.GetPlayer();
+			Print( player.GetOrigin() );
+	
+			>> <2577.02,15.6837,2924.27>
+		@endcode
+	*/
+	proto native external vector GetOrigin();
+	
+	/**
+	\brief Returns local position of Entity
+		\return \p vector entity local position
+		@code
+			Man player = g_Game.GetPlayer();
+			Print( player.GetOrigin() );
+	
+			>> <2577.02,15.6837,2924.27>
+		@endcode
+	*/
+	proto external vector GetLocalPosition();
+	
+	/**
+	\brief Returns orientation of Entity in world space (Yaw, Pitch, Roll)
+		\return \p vector entity orientation
+		@code
+			Man player = g_Game.GetPlayer();
+			Print( player.GetYawPitchRoll() );
+	
+			>> <180,-76.5987,180>
+		@endcode
+	*/
+	proto native external vector GetYawPitchRoll();
+
+	/**
+	\brief Same as GetYawPitchRoll, but returns rotation vector around X, Y and Z axis.
+	*/
+	proto native external vector GetAngles();
+
+	/**
+	\brief Returns local orientation when it's in hierarchy (Yaw, Pitch, Roll)
+		\return \p vector local orientation
+		@code
+			Man player = g_Game.GetPlayer();
+			Print( player.GetLocalYawPitchRoll() );
+	
+			>> <180,-57.2585,180>
+		@endcode
+	*/
+	proto native external vector GetLocalYawPitchRoll();
+
+	/**
+	\brief Same as GetLocalYawPitchRoll, but returns rotation vector around X, Y and Z axis.
+	*/
+	proto native external vector GetLocalAngles();
+
+	/**
+	\brief Sets angles for entity (Yaw, Pitch, Roll)
+		\param angles \p vector angles to be set
+		@code
+			Man player = g_Game.GetPlayer();
+			player.SetYawPitchRoll("180 50 180" );
+			Print( player.GetYawPitchRoll() );
+	
+			>> <-180,50,-180>
+		@endcode
+	*/
+	proto native external void SetYawPitchRoll(vector angles);
+
+	/**
+	\brief Same as SetYawPitchRoll, but sets rotation around X, Y and Z axis.
+	*/
+	proto native external void SetAngles(vector angles);
+	
+	/**
+	\brief Sets origin for entity
+		\param orig \p vector origin to be set
+		@code
+			Man player = g_Game.GetPlayer();
+			player.SetOrigin("2550 10 2900" );
+			Print( player.GetOrigin() );
+	
+			>> <2550,10,2900>
+		@endcode
+	*/
+	proto native external void SetOrigin(vector orig);
+
+	proto native external float GetScale();
+	proto native external void SetScale(float scale);
+	/**
+	\brief Transforms local vector to world space
+	    \param vec \p vector local space vector to transform
+		\return \p vector world space vector
+		@code
+			Man player = g_Game.GetPlayer();
+			Print( player.VectorToParent("1 2 3") );
+
+			>> <2.89791,2,1.26575>
+		@endcode
+	*/
+	proto native external vector VectorToParent(vector vec);
+
+	/**
+	\brief Transforms local position to world space
+		\param coord \p vector local position to transform
+		\return \p vector position in world space
+		@code
+			Man player = g_Game.GetPlayer();
+			Print( player.CoordToParent("1 2 3") );
+
+			>> <2549,17.6478,2857>
+		@endcode
+	*/
+	proto native external vector CoordToParent(vector coord);
+
+	/**
+	\brief Transforms world space vector to local space
+		\param vec \p vector world space vector to transform
+		\return \p vector local space vector
+		@code
+			Man player = g_Game.GetPlayer();
+			Print( player.VectorToLocal("2 1 5") );
+
+			>> <-0.166849,1,5.38258>
+		@endcode
+	*/
+	proto native external vector VectorToLocal(vector vec);
+
+	/**
+	\brief Transforms world space position to local space
+		\param coord \p vector world space position to transform
+		\return \p vector position in local space
+		@code
+			Man player = g_Game.GetPlayer();
+			Print( player.CoordToLocal("500 10 155") );
+
+			>> <15254,-54.2004,8745.53>
+		@endcode
+	*/
+	proto native external vector CoordToLocal(vector coord);
+
+	//@}
+
+
+	/** \name Name/ID methods		
+	*/
+	//@{
+
+	/**
+	\brief Return unique entity ID
+		\return \p int unique entity ID
+		@code
+			ItemBase apple = g_Game.CreateObject( "FruitApple", String2Vector("0 10 0"), false );
+			Print( apple.GetID() );
+
+			>> 0
+		@endcode
+	*/
+	proto native int GetID();
+
+	/**
+	\brief Set unique entity ID
+		\param id \p int unique entity ID to be set
+		@code
+			ItemBase apple = g_Game.CreateObject( "Fruit_Apple", String2Vector("0 10 0"), false );
+			apple.SetID(101);
+			Print( apple.GetID() );
+
+			>> 101
+		@endcode
+	*/
+	proto native void SetID(int id);
+	
+	proto native void SetName(string name);
+	proto native external owned string GetName();
+	//@}
+	
+
+	/** \name Hierarchy methods
+		Scene hierarchy management
+	*/
+	//@{
+
+	/**
+	\brief Adds child entity to this entity.
+		\note Make sure the parent is not ToDelete
+		\param child \p IEntity Pointer to entity which become our child
+		\param pivot \p int Pivot is pivot index, or -1 for center of parent.
+		\param positionOnly \p bool When set to true, the orientation will still be in WS.
+		\return \p bool True when entity has been attached. False otherwise.
+	*/
+	proto native external bool AddChild(notnull IEntity child, int pivot, bool positionOnly = false);
+	
+	/**
+	\brief Removes child entity from hierarchy.
+		\note Make sure the child is not ToDelete
+		\param child \p IEntity Pointer to child entity we want to remove.
+		\param keepTransform \p bool When set to true, Entity is kept on her world position. Otherwise it's local transform is used as world-space one.
+		\return \p bool True if it was removed, false when this entity is not our child.
+	*/
+	proto native external bool RemoveChild(notnull IEntity child, bool keepTransform = false);
+	
+	//! Returns if the hierarchy component was created with positionOnly
+	proto native bool IsHierarchyPositionOnly();
+
+	//! Returns the hierarchy component pivot
+	proto native int GetHierarchyPivot();
+
+	//! Returns pointer to parent Entity in hierarchy
+	proto native IEntity GetParent();
+	//! Returns pointer to first child Entity in hierarchy
+	proto native IEntity GetChildren();
+	//! Returns pointer to next child Entity on the same hierarchy
+	proto native IEntity GetSibling();
+	//@}
+
+	/**
+	\brief Returns local bounding box of model on Entity
+		\param[out] mins \p vector minimum point of bounding box
+		\param[out] maxs \p vector maximum point of bounding box
+		@code
+			Man player = g_Game.GetPlayer();
+	
+			vector mins, maxs;
+			player.GetBounds(mins, maxs );
+	
+			Print( mins );
+			Print( maxs );
+	
+			>> <0,0,0>
+			>> <0,0,0>
+		@endcode
+	*/
+	proto external void GetBounds(out vector mins, out vector maxs);
+	
+	/**
+	\brief Returns quantized world-bound-box of Entity
+		\param[out] mins \p vector minimum point of bounding box
+		\param[out] maxs \p vector maximum point of bounding box
+		@code
+			Man player = g_Game.GetPlayer();
+	
+			vector mins, maxs;
+			player.GetWorldBounds( mins, maxs );
+	
+			Print( mins );
+			Print( maxs );
+	
+			>> <2547.2,15.5478,2852.85>
+			>> <2548.8,17.5478,2855.05>
+		@endcode
+	*/
+	proto external void GetWorldBounds(out vector mins, out vector maxs);
+	
+	/** \name Simulation/handling properties
+	Flags that affects simulation and entity handling behavior
+	*/
+	//@{
+	/**
+	\brief Returns Entity flags
+		\return \p EntityFlags entity flags
+		@code
+			Man player = g_Game.GetPlayer();
+			Print( player.GetFlags() );
+	
+			>> 1610612745
+		@endcode
+	*/
+	proto native external EntityFlags GetFlags();
+	
+	/**
+	\brief Test if one or more of specified flags are set
+		\return \p bool True if is set, false otherwise.
+		@code
+			Man player = g_Game.GetPlayer();
+			player.SetFlags(EntityFlags.VISIBLE);
+			Print( player.IsFlagSet(EntityFlags.VISIBLE) );
+	
+			>> true
+		@endcode
+	*/
+	proto native external bool IsFlagSet(EntityFlags flags);
+
+	/**
+	\brief Sets Entity flags. It's OR operation, not rewrite. Returns previous flags
+		\param flags \p int flags to be set
+		\param recursively flags will be recursively applied to children of hierarchy too
+		\return \p int previous flags
+		@code
+			Man player = g_Game.GetPlayer();
+			player.SetFlags(EntityFlags.VISIBLE|EntityFlags.SOLID );
+			Print( player.GetFlags() );
+	
+			>> 1610612747
+		@endcode
+	*/
+	proto native external EntityFlags SetFlags(EntityFlags flags, bool recursively);
+
+	/**
+	\brief Clear Entity flags. Returns cleared flags
+		\param flags \p int flags to be set
+		\param recursively flags will be recursively applied to children of hierarchy too
+		\return \p int cleared flags
+		@code
+			Man player = g_Game.GetPlayer();
+			player.ClearFlags(EntityFlags.VISIBLE|EntityFlags.SOLID );
+			Print( player.GetFlags() );
+	
+			>> 1610612744
+		@endcode
+	*/
+	proto native external EntityFlags ClearFlags(EntityFlags flags, bool recursively);
+
+
+	/**
+	\brief Returns current event mask
+		\return \p int current event mask
+		@code
+			Man player = g_Game.GetPlayer();
+			Print( player.GetEventMask() );
+	
+			>> 0
+		@endcode
+	*/
+	proto native external EntityEvent GetEventMask();
+
+	/**
+	\brief Sets event mask
+		\param e combined mask of one or more members of EntityEvent enum
+		@code
+			Man player = g_Game.GetPlayer();
+			Print( player.GetEventMask() );
+			player.SetEventMask( EntityEvent.VISIBLE );
+			Print( player.GetEventMask() );
+	
+			>> 0
+			>> 128
+		@endcode
+	*/
+	proto native external EntityEvent SetEventMask(EntityEvent e );
+
+	/**
+	\brief Clears event mask
+		\param e \p int event mask
+		\return \p int event mask
+		@code
+			Man player = g_Game.GetPlayer();
+			player.SetEventMask(EntityEvent.VISIBLE );
+			Print( player.GetEventMask() );
+			player.ClearEventMask(EntityEvent.ALL );
+			Print( player.GetEventMask() );
+	
+			>> 128
+			>> 0
+		@endcode
+	*/
+	proto native external EntityEvent ClearEventMask(EntityEvent e);
+	
+	//!Dynamic event invokation. Parameters are the same as in IEntity::EOnXXXX() methods
+	proto external volatile void SendEvent(notnull IEntity actor, EntityEvent e, void extra);
+
+//@}
+
+/** \name Visual component methods
+ Manipulation with visual component - model, particle effect etc			
+*/
+//@{
+
+	/**
+	\brief Sets the visual object to this entity. Reference is added and released upon entity destruction
+	\param object handle to object got by GetObject()
+	\param options String, dependant on object type.
+	//Only supported one for XOB objects:
+	//$remap 'original material name' 'new material'; [$remap 'another original material name' 'anothernew material']
+	*/
+	proto native external void SetObject(vobject object, string options);
+	
+	/**
+	\brief Returns visual object set to this Entity. No reference is added
+	*/
+	proto native vobject GetVObject();
+
+	//!Updates animation (either xob, or particle, whatever)
+	proto native external int Animate(float speed, int loop);
+	//!Updates animation (either xob, or particle, whatever)
+	proto native external int AnimateEx(float speed, int loop, out vector lin, out vector ang);
+
+	//!Sets visibility mask for cameras, where Entity will be rendered
+	proto native external int SetCameraMask(int mask);	
+//@}
+
+	/**
+	\brief When called, the Entity is excluded from consequent TraceMove/TraceLine
+	*/
+	proto native external void FilterNextTrace();
+
+	/*!
+	Updates entity state/position. Should be called when you want to manually commit position changes etc
+	before trace methods etc. Entity is updated automatically at the end and the beginning of simulation step,
+	when it has EntityFlags.TFL_ACTIVE flag set.
+	\returns mask with flags
+	//	EntityFlags.UPDATE - hierarchy has been updated
+	//	EntityFlags.UPDATE_MDL - model hierarchy has been updated
+	*/
+	proto native external int Update();
+		
+#ifdef COMPONENT_SYSTEM		
+	//! Constructor
+	protected void IEntity(IEntitySource src, IEntity parent);	
+#endif		
+};
+
+#ifdef ENF_DONE
+// Set fixed LOD. -1 for non-fixed LOD
+proto native void SetFixedLOD(IEntity ent, int lod);
+//Sets the texture that can be referenced from material as $renderview
+//and connects it with camera cam_index. Size iz recommended size of
+//rendertarget (0 is default)
+proto native void SetRenderView(IEntity ent, int cam_index, int width, int height);
+proto void GetRenderView(IEntity ent, out int cam_index, out int width, out int height);
+#endif
+
+
+/**
+ * \defgroup EntityAttributes Entity editor attribute system
+ * @{
+ */
+
+class ParamEnum: Managed
+{
+	string m_Key;
+	string m_Value;
+	string m_Desc;
+	
+	void ParamEnum(string key, string value, string desc = "")
+	{
+		m_Key = key;
+		m_Value = value;
+		m_Desc = desc;
+	}
+}
+
+class ParamEnumArray: array<ref ParamEnum>
+{
+	static ParamEnumArray FromEnum(typename e)
+	{
+		ParamEnumArray params = new ParamEnumArray();	
+		int cnt = e.GetVariableCount();
+		int val;
+
+		for (int i = 0; i < cnt; i++)
+		{
+			if (e.GetVariableType(i) == int && e.GetVariableValue(NULL, i, val))
+			{
+				params.Insert(new ParamEnum(e.GetVariableName(i), val.ToString()));
+			}
+		}
+				
+		return params;
+	}	
+}
+
+// -------------------------------------------------------------------------
+class Attribute
+{
+	string m_DefValue;
+	string m_UiWidget; ///< can be "editbox", "combobox", "spinbox", "slider", "font", "fileeditbox", "colorPicker", "flags", "resourceNamePicker"
+	string m_RangeScale; ///< defined as "MIN_VALUE MAX_VALUE STEP" eg. "1 100 0.5"
+	string m_Desc;
+	ref ParamEnumArray m_Enums; ///< Only ints and floats are currently supported. Array can be defined this way: { ParamEnum("Choice 1", "1"), ParamEnum("Choicen 2", "2") }
+	
+	void Attribute(string defvalue, string uiwidget, string desc = "", string rangescale = "", ParamEnumArray enums = NULL)
+	{
+		m_DefValue = defvalue;
+		m_UiWidget = uiwidget;
+		m_RangeScale = rangescale;
+		m_Desc = desc;
+		m_Enums = enums;
+	}
+}
+
+class EditorAttribute
+{
+	string m_Style; ///< can be "box", "sphere", "cylinder", "pyramid", "diamond" or custom style name
+	string m_Category; ///< folder structure eg. StaticEntities/Walls
+	string m_Description; ///< class purpose description
+	vector m_SizeMin; ///< min vector of a bounding box
+	vector m_SizeMax; ///< max vector of a bounding box
+	string m_Color;
+	string m_Color2;
+	bool m_Visible;
+	bool m_Insertable;
+	bool m_DynamicBox;
+	
+	void EditorAttribute(string style, string category, string description, vector sizeMin, vector sizeMax, string color, string color2 = "0 0 0 0", bool visible = true, bool insertable = true, bool dynamicBox = false)
+	{
+		m_Style = style;
+		m_Category = category;
+		m_Description = description;
+		m_SizeMin = sizeMin;
+		m_SizeMax = sizeMax;
+		m_Color = color;
+		m_Color2 = color2;
+		m_Visible = visible;
+		m_Insertable = insertable;
+		m_DynamicBox = dynamicBox;
+	}
+}
+//@}
+
+//@}

+ 739 - 0
Scripts/1_core/proto/enmath.c

@@ -0,0 +1,739 @@
+/**
+ * \defgroup Math Math library
+ * @{
+ */
+
+class Math
+{
+	private void Math() {}
+	private void ~Math() {}
+	
+	static const float EULER = 2.7182818284590452353;
+	static const float PI = 3.14159265358979;
+	static const float PI2 = 6.28318530717958;
+	static const float PI_HALF = 1.570796326794;
+
+	static const float RAD2DEG = 57.2957795130823208768;
+	static const float DEG2RAD = 0.01745329251994329577;
+
+	//! returns the number of bits set in a bitmask i
+	proto static int GetNumberOfSetBits(int i);
+	
+	//! returns the the index of n-th bit set in a bit mask counting from the right, for instance, in a mask ..0110 1000 , the 0th set bit(right-most bit set to 1) is at 3th position(starting at 0), 1st bit is at 5th position, 2nd bit is at 6th position etc..
+	proto static int GetNthBitSet(int value, int n);
+	
+	/**
+	\brief Returns a random \p int number between and min [inclusive] and max [exclusive].
+		\param min \p int Range starts [inclusive]
+		\param max \p int Range ends [exclusive]
+		\return \p int - Random number in range
+		@code
+			Print( Math.RandomInt(0, 1) );	// only 0
+			Print( Math.RandomInt(0, 2) );	// 0 or 1
+
+			>> 0
+			>> 1
+		@endcode
+	*/
+	proto static int RandomInt(int min, int max);
+	
+	/**
+	\brief Returns a random \p int number between and min [inclusive] and max [inclusive].
+		\param min \p int Range starts [inclusive]
+		\param max \p int Range ends [inclusive]
+		\return \p int - Random number in range
+		@code
+			Print( Math.RandomIntInclusive(0, 1) );	// 0 or 1
+			Print( Math.RandomIntInclusive(0, 2) );	// 0, 1, 2
+
+			>> 1
+			>> 2
+		@endcode
+	*/
+	
+	static int RandomIntInclusive(int min, int max)
+	{
+		return Math.RandomInt(min, max+1);
+	}
+	
+	/**
+	\brief Returns a random \p bool .
+		\return \p bool - Random bool either 0 or 1
+		@code
+			Print( Math.RandomBool() );
+			Print( Math.RandomBool() );
+			Print( Math.RandomBool() );
+	
+			>> true
+			>> true
+			>> false
+		@endcode
+	*/
+	
+	static bool RandomBool()
+	{
+		return RandomIntInclusive(0,1);
+	}
+	
+	/**
+	\brief Returns a random \p float number between and min[inclusive] and max[exclusive].
+		\param min \p float Range starts [inclusive]
+		\param max \p float Range ends [exclusive]
+		\return \p float - Random number in range
+		@code
+			Print( Math.RandomFloat(0,1) );
+			Print( Math.RandomFloat(0,2) );
+
+			>> 0.597561
+			>> 1.936456
+		@endcode
+	*/
+	proto static float RandomFloat(float min, float max);
+
+	/**
+	\brief Returns a random \p float number between and min [inclusive] and max [inclusive].
+		\param min \p float Range starts [inclusive]
+		\param max \p float Range ends [inclusive]
+		\return \p float - Random number in range
+		@code
+			Print( Math.RandomFloatInclusive(0, 1) );	// 0.0 .. 1.0
+			Print( Math.RandomFloatInclusive(1, 2) );	// 1.0 .. 2.0
+
+			>> 0.3
+			>> 2.0
+		@endcode
+	*/
+	static float RandomFloatInclusive(float min, float max)
+	{
+		int max_range = Math.Pow(2, 30); //max range
+		int random_int = Math.RandomInt(0, max_range);
+		float rand_float = (float)random_int / (float)max_range;
+		float range = max - min;
+
+		return min + (rand_float * range); //rand float
+	}
+
+	/**
+	\brief Returns a random \p float number between and min [inclusive] and max [inclusive].
+		\return \p float - Random number in range 0.0 .. 1.0
+		@code
+			Print( Math.RandomFloat01() );	// 0.0 .. 1.0
+
+			>> 0.3
+			>> 1.0
+		@endcode
+	*/
+	static float RandomFloat01()
+	{
+		return RandomFloatInclusive(0, 1);
+	}
+	
+	/**
+	\brief Sets the seed for the random number generator.
+		\param seed \p int New seed for the random number generator, -1 will use time
+		\return \p int - Returns new seed
+		@code
+			Print( Math.Randomize(5) );
+
+			>> 5
+		@endcode
+	*/
+	proto static int Randomize(int seed);
+	
+	/**
+	\brief Normalizes the angle (0...360)
+		\param ang \p float Angle for normalizing
+		\return \p float - Normalized angle
+		@code
+			Print( Math.NormalizeAngle(390) );
+			Print( Math.NormalizeAngle(-90) );
+
+			>> 30
+			>> 270
+		@endcode
+	*/
+	proto static float NormalizeAngle(float ang);
+
+	/**
+	\brief Return relative difference between angles
+		\param angle1 \p float 
+		\param angle2 \p float
+		\return \p float Difference between angles (angle1 - angle2)
+		@code
+			Print( Math.DiffAngle(-45, 45) );
+			Print( Math.DiffAngle(90, 80) );
+
+			>> -90
+			>> 10
+		@endcode
+	*/
+	proto static float DiffAngle(float angle1, float angle2);
+	
+	/**
+	\brief Return power of v ^ power
+		\param v \p float Value
+		\param power \p float Power
+		\return \p float - The result of raising v to the given power
+		@code
+			Print( Math.Pow(2, 4) ); // (2*2*2*2)=16
+
+			>> 16
+		@endcode
+	*/
+	proto static float Pow(float v, float power);
+
+	/**
+	\brief Returns the floating-point remainder of x/y rounded towards zero
+		\param x \p float Value of the quotient numerator
+		\param y \p float Value of the quotient denominator
+		\return \p float - The remainder of dividing the arguments
+		@code
+			Print( Math.ModFloat(5.3, 2) );
+			Print( Math.ModFloat(18.5, 4.2) );
+
+			>> 1.3
+			>> 1.7
+		@endcode
+	*/
+	proto static float ModFloat(float x, float y);
+
+	/**
+	\brief Returns the floating-point remainder of x/y rounded to nearest
+		\param x \p float Value of the quotient numerator
+		\param y \p float Value of the quotient denominator
+		\return \p float - The remainder of dividing the arguments
+		@code
+			Print( Math.RemainderFloat(5.3, 2) );
+			Print( Math.RemainderFloat(18.5, 4.2) );
+
+			>> -0.7
+			>> 1.7
+		@endcode
+	*/
+	proto static float RemainderFloat(float x, float y);
+	
+	/**
+	\brief Returns absolute value
+		\param f \p float Value
+		\return \p float - Absolute value
+		@code
+			Print( Math.AbsFloat(-12.5) );
+
+			>> 12.5
+		@endcode
+	*/
+	proto static float AbsFloat(float f);
+
+	/**
+	\brief Returns absolute value
+		\param i \p int Value
+		\return \p int - Absolute value
+		@code
+			Print( Math.AbsInt(-12) );
+
+			>> 12
+		@endcode
+	*/
+	proto static int AbsInt(int i);
+
+	/**
+	\brief Returns sign of given value
+		\param f \p float Value
+		\return \p float - Sign of given value
+		@code
+			Print( Math.SignFloat(-12.0) );
+			Print( Math.SignFloat(0.0) );
+			Print( Math.SignFloat(12.0) );
+
+			>> -1.0
+			>> 0
+			>> 1.0
+		@endcode
+	*/
+	proto static float SignFloat(float f);
+
+	/**
+	\brief Returns sign of given value
+		\param i \p int Value
+		\return \p int - Sign of given value
+		@code
+			Print( Math.SignFloat(-12) );
+			Print( Math.SignFloat(0) );
+			Print( Math.SignFloat(12) );
+
+			>> -1
+			>> 0
+			>> 1
+		@endcode
+	*/
+	proto static int SignInt(int i);
+	
+	/**
+	\brief Returns squared value
+		\param f \p float Value
+		\return \p float - Squared value
+		@code
+			Print( Math.SqrFloat(12.5) );
+
+			>> 156.25
+		@endcode
+	*/
+	proto static float SqrFloat(float f);
+
+	/**
+	\brief Returns squared value
+		\param i \p int Value
+		\return \p int - Squared value
+		@code
+			Print( Math.SqrInt(12) );
+
+			>> 144
+		@endcode
+	*/
+	proto static int SqrInt(int i);
+	
+	/**
+	\brief Returns square root
+		\param val \p float Value
+		\return \p float - Square of value
+		@code
+			Print( Math.Sqrt(25));
+
+			>> 5
+		@endcode
+	*/
+	proto static float Sqrt(float val);
+	
+	/**
+	\brief Returns the binary (base-2) logarithm of x.
+		\param x \p float Value whose logarithm is calculated.
+		\return \p float The binary logarithm of x: log2x.
+				\n If x is negative, it causes a domain error:
+				\n If x is zero, it may cause a pole error (depending on the library implementation).
+		@code
+			Print( Math.Log2(1.0) ); 
+	
+			>> 0.0
+		@endcode
+	*/
+	proto static float Log2(float x);
+
+	/**
+	\brief Returns sinus of angle in radians
+		\param angle \p float Angle in radians
+		\return \p float - Sinus of angle
+		@code
+			Print( Math.Sin(0.785398) ); // (45)
+
+			>> 0.707107
+		@endcode
+	*/
+	proto static float Sin(float angle);
+
+	/**
+	\brief Returns cosinus of angle in radians
+		\param angle \p float Angle in radians
+		\return \p float - Cosinus of angle
+		@code
+			Print( Math.Cos(0.785398) ); // (45)
+
+			>> 0.707107
+		@endcode
+	*/
+	proto static float Cos(float angle);
+
+	/**
+	\brief Returns tangent of angle in radians
+		\param angle \p float Angle in radians
+		\return \p float - Tangens of angle
+		@code
+			Print( Math.Tan(0.785398) ); // (45)
+
+			>> 1
+		@endcode
+	*/
+	proto static float Tan(float angle);
+
+	/**
+	\brief Returns angle in radians from sinus
+		\param s \p float Sinus
+		\return \p float - Angle in radians
+		@code
+			Print( Math.Asin(0.707107) ); // (sinus 45)
+
+			>> 0.785398
+		@endcode
+	*/
+	proto static float Asin(float s);
+
+	/**
+	\brief Returns angle in radians from cosinus
+		\param c \p float Cosinus
+		\return \p float - Angle in radians
+		@code
+			Print( Math.Acos(0.707107) ); // (cosinus 45)
+
+			>> 0.785398
+		@endcode
+	*/
+	proto static float Acos(float c);
+	
+	/**
+	\brief Returns angle in radians from tangent
+		\param x \p float Tangent
+		\return \p float - Angle in radians
+	*/
+	proto static float Atan(float x);
+
+	/**
+	\brief Returns angle in radians from tangent
+		\param y \p float Tangent
+		\param x \p float Tangent
+		\return \p float - Angle in radians
+		@code
+			Print ( Math.Atan2(1, 1) );
+
+			>> 0.785398
+		@endcode
+	*/
+	proto static float Atan2(float y, float x);
+
+	/**
+	\brief Returns mathematical round of value
+		\param f \p float Value
+		\return \p float - closest whole number to 'f'
+		@code
+			Print( Math.Round(5.3) );
+			Print( Math.Round(5.8) );
+
+			>> 5
+			>> 6
+		@endcode
+	*/
+	proto static float Round(float f);
+		
+	/**
+	\brief Returns floor of value
+		\param f \p float Value
+		\return \p float - Floor of value
+		@code
+			Print( Math.Floor(5.3) );
+			Print( Math.Floor(5.8) );
+
+			>> 5
+			>> 5
+		@endcode
+	*/
+	proto static float Floor(float f);
+
+	/**
+	\brief Returns ceil of value
+		\param f \p float Value
+		\return \p float - Ceil of value
+		@code
+			Print( Math.Ceil(5.3) );
+			Print( Math.Ceil(5.8) );
+
+			>> 6
+			>> 6
+		@endcode
+	*/
+	proto static float Ceil(float f);
+	
+	/**
+	\brief Returns wrap number to specified interval [min, max[
+		\param f \p float Value
+		\param min \p float Minimum
+		\param max \p float Maximum
+		\return \p float - number in specified interval [min, max[
+		@code
+			Print( Math.WrapFloat(9.0, 1.0, 9.0) );
+
+			>> 1.0
+		@endcode
+	*/
+	proto static float WrapFloat(float f, float min, float max);
+	
+	/**
+	\brief Returns wrap number to specified interval, inclusive [min, max]
+		\param f \p float Value
+		\param min \p float Minimum
+		\param max \p float Maximum
+		\return \p float - number in specified interval [min, max]
+		@code
+			Print( Math.WrapFloatInclusive(9.0, 1.0, 9.0) );
+
+			>> 9.0
+		@endcode
+	*/
+	proto static float WrapFloatInclusive(float f, float min, float max);
+	
+	/**
+	\brief Returns wrap number to specified interval [0, max[
+		\param f \p float Value
+		\param max \p float Maximum
+		\return \p float - number in specified interval [0, max[
+		@code
+			Print( Math.WrapFloat0X(9.0, 9.0) );
+
+			>> 0.0
+		@endcode
+	*/
+	proto static float WrapFloat0X(float f, float max);
+	
+	/**
+	\brief Returns wrap number to specified interval, inclusive [0, max]
+		\param f \p float Value
+		\param max \p float Maximum
+		\return \p float - number in specified interval [0, max]
+		@code
+			Print( Math.WrapFloat0XInclusive(9.0, 9.0) );
+
+			>> 9.0
+		@endcode
+	*/
+	proto static float WrapFloat0XInclusive(float f, float max);
+	
+	/**
+	\brief Returns wrap number to specified interval [min, max[
+		\param i \p int Value
+		\param min \p float Minimum
+		\param max \p int Maximum
+		\return \p int - number in specified interval [min, max[
+		@code
+			Print( Math.WrapInt(9, 1, 9) );
+
+			>> 1
+		@endcode
+	*/
+	proto static int WrapInt(int i, int min, int max);
+	
+	/**
+	\brief Returns wrap number to specified interval [0, max[
+		\param i \p int Value
+		\param max \p int Maximum
+		\return \p int - number in specified interval [0, max[
+		@code
+			Print( Math.WrapInt0X(9, 9) );
+
+			>> 0
+		@endcode
+	*/
+	proto static int WrapInt0X(int i, int max);
+
+	/**
+	\brief Clamps 'value' to 'min' if it is lower than 'min', or to 'max' if it is higher than 'max'
+		\param value \p float Value
+		\param min \p float Minimum value
+		\param max \p float Maximum value
+		\return \p float - Clamped value
+		@code
+			Print( Math.Clamp(-0.1, 0, 1) );
+			Print( Math.Clamp(2, 0, 1) );
+			Print( Math.Clamp(0.5, 0, 1) );
+	
+			>> 0
+			>> 1
+			>> 0.5
+		@endcode
+	*/
+	proto static float Clamp(float value, float min, float max);
+		
+	/**
+	\brief Returns smaller of two given values
+		\param x \p float Value
+		\param y \p float Value
+		\return \p float  - min value
+		@code
+			Print( Math.Min(5.3, 2.8) );
+
+			>> 2.8
+		@endcode
+	*/
+	proto static float Min(float x, float y);
+	
+	/**
+	\brief Returns bigger of two given values
+		\param x \p float Value
+		\param y \p float Value
+		\return \p float  - max value
+		@code
+			Print( Math.Max(5.3, 2.8) );
+
+			>> 5.3
+		@endcode
+	*/
+	proto static float Max(float x, float y);	
+	
+	/**
+	\brief Returns if value is between min and max (inclusive)
+		\param v \p float Value
+		\param min \p float Minimum value
+		\param max \p float Maximum value
+		\return \p bool  - if value is within range [min,max]
+		@code
+			Print( Math.IsInRange(6.9, 3.6, 9.3) );
+
+			>> true
+		@endcode
+	*/
+	proto static bool IsInRange(float v, float min, float max);
+	
+	/**
+	\brief Returns if value is between min and max (inclusive)
+		\param v \p int Value
+		\param min \p int Minimum value
+		\param max \p int Maximum value
+		\return \p bool  - if value is within range [min,max]
+		@code
+			Print( Math.IsInRangeInt(6, 3, 9) );
+
+			>> true
+		@endcode
+	*/
+	proto static bool IsInRangeInt(int v, int min, int max);
+	
+	/**
+	\brief Linearly interpolates between 'a' and 'b' given 'time'.
+		\param a \p float Start
+		\param b \p float End
+		\param time \p float Time [value needs to be between 0..1 for correct results, no auto clamp applied]
+		\return \p float - The interpolated result between the two float values. 
+		@code
+			Print( Math.Lerp(3, 7, 0.5) );
+	
+			>> 5
+		@endcode
+	*/ 
+	proto static float Lerp(float a, float b, float time);
+
+	/**
+	\brief Calculates the linear value that produces the interpolant value within the range [a, b], it's an inverse of Lerp.
+		\param a \p float Start
+		\param b \p float End
+		\param value \p float value
+		\return \p float - the time given the position between 'a' and 'b' given 'value', there is no clamp on 'value', to stay between [0..1] use 'value' between 'a' and 'b'
+		@code
+			Print( Math.InverseLerp(3, 7, 5) );
+	
+			>> 0.5
+		@endcode
+	*/
+	proto static float InverseLerp(float a, float b, float value);
+	
+	/**
+	\brief Returns area of a right triangle
+		\param s \p float Length of adjacent leg
+		\param a \p float Angle of corner bordering adjacent which is not the right corner (in radians)
+		\return \p float - Area
+	*/
+	proto static float AreaOfRightTriangle(float s, float a);
+	
+	/**
+	\brief Returns hypotenus of a right triangle
+		\param s \p float Length of adjacent leg
+		\param a \p float Angle of corner bordering adjacent which is not the right corner (in radians)
+		\return \p float - hypotenus
+	*/
+	proto static float HypotenuseOfRightTriangle(float s, float a);
+	
+	/**
+	\brief Returns if point is inside circle
+		\param c \p vector Center of circle ([0] and [2] will be used, as a circle is 2D)
+		\param r \p float Radius of circle
+		\param p \p vector Point ([0] and [2] will be used, as a circle is 2D)
+		\return \p bool - True when point is in circle
+	*/
+	proto static bool IsPointInCircle(vector c, float r, vector p);
+	
+	/**
+	\brief Returns if point is inside rectangle
+		\param mi \p vector Minimums of rectangle ([0] and [2] will be used, as a rectangle is 2D)
+		\param ma \p vector Maximums of rectangle ([0] and [2] will be used, as a rectangle is 2D)
+		\param p \p vector Point ([0] and [2] will be used, as a rectangle is 2D)
+		\return \p bool - True when point is in rectangle
+	*/
+	proto static bool IsPointInRectangle(vector mi, vector ma, vector p);
+	
+	//--------------------------------------------------------------------------
+	//-------------------------------- filters ---------------------------------
+	//--------------------------------------------------------------------------
+
+	/**
+	\brief Does the CD smoothing function - easy in | easy out / S shaped smoothing 
+		\param val \p actual value 
+		\param target \p value we are reaching for -> Target
+		\param velocity \p float[1] - array of ONE member - some kind of memory and actual accel/decel rate, need to be zeroed when filter is about to be reset
+		\param smoothTime \p smoothing parameter, 0.1 .. 0.4 are resonable values, 0.1 is sharp, 0.4 is very smooth
+		\param maxVelocity \p maximal value change when multiplied by dt
+		\param dt \p delta time 
+
+		\return \p float smoothed/filtered value 
+
+		@code
+			val = EnfMath.SmoothCD(val, varTarget, valVelocity, 0.3, 1000, dt);
+		@endcode
+	*/
+
+	proto static float SmoothCD(float val, float target, inout float velocity[], float smoothTime, float maxVelocity, float dt);
+	
+	static float SmoothCDPI2PI(float val, float target, inout float velocity[], float smoothTime, float maxVelocity, float dt)
+	{
+		float diff = target - val;
+		if (diff < -Math.PI)
+		{
+			target += Math.PI2;
+		}
+		else if (diff > Math.PI)
+		{
+			target -= Math.PI2;
+		}
+		
+		float retVal = SmoothCD(val, target, velocity, smoothTime, maxVelocity, dt);
+		
+		while (retVal > Math.PI)
+		{
+			retVal -= Math.PI2;
+		}
+		
+		while (retVal < -Math.PI)
+		{
+			retVal += Math.PI2;
+		}
+		
+		return retVal;
+	}
+	
+	//! occurences values above '12' will cause Factorial to overflow int.
+	static float Poisson(float mean, int occurences)
+	{
+		return Pow(mean, occurences) * Pow(EULER,-mean) / Factorial(occurences);
+	}
+	
+	//! values above '12' will cause int overflow
+	static int Factorial(int val)
+	{
+		if (val > 12)
+		{
+			ErrorEx("Values above '12' cause int overflow! Returning '1'",ErrorExSeverity.INFO);
+			return 1;
+		}
+		
+		int res = 1;
+		while (val > 1)
+		{
+			res *= val--;
+		}
+		return res;
+	}
+	
+	static vector CenterOfRectangle(vector min, vector max)
+	{
+		float x = (min[0] + max[0]) * 0.5;
+		float z = (min[2] + max[2]) * 0.5;
+		
+		return Vector(x, 0.0, z);
+	}
+}
+
+//@}

+ 43 - 0
Scripts/1_core/proto/enmath2d.c

@@ -0,0 +1,43 @@
+/**
+ * \defgroup Math2D Math2D library
+ * @{
+ */
+
+//-----------------------------------------------------------------------------
+
+//! exposed from C++ (do not change)
+enum WindingOrder
+{
+	CounterClockwise,	// 0
+	Clockwise,			// 1
+	Invalid				// 2
+}
+
+
+class Math2D
+{
+	private void Math2D();
+	private void ~Math2D();
+
+	/*!
+	Check if a `point` is inside `polygon`.
+	Takes polygon and point only in the XZ plane.
+	*/
+	static proto bool IsPointInPolygonXZ(notnull array<vector> polygon, vector point);
+	//! Check if `point` is inside triangle specified by points `p1`, `p2` and `p3`.
+	static proto bool IsPointInTriangleXZ(vector p1, vector p2, vector p3, vector point);
+	/*!
+	Check if a point is inside `polygon`.
+	\param polygon Must be an array of Vector2, every two consecutive floats represent one point in polygon.
+	\param x X coordinate of point to test
+	\param y Y coordinate of point to test
+	*/
+	static proto bool IsPointInPolygon(notnull array<float> polygon, float x, float y);
+	/*!
+	Determines winding order of triangle given by points `a`, `b`, `c`. If the triangles
+	form a line, WindingOrder.Invalid is returned.
+	*/
+	static proto WindingOrder TriangleWindingXZ(vector a, vector b, vector c);
+}
+
+//@}

+ 497 - 0
Scripts/1_core/proto/enmath3d.c

@@ -0,0 +1,497 @@
+/**
+ * \defgroup Math3DAPI Math3D library
+ * @{
+ */
+
+/**
+\brief Vector constructor from components
+    \param x \p float x component
+	\param y \p float y component
+	\param z \p float z component
+	\return \p vector resulting vector
+	@code
+		Print( Vector(1, 2, 3) );
+
+		>> <1,2,3>
+	@endcode
+*/
+proto native vector Vector(float x, float y, float z);
+
+enum ECurveType
+{
+	CatmullRom,
+	NaturalCubic,
+	UniformCubic
+};
+
+class Math3D
+{
+	private void Math3D() {}
+	private void ~Math3D() {}
+	
+	//-----------------------------------------------------------------
+	proto static vector ClipLine(vector start, vector end, vector norm, float d);
+
+	/**
+	\brief Tests whether ray is intersecting sphere.
+		\param raybase \p vector Start of ray
+		\param raycos \p vector End of ray
+		\param center \p vector Center of sphere
+		\param radius \p float Radius of sphere
+		\return \p float -1 when not intersecting, else the fraction of ray
+	*/
+	proto static float IntersectRaySphere(vector raybase, vector raycos, vector center, float radius);
+	
+	/**
+	\brief Tests whether ray is intersecting axis aligned box.
+		\param start \p vector Start of ray
+		\param end \p vector End of ray
+		\param mins \p vector Minimums of bound box
+		\param maxs \p vector Maximums of bound box
+		\return \p float -1 when not intersecting, else the fraction of ray
+	*/
+	proto static float IntersectRayBox(vector start, vector end, vector mins, vector maxs);
+	
+	/**
+	\brief Tests whether sphere is intersecting axis aligned box.
+		\param origin \p vector Origin of sphere
+		\param radius \p float Radius of sphere
+		\param mins \p vector Minimums of bound box
+		\param maxs \p vector Maximums of bound box
+		\return \p bool True when intersects
+	*/
+	proto static bool IntersectSphereBox(vector origin, float radius, vector mins, vector maxs);
+	
+	/**
+	\brief Tests whether sphere is intersecting cone.
+		\param origin \p vector Origin of sphere
+		\param radius \p float Radius of sphere
+		\param conepos \p vector Position of top of cone
+		\param axis \p vector Orientation of cone in direction from top to bottom
+		\param angle \p float Angle of cone in radians
+		\return \p bool True when sphere is intersecting cone
+	*/
+	proto static bool IntersectSphereCone(vector origin, float radius, vector conepos, vector axis, float angle);
+	
+	/**
+	\brief Tests whether sphere is fully inside cone.
+		\param origin \p vector Origin of sphere
+		\param radius \p float Radius of sphere
+		\param conepos \p vector Position of top of cone
+		\param axis \p vector Orientation of cone in direction from top to bottom
+		\param angle \p float Angle of cone in radians
+		\return \p bool True when sphere is fully inside cone
+	*/
+	proto static bool IntersectWholeSphereCone(vector origin, float radius, vector conepos, vector axis, float angle);
+	
+	/**
+	\brief Tests whether cylinder is intersecting oriented box.
+		\param mins \p vector Minimums of bound box
+		\param maxs \p vector Maximums of bound box
+		\param obbMat \p vector Transform of box
+		\param cylMat \p vector Transform of cylinder
+		\param cylinderRadius \p float Radius of cylinder
+		\param cylinderHeight \p float Height of cylinder
+		\return \p bool True when cylinder is intersecting oriented box
+	*/
+	proto static bool IntersectCylinderOBB(vector mins, vector maxs, vector obbMat[4], vector cylMat[4], float cylinderRadius, float cylinderHeight);
+	
+	/**
+	\brief Tests whether ray is intersecting cylinder.
+		\param rayStart \p vector Start of ray
+		\param rayEnd \p vector End of ray
+		\param center \p vector Center of cylinder
+		\param radius \p float Radius of cylinder
+		\param height \p float Height of cylinder
+		\return \p bool True when ray is intersecting cylinder
+	*/
+	proto static bool IntersectRayCylinder(vector rayStart, vector rayEnd, vector center, float radius, float height);
+	
+	/**
+	\brief Tests whether ray is intersecting plane.
+		\param rayStart \p vector Start of ray
+		\param rayEnd \p vector End of ray
+		\param planeNormal \p vector Normal of the plane
+		\param planeDist \p float Length of the plane
+		\param intersection \p vector Intersection point of the plane, only valid when return is 3
+		\return \p int 1 when behind, 2 when in front and 3 when intersecting the plane
+	*/
+	proto static int IntersectRayPlane(vector rayStart, vector rayEnd, vector planeNormal, float planeDist, out vector intersection);
+	
+	/**
+	\brief Creates rotation matrix from angles
+		\param ang \p vector which contains angles
+		\param[out] mat \p vector created rotation matrix
+		@code
+			vector mat[3];
+			YawPitchRollMatrix( "70 15 45", mat );
+			Print( mat );
+
+			>> <0.330366,0.0885213,-0.939693>,<0.458809,0.854988,0.241845>,<0.824835,-0.511037,0.241845>
+		@endcode
+	*/
+	proto static void YawPitchRollMatrix(vector ang, out vector mat[3]);
+
+	/**
+	\brief Creates rotation matrix from direction and up vector
+		\param dir \p vector direction vector
+		\param up \p vector up vector
+		\param[out] mat \p vector[4] created rotation matrix
+		@code
+			vector mat[4];
+			vector dir = "1 0 1";
+			vector up = "0 1 0";
+			DirectionAndUpMatrix( dir, up, mat );
+			Print( mat );
+
+			>> <0.707107,0,-0.707107>,<0,1,0>,<0.707107,0,0.707107>,<0,0,0>
+		@endcode
+	*/
+	proto static void DirectionAndUpMatrix(vector dir, vector up, out vector mat[4]);
+
+	/**
+	\brief Transforms matrix
+		\param mat0 \p vector[4] first matrix
+		\param mat1 \p vector[4] second matrix
+		\param[out] res \p vector[4] result of first and second matrix multiplication
+		@code
+			vector mat0[4] = { "2 0 0 0", "0 3 0 0", "0 1 0 0", "0 0 0 1" }; // scale matrix
+			vector mat1[4] = { "1 0 0 0", "0 1 0 0", "0 1 0 0", "2 4 1 3" }; // translation matrix
+			vector res[4];
+			Math3D.MatrixMultiply4(mat0, mat1, res)
+			Print( res );
+
+			>> <2,0,0>,<0,3,0>,<0,3,0>,<4,13,0>
+		@endcode
+	*/
+	proto static void MatrixMultiply4(vector mat0[4], vector mat1[4], out vector res[4]);
+
+	/**
+	\brief Transforms rotation matrix
+		\param mat0 \p vector[3] first matrix
+		\param mat1 \p vector[3] second matrix
+		\param[out] res \p vector[3] result of first and second matrix multiplication
+		@code
+			vector mat0[3] = { "1.5 2.5 0", "0.1 1.3 0", "0 0 1" }; // rotation matrix
+			vector mat1[3] = { "1 0.4 0", "0 1 0", "0 1.3 2.7" }; // rotation matrix
+			vector res[3];
+			Math3D.MatrixMultiply3(mat0, mat1, res)
+			Print( res );
+
+			>> <1.54,3.02,0>,<0.1,1.3,0>,<0.13,1.69,2.7>
+		@endcode
+	*/
+	proto static void MatrixMultiply3(vector mat0[3], vector mat1[3], out vector res[3]);
+
+	/**
+	\brief Invert-transforms matrix
+		\param mat0 \p vector[4] first matrix
+		\param mat1 \p vector[4] second matrix
+		\param[out] res \p vector[4] inverse result of first and second matrix multiplication
+		@code
+			vector mat0[4] = { "2 0 0", "0 3 0", "0 0 1", "0 0 0" }; // scale matrix
+			vector mat1[4] = { "1 0 0", "0 1 0", "0 0 1", "2 4 1" }; // translation matrix
+			vector res[4];
+			Math3D.MatrixInvMultiply4(mat0, mat1, res)
+			Print( res );
+
+			>> <2,0,0>,<0,3,1>,<0,3,1>,<4,12,4>
+		@endcode
+	*/
+	proto static void MatrixInvMultiply4(vector mat0[4], vector mat1[4], out vector res[4]);
+
+	/**
+	\brief Invert-transforms rotation matrix
+		\param mat0 \p vector[3] first matrix
+		\param mat1 \p vector[3] second matrix
+		\param[out] res \p vector[3] result of first and second matrix multiplication
+		@code
+			vector mat0[3] = { "1.5 2.5 0", "0.1 1.3 0", "0 0 1" }; // rotation matrix
+			vector mat1[3] = { "1 0.4 0", "0 1 0", "0 1.3 2.7" }; // rotation matrix
+			vector res[3];
+			Math3D.MatrixInvMultiply3(mat0, mat1, res)
+			Print( res );
+
+			>> <2.5,0.62,0>,<2.5,1.3,0>,<3.25,1.69,2.7>
+		@endcode
+	*/
+	proto static void MatrixInvMultiply3(vector mat0[3], vector mat1[3], out vector res[3]);
+
+	/**
+	\brief Inverses a matrix
+	    \param[it] mat \p matrix which should be inversed
+	*/
+	proto static void MatrixInverse4(vector mat[4]);
+	
+	/**
+	\brief Inverses a matrix
+	    \param[it] mat \p matrix which should be inversed
+	*/
+	proto static void MatrixInverse3(vector mat[3]);
+
+	/**
+	\brief Orthogonalizes matrix
+	    \param[it] mat \p matrix which should be orthogonalized
+	*/
+	proto static void MatrixOrthogonalize4(vector mat[4]);
+	
+	/**
+	\brief Orthogonalizes matrix
+	    \param[it] mat \p matrix which should be orthogonalized
+	*/
+	proto static void MatrixOrthogonalize3(vector mat[3]);
+	
+	/**
+	\brief Creates identity matrix
+	    \param[out] mat \p created identity matrix
+		@code
+	        vector mat[4];
+	    	Math3D.MatrixIdentity4( mat );
+	    	Print( mat );
+
+			>> <1,0,0>,<0,1,0>,<0,0,1>,<0,0,0>
+		@endcode
+	*/
+	
+	static void MatrixIdentity4(out vector mat[4])
+	{
+		mat[0] = "1 0 0";
+		mat[1] = "0 1 0";
+		mat[2] = "0 0 1";
+		mat[3] = vector.Zero;
+	}
+	
+	/**
+	\brief Creates identity matrix
+	    \param[out] mat \p created identity matrix
+		@code
+	        vector mat[3];
+	    	Math3D.MatrixIdentity3( mat );
+	    	Print( mat );
+
+			>> <1,0,0>,<0,1,0>,<0,0,1>
+		@endcode
+	*/
+	static void MatrixIdentity3(out vector mat[3])
+	{
+		mat[0] = "1 0 0";
+		mat[1] = "0 1 0";
+		mat[2] = "0 0 1";
+	}
+
+	/**
+	\brief Creates scale matrix
+	    \param scale \p scale coeficient
+	    \param[out] mat \p created scale matrix
+		@code
+	        vector mat[3];
+	    	Math3D.ScaleMatrix( 2.5, mat );
+	    	Print( mat );
+
+			>> <2.5,0,0>,<0,2.5,0>,<0,0,2.5>
+		@endcode
+	*/
+	static void ScaleMatrix(float scale, out vector mat[3])
+	{
+		vector v0, v1, v2;
+		v0[0] = scale;
+		v1[1] = scale;
+		v2[2] = scale;
+		mat[0] = v0;
+		mat[1] = v1;
+		mat[2] = v2;
+	}
+
+	/**
+	\brief Creates identity quaternion
+		\param[out] q \p float[4] created identity quaternion
+		@code
+			float q[4];
+			Math3D.QuatIdentity( q );
+			Print( q );
+
+			>> {0,0,0,1}
+		@endcode
+	*/
+	static void QuatIdentity(out float q[4])
+	{
+		q[0] = 0;
+		q[1] = 0;
+		q[2] = 0;
+		q[3] = 1;
+	}
+
+	/**
+	\brief Copies quaternion
+	    \param s \p float[4] quaternion to copy
+		\param[out] d \p float[4] created quaternion copy
+		@code
+			float s[4] = { 2, 3, 4, 1 };
+			float d[4];
+			Math3D.QuatCopy( s, d );
+			Print( d );
+
+			>> {2,3,4,1}
+		@endcode
+	*/
+	static void QuatCopy(float s[4], out float d[4])
+	{
+		d[0] = s[0];
+		d[1] = s[1];
+		d[2] = s[2];
+		d[3] = s[3];
+	}
+
+	/**
+	\brief Converts rotation matrix to quaternion
+	    \param mat \p vector[3] rotation matrix
+		\param[out] d \p float[4] created quaternion copy
+		@code
+			vector mat[3];
+			vector rot = "70 15 45";
+			rot.RotationMatrixFromAngles( mat );
+			float d[4];
+			Math3D.MatrixToQuat( mat, d );
+			Print( d );
+
+			>> {0.241626,0.566299,-0.118838,0.778973}
+		@endcode
+	*/
+	proto static void MatrixToQuat(vector mat[3], out float d[4]);
+
+	
+	//! Converts quaternion to rotation matrix
+	proto static void QuatToMatrix(float q[4], out vector mat[3]);
+
+	/**
+	\brief Returns angles of rotation matrix
+		\param mat \p vector[3] rotation matrix
+		\return \p vector roll, pitch, yaw angles
+		@code
+			vector mat[3];
+			Math3D.RollPitchYawMatrix( "70 15 45", mat );
+			vector ang = Math3D.MatrixToAngles( mat );
+			Print( ang );
+
+			>> <70,15,-45>
+		@endcode
+	*/
+	proto static vector MatrixToAngles(vector mat[3]);
+	
+	/**
+	\brief Linear interpolation between q1 and q2 with weight 'frac' (0...1)
+	    \param[out] qout \p float[4] result quaternion
+		\param q1 \p float[4] first quaternion
+		\param q2 \p float[4] second quaternion
+		\param frac \p float interpolation weight
+		@code
+			float q1[4] = { 1, 1, 1, 1 };
+			float q2[4] = { 2, 2, 2, 1 };
+			float qout[4];
+			Math3D.QuatLerp( qout, q1, q2, 0.5 );
+			Print( qout );
+
+			>> {1.5,1.5,1.5,1}
+		@endcode
+	*/
+	proto static void QuatLerp(out float qout[4], float q1[4], float q2[4], float frac);
+
+	/**
+	\brief Multiplies quaternions
+	    \param[out] qout \p float[4] result quaternion
+		\param q1 \p float[4] first quaternion
+		\param q2 \p float[4] second quaternion
+		@code
+			float q1[4] = { 1, 2, 3, 1 };
+			float q2[4] = { 2, 2, 2, 1 };
+			float qout[4];
+			Math3D.QuatMultiply( qout, q1, q2 );
+			Print( qout );
+
+			>> {2,4,6,1}
+		@endcode
+	*/
+	proto static void QuatMultiply(out float qout[4], float q1[4], float q2[4]);
+
+	//! Returns Angles vector from quaternion
+	proto static vector QuatToAngles(float q[4]);
+	
+	/**
+	\brief Returns 1, when bounding boxes intersects
+	    \param mins1 \p vector minimum point of first bounding box
+		\param maxs1 \p vector maximum point of first bounding box
+		\param mins2 \p vector minimum point of second bounding box
+		\param maxs2 \p vector maximum point of second bounding box
+		\return \p int 1 if boundig boxes intersects, otherwise 0
+		@code
+			vector mins1 = "1 1 1";
+			vector maxs1 = "3 3 3";
+			vector mins2 = "2 2 2";
+			vector maxs2 = "4 4 4";
+			Print( Math3D.CheckBoundBox(mins1, maxs1, mins2, maxs2) );
+
+			>> 1
+		@endcode
+	*/
+	proto static int CheckBoundBox(vector mins1, vector maxs1, vector mins2, vector maxs2);
+	
+	/**
+	\brief Returns randon normalized direction
+	    \return \p vector 
+		@code
+			Print( Math3D.GetRandomDir() );
+
+			>>vector ret =  0x0000000007c1a1c0 {<0.422565,0,-0.906333>}
+		@endcode
+	*/
+	static vector GetRandomDir()
+	{
+		float x = Math.RandomFloatInclusive(-1, 1);
+		float y = Math.RandomFloatInclusive(-1, 1);
+		float z = Math.RandomFloatInclusive(-1, 1);
+			
+		return Vector(x, y, z).Normalized();
+	}
+	
+	
+	/**
+	\brief Computes curve
+		\return \p vector 
+		@code
+			auto points = new array<vector>();
+			points.Insert( Vector( 0, 0, 0) );
+	    	points.Insert( Vector( 5, 0, 0) );
+	    	points.Insert( Vector( 8, 3, 0) );
+	    	points.Insert( Vector( 6, 1, 0) );
+		
+			float t = 0.5;
+			vector result = Math3D.Curve(ECurveType.CatmullRom, t, points);
+		@endcode
+	*/
+	proto static native vector Curve(ECurveType type, float param, notnull array<vector> points);
+	
+	
+	/**
+	\brief Point on line beg .. end nearest to pos
+		\return \p vector
+	*/
+	proto static vector NearestPoint(vector beg, vector end, vector pos);
+	
+	/**
+	\brief Angle that a target is from the direction of an origin
+		\return \p float Angle in radians
+	*/
+	proto static float AngleFromPosition(vector origin, vector originDir, vector target);
+	
+	/**
+	\brief Calculates the points of a right 2D cone in 3D space
+		\param origin \p vector Origin of cone
+		\param length \p float Length of the cone
+		\param halfAngle \p float Half of the angle of the cone in radians
+		\param angleOffset \p float Angle offset of the cone in radians (handy for rotating it along with something in the world)
+		\param[out] leftPoint \p vector Left point of the cone
+		\param[out] rightPoint \p vector Right point of the cone
+	*/
+	proto static void ConePoints(vector origin, float length, float halfAngle, float angleOffset, out vector leftPoint, out vector rightPoint);
+};
+//@}

+ 331 - 0
Scripts/1_core/proto/enphysics.c

@@ -0,0 +1,331 @@
+/**
+ * \defgroup Physics Physics system
+ * @{
+ */
+
+typedef int[] dGeom;
+typedef int[] dJoint;
+typedef int[] dBlock;
+
+proto native int dGetNumDynamicBodies(notnull IEntity worldEnt);
+proto native IEntity dGetDynamicBody(notnull IEntity worldEnt, int index);
+proto native void dSetInteractionLayer(notnull IEntity worldEntity, int mask1, int mask2, bool enable);
+proto native bool dGetInteractionLayer(notnull IEntity worldEntity, int mask1, int mask2);
+
+//!Gets global gravity
+proto native vector dGetGravity(notnull IEntity worldEntity);
+//!Changes global gravity
+proto native void dSetGravity(notnull IEntity worldEntity, vector g);
+//!Changes fixed time-slice. Default is 1/40, thus simulation runs on 40fps. With smaller values, there is more precise simulation
+proto native void dSetTimeSlice(notnull IEntity worldEntity, float timeSlice);
+
+/**
+ * \defgroup RigidBody RigidBody API
+ * @{
+ */
+
+//proto native int dMaterialClone(string target, string source, int material_index)
+//proto native int dMaterialGetType(string source)
+//proto native int dMaterialSetType(string source, int material_index)
+
+class PhysicsGeomDef: Managed
+{
+	string	Name;
+	dGeom		Geometry;
+	vector	Frame[4] = {Vector(1, 0, 0), Vector(0, 1, 0), Vector(0, 0, 1), Vector(0, 0, 0)};
+	int			ParentNode = -1;
+	string	MaterialName;
+	int			LayerMask; //<Bit mask of layers we are in
+
+	
+	void PhysicsGeomDef(string name, dGeom geom, string materialName, int layerMask)
+	{
+		Name = name;
+		Geometry = geom;
+		MaterialName = materialName;
+		LayerMask = layerMask;	
+	}	
+};
+
+/*!
+Creates RigidBody from custom made geometries. The geometries are deleted when rigid body is destroyed
+\param geoms array of custom made geometries
+@code
+	autoptr PhysicsGeomDef geoms[] = {PhysicsGeomDef("", dGeomCreateBox(size), "material/default", 0xffffffff)};
+	dBodyCreateStaticEx(this, geoms);
+@endcode
+*/
+proto bool dBodyCreateStaticEx(notnull IEntity ent, PhysicsGeomDef geoms[]);
+proto bool dBodyCreateGhostEx(notnull IEntity ent, PhysicsGeomDef geoms[]);
+
+/*!
+Creates RigidBody from custom made geometries. The geometries are deleted when rigid body is destroyed
+\param centerOfMass Offset from object-pivot to center of mass
+\param mass Body mass
+\param geoms array of custom made geometries
+@code
+	autoptr PhysicsGeomDef geoms[] = {PhysicsGeomDef("", dGeomCreateBox(size), "material/default", 0xffffffff)};
+	dBodyCreateDynamicEx(this, center, 1.0, geoms);
+@endcode
+*/
+proto bool dBodyCreateDynamicEx(notnull IEntity ent, vector centerOfMass, float mass, PhysicsGeomDef geoms[]);
+
+//!Destroys attached physics body
+proto native void dBodyDestroy(notnull IEntity ent);
+
+//!Has the entity attached physics body?
+proto native bool dBodyIsSet(notnull IEntity ent);
+
+proto native void dBodySetInteractionLayer(notnull IEntity ent, int mask);
+proto native int dBodyGetInteractionLayer(notnull IEntity ent);
+proto native void dBodySetGeomInteractionLayer(notnull IEntity ent, int index, int mask);
+proto native int dBodyGetGeomInteractionLayer(notnull IEntity ent, int index);
+
+//! state of a rigidbody
+enum ActiveState
+{
+	ACTIVE,
+	INACTIVE,
+	ALWAYS_ACTIVE
+};
+	
+proto native void dBodyActive(notnull IEntity ent, ActiveState activeState);
+proto native void dBodyDynamic(notnull IEntity ent, bool dynamic);
+proto native bool dBodyIsDynamic(notnull IEntity ent);
+
+proto native bool dBodyIsActive(notnull IEntity ent);
+proto native bool dBodyEnableGravity(notnull IEntity ent, bool enable);
+proto native void dBodySetDamping(notnull IEntity ent, float linearDamping, float angularDamping);
+proto native void dBodySetSleepingTreshold(notnull IEntity body, float linearTreshold, float angularTreshold);
+
+proto native bool dBodyIsSolid(notnull IEntity ent);
+proto native void dBodySetSolid(notnull IEntity ent, bool solid);
+
+/*!
+If both maxMotion and shapeCastRadius is >=0 then the continuous collision detection is enabled.
+If you want to disable it, use -1
+\param maxMotion max motion threshold when sphere-cast is performed, to find time of impact. It should be
+little bit less than size of the geometry to catch the situation when tunelling can happen
+\param sphereCastRadius The radius of the largest possible sphere, that is completelly inside the body geometry.
+*/
+proto native void dBodyEnableCCD(notnull IEntity body, float maxMotion, float sphereCastRadius);
+/*!
+Sets scale factor for all impulses/velocities/forces. Default is <1,1,1>. Zero any axis if you want to do 2D physics
+*/
+proto native void dBodySetLinearFactor(notnull IEntity body, vector linearFactor);
+
+//!returns center of mass offset
+proto native vector dBodyGetCenterOfMass(notnull IEntity body);
+
+/**
+\brief Returns linear velocity
+	\param ent \p IEntity entity which origin will be set
+	\param mat \p vector[4] matrix to be set
+	\return \p vector linear velocity
+	@code
+		Man player = g_Game.GetPlayer();
+		Print( GetVelocity(player) );
+
+		>> <0,0,0>
+	@endcode
+*/
+proto native vector GetVelocity(notnull IEntity ent);
+
+/**
+\brief Sets linear velocity (for Rigid bodies)
+	\param ent \p entity which velocity will be set
+	\param vel \p velocity vector to be set
+*/
+proto native void SetVelocity(notnull IEntity ent, vector vel);
+
+/**
+\brief Disables collisions between two entities
+*/
+proto native dBlock dBodyCollisionBlock(notnull IEntity ent1, notnull IEntity ent2);
+proto native void dBodyRemoveBlock(notnull IEntity worldEntity, dBlock block);
+
+proto native void dBodySetInertiaTensorV(notnull IEntity body, vector v);
+proto native void dBodySetInertiaTensorM(notnull IEntity body, vector m[3]);
+
+proto native float dBodyGetMass(notnull IEntity ent);
+proto native void dBodySetMass(notnull IEntity body, float mass);
+
+proto native void dBodyApplyTorqueImpulse(notnull IEntity ent, vector torqueImpulse);
+proto native vector dBodyGetInvInertiaDiagLocal(notnull IEntity ent);
+proto native float dBodyComputeImpulseDenominator(notnull IEntity ent, vector position, vector normal);
+proto native float dBodyComputeAngularImpulseDenominator(notnull IEntity ent, vector axis);
+proto native vector dBodyGetLocalInertia(notnull IEntity ent);
+
+proto void dBodyGetInvInertiaTensorWorld(notnull IEntity body, out vector inertiaTensorWS[3]);
+
+/**
+\brief Applies impuls on a pos position in world coordinates
+*/
+proto void dBodyApplyImpulseAt(notnull IEntity body, vector impulse, vector pos);
+
+/**
+\brief Applies impuls on a rigidbody (origin)
+*/
+proto void dBodyApplyImpulse(notnull IEntity body, vector impulse);
+
+/**
+\brief Applies constant force on a rigidbody (origin)
+*/
+proto void dBodyApplyForce(notnull IEntity body, vector force);
+
+/**
+\brief Applies constant force on a position
+*/
+proto void dBodyApplyForceAt(notnull IEntity body, vector pos, vector force);
+
+proto native void dBodyApplyTorque(notnull IEntity body, vector torque);
+
+/**
+\brief Gets angular velocity for a rigidbody
+*/
+proto vector dBodyGetAngularVelocity(notnull IEntity body);
+
+/**
+\brief Changed an angular velocity
+	\param body \p Rigid body
+	\param angvel \p Angular velocity, rotation around x, y and z axis (not yaw/pitch/roll)
+*/
+proto void dBodySetAngularVelocity(notnull IEntity body, vector angvel);
+
+/**
+\brief Sets target transformation. If timeslice == dt (simulation step delta time), it will happen in next step, otherwise in time = timeslice
+*/
+proto native void dBodySetTargetMatrix(notnull IEntity body, vector matrix[4], float timeslice);
+
+proto native void dBodyGetWorldTransform(notnull IEntity body, out vector matrix[4]);
+proto native void dBodyGetDirectWorldTransform(notnull IEntity body, out vector matrix[4]);
+
+proto native float dBodyGetKineticEnergy(notnull IEntity body);
+
+proto native vector dBodyGetVelocityAt(notnull IEntity body, vector globalpos);
+//@}
+
+/**
+ * \defgroup Geometry Geometry API definition
+ * @{
+ */
+
+//! Creates box geometry
+proto native dGeom dGeomCreateBox(vector size);
+
+//! Creates sphere geometry
+proto native dGeom dGeomCreateSphere(float radius);
+
+//! Creates capsule geometry
+proto native dGeom dGeomCreateCapsule(float radius, vector extent);
+
+//! Creates cylinder geometry
+proto native dGeom dGeomCreateCylinder(float radius, vector extent);
+
+//! Destroys geometry
+proto native void dGeomDestroy(dGeom geom);
+
+//proto native int dBodyAddGeom(notnull IEntity body, dGeom geom, vector frame[4], string material, int interactionLayer);
+// find a geometry by its name and returns its index or -1 if the geometry wasn't found
+proto native int dBodyGetGeom(notnull IEntity ent, string name);
+// returns number of geometries of the entity
+proto native int dBodyGetNumGeoms(notnull IEntity ent);
+//@}
+
+/**
+ * \defgroup Constraints Constraints API definition
+ * @{
+ */
+
+proto native dJoint dJointCreateHinge(notnull IEntity ent1, notnull IEntity ent2, vector point1, vector axis1, vector point2, vector axis2, bool block, float breakThreshold);
+proto native dJoint dJointCreateHinge2(notnull IEntity ent1, notnull IEntity ent2, vector matrix1[4], vector matrix2[4], bool block, float breakThreshold);
+proto native dJoint dJointCreateSlider(notnull IEntity ent1, notnull IEntity ent2, vector matrix1[4], vector matrix2[4], bool block, float breakThreshold);
+proto native dJoint dJointCreateBallSocket(notnull IEntity ent1, notnull IEntity ent2, vector point1, vector point2, bool block, float breakThreshold);
+proto native dJoint dJointCreateFixed(notnull IEntity ent1, notnull IEntity ent2, vector point1, vector point2, bool block, float breakThreshold);
+proto native dJoint dJointCreateConeTwist(notnull IEntity ent1, notnull IEntity ent2, vector matrix1[4], vector matrix2[4], bool block, float breakThreshold);
+proto native dJoint dJointCreate6DOF(notnull IEntity ent1, notnull IEntity ent2, vector matrix1[4], vector matrix2[4], bool block, float breakThreshold);
+proto native dJoint dJointCreate6DOFSpring(notnull IEntity ent1, notnull IEntity ent2, vector matrix1[4], vector matrix2[4], bool block, float breakThreshold);
+proto native void dJointDestroy(dJoint joint);
+
+//only hinge joint
+proto native void dJointHingeSetLimits(dJoint joint, float low, float high, float softness, float biasFactor, float relaxationFactor);
+proto native void dJointHingeSetAxis(dJoint joint, vector axis);
+proto native void dJointHingeSetMotorTargetAngle(dJoint joint, float angle, float dt, float maxImpulse);
+
+//only cone-twist joint
+proto native void dJointConeTwistSetAngularOnly(dJoint joint, bool angularOnly);
+// setLimit(), a few notes:
+// _softness:
+//		0->1, recommend ~0.8->1.
+//		describes % of limits where movement is free.
+//		beyond this softness %, the limit is gradually enforced until the "hard" (1.0) limit is reached.
+// _biasFactor:
+//		0->1?, recommend 0.3 +/-0.3 or so.
+//		strength with which constraint resists zeroth order (angular, not angular velocity) limit violation.
+// __relaxationFactor:
+//		0->1, recommend to stay near 1.
+//		the lower the value, the less the constraint will fight velocities which violate the angular limits.
+proto native void dJointConeTwistSetLimit(dJoint joint, int limitIndex, float limitValue);
+proto native void dJointConeTwistSetLimits(dJoint joint, float _swingSpan1, float _swingSpan2, float _twistSpan, float _softness, float _biasFactor, float _relaxationFactor);
+
+//only 6DOF & 6DOFSpring.
+/*!
+    - free means upper < lower,
+    - locked means upper == lower
+    - limited means upper > lower
+    - axis: first 3 are linear, next 3 are angular
+*/
+proto native void	dJoint6DOFSetLinearLimits(dJoint joint, vector linearLower, vector linearUpper);
+proto native void	dJoint6DOFSetAngularLimits(dJoint joint, vector angularLower, vector angularUpper);
+proto native void dJoint6DOFSetLimit(dJoint joint, int axis, float lo, float hi);
+
+//when stiffness == -1 && damping == -1, spring is disabled
+proto native void dJoint6DOFSpringSetSpring(dJoint joint, int axis, float stiffness, float damping);
+
+//only slider joint
+proto native void dJointSliderSetLinearLimits(dJoint joint, float lowerLimit, float upperLimit);
+proto native void dJointSliderSetAngularLimits(dJoint joint, float lowerLimit, float upperLimit);
+proto native void dJointSliderSetDirLinear(dJoint joint, float softness, float restitution, float damping);
+proto native void dJointSliderSetDirAngular(dJoint joint, float softness, float restitution, float damping);
+proto native void dJointSliderSetLimLinear(dJoint joint, float softness, float restitution, float damping);
+proto native void dJointSliderSetLimAngular(dJoint joint, float softness, float restitution, float damping);
+proto native void dJointSliderSetOrthoLinear(dJoint joint, float softness, float restitution, float damping);
+proto native void dJointSliderSetOrthoAngular(dJoint joint, float softness, float restitution, float damping);
+//if force == 0, motor is off
+proto native void dJointSliderSetLinearMotor(dJoint joint, float velocity, float force);
+proto native void dJointSliderSetAngularMotor(dJoint joint, float velocity, float force);
+proto native float dJointSliderGetLinearPos(dJoint joint);
+proto native float dJointSliderGetAngularPos(dJoint joint);
+//@}
+
+//-----------------------------------------------------------------
+typedef int[] dMaterial;
+
+class Contact
+{
+	private void Contact() {}
+	private void ~Contact() {}
+	
+	dMaterial	Material1;
+	dMaterial	Material2;
+	int			MaterialIndex1;
+	int			MaterialIndex2;
+	int			Index1;
+	int			Index2;
+
+	float		PenetrationDepth;
+
+	float		Impulse;
+	float		RelativeNormalVelocityBefore;
+	float		RelativeNormalVelocityAfter;
+
+	vector		Normal;
+	vector		Position;
+	vector		RelativeVelocityBefore;
+	vector		RelativeVelocityAfter;
+
+	proto native vector GetNormalImpulse();
+	proto native float GetRelativeVelocityBefore(vector vel);
+	proto native float GetRelativeVelocityAfter(vector vel);
+};
+//@}

+ 762 - 0
Scripts/1_core/proto/enprofiler.c

@@ -0,0 +1,762 @@
+/**
+ * \defgroup Profiler Enforce Script profiling API
+ *	\warning Only available on developer and diag builds
+ * @{
+ */
+
+//! Flags that influences the behaviour of the EnProfiler API, applied through ...Flags functions
+enum EnProfilerFlags
+{
+	//! No flags
+	NONE,
+	//! When present, will reset [PD] on sorting, otherwise will accumulate on top of it
+	RESET,
+	//! Whether to profile child modules
+	RECURSIVE,
+	//! All flags enabled
+	ALL
+};
+
+//! Current base scripted modules 
+enum EnProfilerModule
+{
+	//! 1_Core
+	CORE,
+	//! 2_GameLib
+	GAMELIB,
+	//! 3_Game
+	GAME,
+	//! 4_World
+	WORLD,
+	//! 5_Mission
+	MISSION,
+	//! init.c
+	MISSION_CUSTOM,
+	//! Can be returned from some methods
+	ERROR,
+};
+
+/**
+*\brief There are 3 states which can be toggled that governs whether script profiling is enabled or not
+*	\note The reason for this is because when it is enabled in debug menu, or through this API without 'immediate', it will only be enabled the next frame
+*/
+enum EnProfilerEnabledFlags
+{
+	//! No flags, has value 0, so will count as false in conditions
+	NONE,
+	//! Script profiling UI is enabled in WIN+ALT debug menu, when this is true, it will override SCRP
+	DIAG,
+	//! It has been set to being always enabled through EnProfiler (SCRipt Profiler)
+	SCRP,
+	//! Whether profiling is currently truly happening (SCRipt Context)
+	SCRC,
+};
+
+typedef Param2<float, typename> EnProfilerTimeClassPair;
+typedef Param2<int, typename> EnProfilerCountClassPair;
+
+typedef Param2<float, string> EnProfilerTimeFuncPair;
+typedef Param2<int, string> EnProfilerCountFuncPair;
+
+/**
+*\brief Set of methods for accessing script profiling data
+*	\note To enable profiling on game launch, use parameter "-profile"
+*	\note Any mention of "[DM]" in this context will mean the WIN+ALT debug menu
+*	\note Any mention of "[CI]" in this context will mean Class Instances count
+*	\note Any mention of "[SR]" in this context will mean a Session Reset (See ResetSession for more information)
+*	\note Any mention of "[SD]" in this context will mean a Sorted Data, which is the data which supplies Get...Per... functions (the ones that give an array)
+*	\note Any mention of "[PD]" in this context will mean a Profiling Data, which is the time, count and allocation information which is stored on the class/func itself
+*	\warning [PD] is only calculated AFTER a function call is finished, there is no continuous timer running
+*	\note 'proto' methods are not tracked, but will contribute to a script methods total time
+*/
+class EnProfiler
+{
+	/**
+	\brief Enable the gathering of script profiling data
+	\note DEFAULT: disabled (unless launched with "-profile", then it is default enabled)
+	\note This is separate from the one in [DM], so toggling it in [DM] will not affect this, and toggling it here will not affect [DM]
+	\note It will ignore the call if trying to set the current state, except when "immediate" is used
+		\param enable \p bool Whether to enable or disable, if it was previously not enabled, it will cause [SR]
+			\note Disabling does not cause [SR], so all data will stay intact
+		\param immediate \p bool When true will instantly start/stop profiling, otherwise it will apply it at the end of the frame (to have one stable point in time)
+			\warning Keep in mind that when using immediate, it will not be the data of the entire frame, which can skew data if not kept in mind		
+		\param sessionReset \p bool When set to false, no [SR] will trigger, regardless of situation
+	
+	@code
+		// Simple enable, will start profiling the next frame
+		// Will cause [SR] if !IsEnabledP() before this call
+		EnProfiler.Enable(true);
+
+		// Immediate enable, will start profiling immediately
+		// Will cause [SR] if !IsEnabledP() before this call
+		EnProfiler.Enable(true, true);
+
+		// Immediate disable, will stop profiling immediately
+		// Disabling will never cause [SR], preserving data
+		EnProfiler.Enable(false, true);
+
+		// Simple disable, will not profile the next frame (but still finish profiling the current one)
+		// Disabling will never cause [SR], preserving data
+		EnProfiler.Enable(false);
+	@endcode
+	*/
+	static proto void Enable(bool enable, bool immediate = false, bool sessionReset = true);
+	
+	/**
+	\brief Return if script profiling is enabled
+	\note Helper methods below
+		\return \p int Flags regarding the current state
+
+	@code
+		int isScriptProfilingEnabled = EnProfiler.IsEnabled();
+	@endcode
+	*/
+	static proto int IsEnabled();
+	
+	/**
+	\brief Return if script profiling is enabled through [DM]
+		\return \p bool Whether script profiling is enabled through [DM]
+	
+	@code
+		bool isScriptProfilingDiagEnabled = EnProfiler.IsEnabledD();
+	@endcode
+	*/
+	static bool IsEnabledD()
+	{
+		return (IsEnabled() & EnProfilerEnabledFlags.DIAG);
+	}
+	
+	/**
+	\brief Return if script profiling is enabled through EnProfiler
+	\note When using "-profile" launch parameter, it will enable it through EnProfiler, so this will return true
+		\return \p bool Whether script profiling is enabled through script profiler
+	
+	@code
+		bool isScriptProfilingToggleEnabled = EnProfiler.IsEnabledP();
+	@endcode
+	*/
+	static bool IsEnabledP()
+	{
+		return (IsEnabled() & EnProfilerEnabledFlags.SCRP);
+	}
+	
+	/**
+	\brief Return if script profiling is actually turned on inside of the script context
+	\note When using "-profile" launch parameter, it will enable it through EnProfiler, so this will return true
+		\return \p bool Whether script is being profiled as of this moment
+	
+	@code
+		bool isScriptProfilingEnabled = EnProfiler.IsEnabledC();
+	@endcode
+	*/
+	static bool IsEnabledC()
+	{
+		return (IsEnabled() & EnProfilerEnabledFlags.SCRC);
+	}
+	
+	/**
+	\brief The internal sorting that happens at the end of the frame (so it is NOT necessary to call this manually) to supply Get...Per... functions 
+	\note This will clear the previous [SD] and sort the [PD] currently available at this moment
+	\note Flags apply to this
+	\warning Keep in mind that EnProfilerFlags.RESET will clear all [PD] after this is called
+	
+	@code
+		// Sorting all the currently available [PD], populating [SD]
+		EnProfiler.SortData();
+
+		// If flag EnProfilerFlags.RESET is enabled, then this will return 0 now even if it has been called, as [PD] has been cleared
+		// This goes for any Get...Of... function (Except for [CI], the counter persists)
+		EnProfiler.GetTimeOfFunc("Sleep", EnProfilerTests, true);
+	@endcode
+	*/
+	static proto void SortData();
+	
+	/**
+	\brief Perform [SR], clearing SessionFrame, ProfiledSessionFrames, [SD] and [PD] (except for [CI])
+	\note Can also be triggered by a variety of other functions in this API
+	\note When triggered by the other functions, it will call with fullReset = false
+		\param fullReset \p bool Whether to clear [PD] of all modules, when false it will only clear the [PD] according to current settings
+	
+	@code
+		// Considering the settings: SetFlags(EnProfilerFlags.NONE) and SetModule(EnProfilerModule.GAME)
+		// The following call will only clear [PD] of 3_Game
+		EnProfiler.ResetSession();
+
+		// Considering the settings: SetFlags(EnProfilerFlags.RECURSIVE) and SetModule(EnProfilerModule.WORLD)
+		// The following call will clear [PD] of 3_Game, 4_World, 5_Mission and their children
+		EnProfiler.ResetSession();
+
+		// The following call resets [PD] across all modules
+		EnProfiler.ResetSession(true);
+	@endcode
+	*/
+	static proto void ResetSession(bool fullReset = false);
+	
+	
+	
+	/** \name EnProfilerFlags
+		Set of functions to configure the currently active EnProfilerFlags
+	*/
+	//@{
+	
+	/**
+	\brief Override the currently used set of EnProfilerFlags across the API
+	\note DEFAULT: EnProfilerFlags.ALL
+		\param flags \p int The combination of desired EnProfilerFlags to override the currently used set
+		\param sessionReset \p bool When set to false, no [SR] will trigger, regardless of situation
+		\return \p int The currently used set of EnProfilerFlags after the function call
+	
+	@code
+		// No RESET flag, [PD] will be accumulated across frames
+		// No RECURSIVE flag, only the curently profiled module will be sorted
+		EnProfiler.SetFlags(EnProfilerFlags.NONE);
+
+		// RESET flag, [PD] will be reset after sorting
+		// No RECURSIVE flag, only the curently profiled module will be sorted
+		EnProfiler.SetFlags(EnProfilerFlags.RESET);
+
+		// RESET flag, [PD] will be reset after sorting
+		// RECURSIVE flag, all modules will be sorted
+		EnProfiler.SetFlags(EnProfilerFlags.ALL);
+	@endcode
+	*/
+	static proto int SetFlags(int flags, bool sessionReset = true);
+	
+	/**
+	\brief Get the currently used flags across the API
+		\return \p int The currently used set of EnProfilerFlags
+	
+	@code
+		int flags = EnProfiler.GetFlags();
+
+		if (flags & EnProfilerFlags.RECURSIVE)
+		{
+			Print("Currently profiling all modules.");
+		}
+	@endcode
+	*/
+	static proto int GetFlags();
+	
+	/**
+	\brief Check if the flags are set
+	\note Is effectively the same as the code displayed in GetFlags example, but without the bitwise operation
+		\param flags \p int The combination of EnProfilerFlags to check if present
+		\return \p bool If the flags are set
+	
+	@code
+		if (EnProfiler.IsFlagsSet(EnProfilerFlags.ALL))
+		{
+			Print("Currently all flags are enabled.");
+		}
+
+		if (EnProfiler.IsFlagsSet(EnProfilerFlags.RECURSIVE))
+		{
+			Print("Currently profiling all modules.");
+		}
+	@endcode
+	*/
+	static proto bool IsFlagsSet(int flags);
+	
+	/**
+	\brief Add flags to the currently used set of EnProfilerFlags across the API
+	\note Simply a helper method to quickly add EnProfilerFlags
+		\param flags \p int The combination of desired EnProfilerFlags to be added to the currently used set
+		\param sessionReset \p bool When set to false, no [SR] will trigger, regardless of situation
+		\return \p int The currently used set of EnProfilerFlags after the function call
+	
+	@code
+		// In the case where the current set of EnProfilerFlags is EnProfilerFlags.RESET
+		EnProfiler.AddFlags(EnProfilerFlags.RECURSIVE);
+		// The resulting set of flags now will be EnProfilerFlags.RESET | EnProfilerFlags.RECURSIVE
+		// As the above is pretty much the same as the following
+		// EnProfiler.SetFlags(EnProfiler.GetFlags() | EnProfilerFlags.RECURSIVE);
+		// But a much cleaner and faster alternative (bitwise operations in script is ~10x slower than C++)
+	@endcode
+	*/
+	static proto int AddFlags(int flags, bool sessionReset = true);
+	
+	/**
+	\brief Remove flags from the currently used set of EnProfilerFlags across the API
+	\note Simply a helper method to quickly remove EnProfilerFlags
+		\param flags \p int The combination of desired EnProfilerFlags to be added to the currently used set
+		\param sessionReset \p bool When set to false, no [SR] will trigger, regardless of situation
+		\return \p int The currently used set of EnProfilerFlags after the function call
+	
+	@code
+		// In the case where the current set of EnProfilerFlags is EnProfilerFlags.RESET
+		EnProfiler.RemoveFlags(EnProfilerFlags.RESET);
+		// The resulting set of flags now will be EnProfilerFlags.NONE
+		// As the above is pretty much the same as the following
+		// EnProfiler.SetFlags(EnProfiler.GetFlags() & ~EnProfilerFlags.RECURSIVE);
+		// But a much cleaner and faster alternative (bitwise operations in script is ~10x slower than C++)
+	@endcode
+	*/
+	static proto int RemoveFlags(int flags, bool sessionReset = true);
+	
+	/**
+	\brief Remove all flags from the currently used set of EnProfilerFlags across the API
+	\note Simply a helper method to quickly remove all EnProfilerFlags
+		\param sessionReset \p bool When set to false, no [SR] will trigger, regardless of situation
+		\return \p int The currently used set of EnProfilerFlags after the function call
+	
+	@code
+		// In the case where the current set of EnProfilerFlags is EnProfilerFlags.RESET
+		EnProfiler.ClearFlags();
+		// The resulting set of flags now will be EnProfilerFlags.NONE
+		// As the above is pretty much the same as the following
+		// EnProfiler.SetFlags(EnProfilerFlags.NONE);
+		// But a much cleaner and implicit alternative
+	@endcode
+	*/
+	static proto int ClearFlags(bool sessionReset = true);
+	
+	//@}
+	
+	
+	
+	/** \name EnProfilerModule
+		Set of functions to configure the currently profiled EnProfilerModule
+	*/
+	//@{
+	
+	/**
+	\brief Set the module to be profiled
+	\note DEFAULT: EnProfilerModule.CORE
+	\note When session reset is enabled, it will only reset the module which it is currently being set to, previous module data will be untouched
+		\param module \p EnProfilerModule The module to profile
+		\param sessionReset \p bool When set to false, no [SR] will trigger, regardless of situation
+	
+	@code
+		EnProfiler.SetModule(EnProfilerModule.WORLD);
+	@endcode
+	*/
+	static proto void SetModule(EnProfilerModule module, bool sessionReset = true);
+	
+	/**
+	\brief Get the currently profiled module
+		\return \p EnProfilerModule The currently profiled module
+	
+	@code
+		EnProfilerModule module = EnProfiler.GetModule();
+	@endcode
+	*/
+	static proto EnProfilerModule GetModule();
+	
+	/**
+	\brief Helper to convert EnProfilerModule to string
+		\param module \p EnProfilerModule The module to get the name of
+		\return \p string The name of the module
+	
+	@code
+		string moduleName = EnProfiler.ModuleToName(EnProfilerModule.GAME);
+	@endcode
+	*/
+	static proto owned string ModuleToName(EnProfilerModule module);
+	
+	/**
+	\brief Convert string to EnProfilerModule
+		\param moduleName \p string The name of the module
+		\param module \p EnProfilerModule The enum value of the module or EnProfilerModule.ERROR if not found
+		\return \p bool Whether the module was found 
+	
+	@code
+		// Get the name of the module of the current class
+		string nameOfCurrentModule = Type().GetModule();
+		EnProfilerModule module;
+
+		// Convert it to the enum value
+		if (EnProfiler.NameToModule(nameOfCurrentModule, module))
+		{
+			EnProfiler.SetModule(module);
+		}
+		else
+		{
+			ErrorEx(string.Format("Could not find EnProfilerModule: %1", nameOfCurrentModule));
+		}
+	@endcode
+	*/
+	static proto bool NameToModule(string moduleName, out EnProfilerModule module);
+	
+	//@}
+	
+	
+	
+	/**
+	\brief Set the interval for the [SD] to update
+	\note DEFAULT: 0
+	\note [DM] has the following values: {0, 5, 10, 20, 30, 50, 60, 120, 144}; When an interval not part of this list is set, [DM] will be set to "CUSTOM_INTERVAL"
+	\note Does not affect the gathering of [PD], this will happen continuously as the profiling is enabled
+	\note This also delays the [SR] caused by EnProfilerFlags.RESET
+		\param interval \p int Amount of frames to wait before [SD] is updated
+		\param sessionReset \p bool When set to false, no [SR] will trigger, regardless of situation
+	
+	@code
+		// This will make it so that [SD] is updated every 60 frames
+		EnProfiler.SetInterval(60);
+	@endcode
+	*/
+	static proto void SetInterval(int interval, bool sessionReset = true);
+	
+	/**
+	\brief Get the currently set interval
+		\return \p int The currently set interval
+	
+	@code
+		int currentInterval = EnProfiler.GetInterval();
+	@endcode
+	*/
+	static proto int GetInterval();
+	
+	
+	
+	/**
+	\brief Set the resolution of the fetched Time data
+	\note DEFAULT: 100000
+	\note [DM] has the following values: {100000, 1000000, 1, 10, 100, 1000, 10000}; These are the only values available, otherwise it will round up to one in the list
+	\note Does not affect any data itself, only the fetching and displaying of it (therefore, no [SR] is ever triggered by this method)
+		\param resolution \p int The nth resolution of a second
+	
+	@code
+		// Have all time being reported in 1 second
+		EnProfiler.SetTimeResolution(1);
+
+		// Have all time being reported in 1000th of a second (ms)
+		EnProfiler.SetTimeResolution(1000);
+	@endcode
+	*/
+	static proto void SetTimeResolution(int resolution);
+	
+	/**
+	\brief Get the currently set time resolution
+		\return \p int The currently set resolution
+	
+	@code
+		int currentTimeResolution = EnProfiler.GetTimeResolution();
+	@endcode
+	*/
+	static proto int GetTimeResolution();
+	
+	
+	
+	/**
+	\brief Enable/disable returning calculated averages
+	\note DEFAULT: false
+	\note When EnProfilerFlags.RESET flag is not present, it will divide by the session frame
+	\note When an interval is set, it will divide by the interval
+	\note Does not affect any data itself, only the fetching and displaying of it (therefore, no [SR] is ever triggered by this method)
+	\note [CI] will never be an average, it will always be the current count of the instance (allocations will be the value of how many times an instance is created)
+		\param enable \p bool Whether to enable or disable
+	
+	@code
+		// For example, take the situation where we only reset every 60 frames
+		EnProfiler.AddFlags(EnProfilerFlags.RESET);
+		EnProfiler.SetInterval(60);
+		EnProfiler.EnableAverage(true);
+
+		// And a method is called once per frame, gathering the count of that function will be 1
+		// Or if a method is called twice per frame, gathering the count of that function will be 2
+		// Or if a method is 3 times every 3 frames, gathering the count of that function will be 1
+		// ...
+		// So you get the average amount of times the method is called per frame, out of the sample of 60 frames
+	@endcode
+	*/
+	static proto void EnableAverage(bool enable);
+	
+	/**
+	\brief Check if returning of average data is enabled
+		\return \p bool Whether returning of average data is enabled
+	
+	@code
+		bool isDataAverage = EnProfiler.IsAverage();
+	@endcode
+	*/
+	static proto bool IsAverage();
+	
+	
+	
+	/**
+	\brief Print out [SD] to script log
+	
+	@code
+		EnProfiler.Dump();
+	@endcode
+	*/
+	static proto void Dump();
+	
+	
+	
+	/** \name Frame data
+		Set of functions to obtain information about frame counts
+	*/
+	//@{
+	
+	/**
+	\brief Get the total amount of frames passed
+		\return \p int The total amount of frames passed
+	
+	@code
+		int gameFrame = EnProfiler.GetGameFrame();
+	@endcode
+	*/
+	static proto int GetGameFrame();
+	
+	/**
+	\brief Get the total amount of frames in this profiling session
+	\note This will only differ from GetProfiledSessionFrames when there is an Interval set
+		\return \p int The total amount of frames in this profiling session
+	
+	@code
+		int sessionFrame = EnProfiler.GetSessionFrame();
+	@endcode
+	*/
+	static proto int GetSessionFrame();
+	
+	/**
+	\brief Get the total amount of frames across all profiling session
+	\note This will only differ from GetProfiledFrames when there was an Interval set at some point
+		\return \p int The total amount of frames across all profiling session
+	
+	@code
+		int totalFrames = EnProfiler.GetTotalFrames();
+	@endcode
+	*/
+	static proto int GetTotalFrames();
+	
+	/**
+	\brief Get the total amount of frames profiled in this profiling session
+	\note This will only differ from GetSessionFrame when there is an Interval set
+		\return \p int The total amount of frames profiled in this profiling session
+	
+	@code
+		int profiledSessionFrames = EnProfiler.GetProfiledSessionFrames();
+	@endcode
+	*/
+	static proto int GetProfiledSessionFrames();
+	
+	/**
+	\brief Get the total amount of frames profiled across all profiling session
+	\note This will only differ from GetTotalFrames when there was an Interval set at some point
+		\return \p int The total amount of frames profiled across all profiling session
+	
+	@code
+		int totalProfiledFrames = EnProfiler.GetProfiledFrames();
+	@endcode
+	*/
+	static proto int GetProfiledFrames();
+	
+	//@}
+	
+
+	
+	/** \name Sorted data
+		Set of functions to obtain [SD]
+		\warning Data is appended to the array, it will not clear any previous data already existing in the array
+		\note Read SortData as well for more information regarding [SD]
+	*/
+	//@{
+	
+	/**
+	\brief Obtain [SD] for Time Per Class
+		\param outArr \p array<ref EnProfilerTimeClassPair> Array sorted by time consumed by a class
+		\param count \p int The maximum amount of entries wanted
+	
+	@code
+		// In this example the array will be filled with the 20 most time intensive classes
+		// If there are less than 20 classes which consumed time, it will output that number of classes instead
+		array<ref EnProfilerTimeClassPair> timePerClass = {};
+		EnProfiler.GetTimePerClass(timePerClass, 20);
+
+		// In this example the array will be filled with all classes sorted by time
+		array<ref EnProfilerTimeClassPair> timePerClass2 = {};
+		EnProfiler.GetTimePerClass(timePerClass2);
+	@endcode
+	*/
+	static proto void GetTimePerClass(notnull out array<ref EnProfilerTimeClassPair> outArr, int count = int.MAX);
+	
+	/**
+	\brief Obtain [SD] for Allocations Per Class
+		\param outArr \p array<ref EnProfilerCountClassPair> Array sorted by number of allocations of a class
+		\param count \p int The maximum amount of entries wanted
+	
+	@code
+		array<ref EnProfilerCountClassPair> allocPerClass = {};
+		EnProfiler.GetAllocationsPerClass(allocPerClass, 20);
+	@endcode
+	*/
+	static proto void GetAllocationsPerClass(notnull out array<ref EnProfilerCountClassPair> outArr, int count = int.MAX);
+	
+	/**
+	\brief Obtain [SD] for Instances Per Class
+		\param outArr \p array<ref EnProfilerCountClassPair> Array sorted by number of instances of a class
+		\param count \p int The maximum amount of entries wanted
+	
+	@code
+		array<ref EnProfilerCountClassPair> instancesPerClass = {};
+		EnProfiler.GetInstancesPerClass(instancesPerClass, 20);
+	@endcode
+	*/
+	static proto void GetInstancesPerClass(notnull out array<ref EnProfilerCountClassPair> outArr, int count = int.MAX);
+	
+	/**
+	\brief Obtain [SD] for Time Per Function
+		\param outArr \p array<ref EnProfilerTimeFuncPair> Array sorted by time consumed by a function
+		\param count \p int The maximum amount of entries wanted
+	
+	@code
+		array<ref EnProfilerTimeFuncPair> timePerFunc = {};
+		EnProfiler.GetTimePerFunc(timePerFunc, 20);
+	@endcode
+	*/
+	static proto void GetTimePerFunc(notnull out array<ref EnProfilerTimeFuncPair> outArr, int count = int.MAX);
+	
+	/**
+	\brief Obtain [SD] for Count Per Function
+		\param outArr \p array<ref EnProfilerCountFuncPair> Array sorted by amount of times a function was called
+		\param count \p int The maximum amount of entries wanted
+	
+	@code
+		array<ref EnProfilerCountFuncPair> countPerFunc = {};
+		EnProfiler.GetCountPerFunc(countPerFunc, 20);
+	@endcode
+	*/
+	static proto void GetCountPerFunc(notnull out array<ref EnProfilerCountFuncPair> outArr, int count = int.MAX);
+	
+	//@}
+	
+	
+	
+	/** \name Specific data
+		Set of functions to obtain specific data
+	*/
+	//@{
+	
+	/**
+	\brief Obtain [SD] or [PD] regarding the time a specific class consumed
+		\param clss \p typename Typename of desired class
+		\param immediate \p bool When true, it will pull from [SD], when false it will pull from [PD]
+		\return \p float Time consumed by the specified class
+	
+	@code
+		// Consider the class
+		EPTHelperClass clss = new EPTHelperClass();
+
+		// Some functions being called here...
+	
+		// Gathering of data can be done through
+		float timeOfClass = EnProfiler.GetTimeOfClass(clss.Type(), true);
+
+		// Or when you have no variable/reference
+		float timeOfClass2 = EnProfiler.GetTimeOfClass(StaticGetType(EPTHelperClass), true);
+	@endcode
+	*/
+	static proto float GetTimeOfClass(typename clss, bool immediate = false);
+	
+	/**
+	\brief Obtain [SD] or [PD] regarding the allocations of a specific class
+		\param clss \p typename Typename of desired class
+		\param immediate \p bool When true, it will pull from [SD], when false it will pull from [PD]
+		\return \p int Allocations of the specified class
+	
+	@code
+		int allocationsOfClass = EnProfiler.GetAllocationsOfClass(StaticGetType(EPTHelperClass), true);
+	@endcode
+	*/
+	static proto int GetAllocationsOfClass(typename clss, bool immediate = false);
+	
+	/**
+	\brief Obtain [SD] or [PD] regarding the [CI] of a specific class
+		\param clss \p typename Typename of desired class
+		\param immediate \p bool When true, it will pull from [SD], when false it will pull from [PD]
+		\return \p int [CI] of the specified class
+	
+	@code
+		int instancesOfClass = EnProfiler.GetInstancesOfClass(StaticGetType(EPTHelperClass), true);
+	@endcode
+	*/
+	static proto int GetInstancesOfClass(typename clss, bool immediate = false);
+	
+	/**
+	\brief Obtain [SD] or [PD] regarding the time consumed by a specific function
+		\param funct \p string Function name
+		\param clss \p typename Typename of class the function belongs to
+		\param immediate \p bool When true, it will pull from [SD], when false it will pull from [PD]
+		\return \p float Time consumed by the specified function or -1 when function was not found
+	
+	@code
+		float timeOfFunc = EnProfiler.GetTimeOfFunc("StringFormat", StaticGetType(EnProfilerTests), true);
+	@endcode
+	*/
+	static proto float GetTimeOfFunc(string funct, typename clss, bool immediate = false);
+	
+	/**
+	\brief Obtain [SD] or [PD] regarding the time consumed by a specific global function
+		\param funct \p string Function name
+		\param immediate \p bool When true, it will pull from [SD], when false it will pull from [PD]
+		\return \p float Time consumed by the specified function or -1 when function was not found
+	
+	@code
+		float timeOfFunc = EnProfiler.GetTimeOfFuncG("ErrorEx", true);
+	@endcode
+	*/
+	static proto float GetTimeOfFuncG(string funct, bool immediate, bool immediate = false);
+	
+	/**
+	\brief Obtain [SD] or [PD] regarding the amount of times a specific function was called
+		\param funct \p string Function name
+		\param clss \p typename Typename of class the function belongs to
+		\param immediate \p bool When true, it will pull from [SD], when false it will pull from [PD]
+		\return \p int Amount of calls to the specified function or -1 when function was not found
+	
+	@code
+		int callCountOfFunc = EnProfiler.GetCountOfFunc("StringFormat", StaticGetType(EnProfilerTests), true);
+	@endcode
+	*/
+	static proto int GetCountOfFunc(string funct, typename clss, bool immediate = false);
+	
+	/**
+	\brief Obtain [SD] or [PD] regarding the amount of times a specific function was called
+		\param funct \p string Function name
+		\param immediate \p bool When true, it will pull from [SD], when false it will pull from [PD]
+		\return \p int Amount of calls to the specified function or -1 when function was not found
+	
+	@code
+		int callCountOfFunc = EnProfiler.GetCountOfFuncG("ErrorEx", true);
+	@endcode
+	*/
+	static proto int GetCountOfFuncG(string funct, bool immediate = false);
+	
+	//@}
+	
+	
+	
+	/** \name Misc
+		Set of helper functions
+	*/
+	//@{
+	
+	/**
+	\brief Helper method to ascertain the profiler will record [PD] right after this call
+		\return \p bool Whether it was enabled before or not
+	
+	@code
+		bool wasEnabled = EnProfiler.RequestImmediateData();
+	@endcode
+	*/
+	static bool RequestImmediateData()
+	{
+		// I only care if it is actually profiling right now, so C
+		bool wasEnabled = IsEnabledC();
+		
+		if (!wasEnabled)
+		{
+			// I want the data, and I want it now, so immediate
+			Enable(true, true);
+		}
+		
+		return wasEnabled;
+	}
+	
+	//@}
+};
+
+ //@}

+ 1003 - 0
Scripts/1_core/proto/enscript.c

@@ -0,0 +1,1003 @@
+/**
+ * \defgroup Enforce Enforce script essentials
+ * \note \p float ftime; The deltaTime since last frame
+ * \note \p float FLT_MAX; The maximum value for float
+ * \note \p float FLT_MIN; The minimum value for float
+ * @{
+ */
+
+ //! Super root of all classes in Enforce script
+class Class
+{
+	/**
+	\brief Returns true when instance is of the type, or inherited one.
+	\param type Class type
+	\returns \p bool true when 'clType' is the same as 'type', or inherited one.
+	@code
+		if (inst && inst.IsInherited(Widget))
+		{
+			Print("inst is inherited from Widget class!");		
+		}
+	@endcode
+	*/
+	proto native external bool IsInherited(typename type);
+	
+	/**
+	\brief Returns name of class-type
+		\param inst Class
+		\returns \p string class-type
+		@code
+			Man player = g_Game.GetPlayer();
+			string className = player.ClassName();
+			Print(className);
+
+			>> className = 'Man'
+		@endcode
+	*/
+	proto native owned external string ClassName();
+	
+	string GetDebugName() { return ClassName(); }
+	
+	/**
+	\brief Returns typename of object's class
+		\returns \p typename class-type
+		@code
+			Man player = g_Game.GetPlayer();
+			typename type = player.Type();
+			Print(type.ToString());
+
+			>> 'Man'
+		@endcode
+	*/
+	proto native external typename Type();
+	
+	/**
+	\brief Returns typename of object's reference
+		\returns \p typename class-type
+		@code
+			EntityAI e;
+			Print(e.StaticType());
+
+			>> 'EntityAI'
+		@endcode
+	*/	
+	proto external static typename StaticType();
+	
+	/**
+	\brief Returns typename of class even without a variable or instance
+		\returns \p typename class-type
+		@code
+			typename eAITypename = StaticGetType(EntityAI);
+		@endcode
+	*/
+	static typename StaticGetType(typename t)
+	{
+		return t;
+	}
+	
+	proto external string ToString();
+	
+	/**
+	\brief Try to safely down-cast base class to child class.
+		\returns down-casted 'from' pointer when cast is successfull (classes are related), or null if casting is invalid
+		@code
+			// assume that Man inheites from Object
+			Object obj = g_Game.GetPlayer();
+			Man player = Man.Cast(obj);
+			
+			if (player)
+			{
+				// horay!
+			}
+		@endcode
+	*/		
+	proto static Class Cast(Class from);
+	
+	/**
+	\brief Try to safely down-cast base class to child class.
+		\returns \p bool true when 'from' is not null and cast successfull, false when casting is not valid or 'from' is null
+		@code
+			// assume that Man inheites from Object
+			Object obj = g_Game.GetPlayer();
+			Man player;
+			
+			if (Class.CastTo(player, obj))
+			{
+				// horay!
+			}
+		@endcode
+	*/	
+	proto static bool CastTo(out Class to, Class from);
+	
+	//! This function is for internal script usage
+	private proto static bool SafeCastType(Class type, out Class to, Class from);
+};
+
+ //! TODO doc
+class Managed
+{
+};
+
+//! TODO doc
+class NonSerialized
+{
+};
+
+//! script representation for C++ RTTI types
+typedef int[] TypeID;
+
+//! Module containing compiled scripts.
+class ScriptModule
+{
+	private void ~ScriptModule();
+
+	/*!dynamic call of function
+	when inst == NULL, it's global function call, otherwise it's method of class
+	returns true, when success
+	The call creates new thread, so it's legal to use sleep/wait
+  */
+	proto volatile int Call(Class inst, string function, void parm);
+
+	/*!dynamic call of function
+	when inst == NULL, it's global function call, otherwise it's method of class
+	returns true, when success
+	The call do not create new thread!!!!
+  */
+	proto volatile int CallFunction(Class inst, string function, out void returnVal, void parm);
+	proto volatile int CallFunctionParams(Class inst, string function, out void returnVal, Class parms);
+	proto native void Release();
+	
+	/**
+	\brief Do load script and create ScriptModule for it
+		\param parentModule Module
+		\param scriptFile Script path
+		\param listing ??
+		\returns \p ScriptModule Loaded scripted module
+		@code
+			???
+		@endcode
+	*/
+	static proto native ScriptModule LoadScript(ScriptModule parentModule, string scriptFile, bool listing);
+};
+
+//main script module (contains script.c and this file)
+//ScriptModule g_Script;
+
+class EnScript
+{
+	private void EnScript() {}
+	private void ~EnScript() {}
+	
+	/**
+	\brief Dynamic read of variable value by its name
+		\param inst When inst == NULL, it's for global variable, otherwise it's class member
+		\param index Is index when variable is array
+		\param[out] result Variable must be of the same type!
+		\returns \p int true when success
+		@code
+			float count = 0;
+
+			bool success = EnScript.GetClassVar(myClass, "m_Counter", 0, count);
+			Print(count);
+			Print(success);
+
+			>> count = 5
+			>> success = 1
+		@endcode
+	*/
+	static proto int GetClassVar(Class inst, string varname,int index, out void result);
+
+	/**
+	\brief Dynamic write to variable by its name
+		\param inst when inst == NULL, it's for global variable, otherwise it's class member
+		\param varname
+		\param index Is index when variable is array
+		\param input Input variable must be of the same type!
+		\returns \p int Returns true(1) when success
+		@code
+			Print(myClass.m_Counter);
+
+			>> m_Counter = 0
+
+			bool success = EnScript.SetClassVar(myClass, "m_Counter", 0, 5.0);
+
+			Print(myClass.m_Counter);
+			Print(success);
+
+			>> m_Counter = 5
+			>> success = 1
+		@endcode
+	*/
+	static proto int SetClassVar(Class inst, string varname, int index, void input);
+	
+	/**
+	\brief Sets variable value by value in string
+		\param[out] var
+		\param value
+		\returns int
+		@code
+			???
+		@endcode
+	*/
+	static proto int SetVar(out void var, string value);
+
+	/**
+	\brief Debug tool for watching certain variable. Invokes debugger whenever is variable used
+		\param var Certain variable for watching
+		\param flags = 1 means it will break even when not modified
+		\return \p void
+	*/
+	static proto void Watch(void var, int flags);
+};
+
+
+
+/**
+\brief Sorts static array of integers(ascendically) / floats(ascendically) / strings(alphabetically)
+	\param param_array \p array Array to sort
+	\param num \p int How many items will be sorted in array
+	\return \p void
+	@code
+		string	arrStr[3] = {"Dog", "Car", "Apple"};
+		Sort(arrStr, 2)
+		for ( int x = 0; x < 3; x++ )
+		{
+			Print( arrStr[x] );
+		}
+
+		>> 'Car'
+		>> 'Dog'
+		>> 'Apple'
+	@endcode
+*/
+proto void Sort(void param_array[], int num);
+proto void reversearray(void param_array);
+proto void copyarray(void destArray, void srcArray);
+
+/**
+\brief Parses one token from input string. Result is put into token string, and type of token is returned. Input string is left-truncated by the resulting token length.
+	\param[in,out] input \p string String for parse\ Output is without founded token
+	\param[out] token \p string Founded string token
+	\return \p int Type of token
+	\verbatim
+Token types:
+ 0 - error, no token
+ 1 - defined token (special characters etc. . / * )
+ 2 - quoted string. Quotes are removed -> TODO
+ 3 - alphabetic string
+ 4 - number
+ 5 - end of line -> TODO
+	\endverbatim
+	@code
+		string input = "Hello*World";
+		string token1;
+		string token2;
+
+		int result1 = ParseStringEx(input, token1);
+		int result2 = ParseStringEx(input, token2);
+
+		Print( String( "Token1 = '" + token1 + "' Type = " + result1.ToString() ) );
+		Print( String( "Token2 = '" + token2 + "' Type = " + result2.ToString() ) );
+		Print( input );
+
+		>> 'Toke1 = 'Hello' Type = 3'
+		>> 'Toke1 = '*' Type = 1'
+	@endcode
+*/
+proto int ParseStringEx(inout string input, string token);
+
+/**
+\brief Parses string into array of tokens returns number of tokens
+	\param input \p string String for parse
+	\param[out] tokens \p array[] Parsed string in array
+	\return \p int Number of tokens
+	@code
+		string token[2];
+		int result = ParseString("Hello World", token);
+
+		for( int i = 0; i < 2; i++ )
+		{
+			Print(token[i]);
+		}
+
+		>> 'Hello'
+		>> 'World'
+	@endcode
+*/
+proto int ParseString(string input, out string tokens[]);
+
+/**
+\brief Kills thread.
+	\param owner Can be NULL for global threads.
+	\param name Name of the first function on stack
+	\return \p int ???
+	@code
+		???
+	@endcode
+*/
+proto native int KillThread(Class owner, string name);
+
+/**
+Yiels execution to other threads and then it continues. Obsolete...
+*/
+proto volatile void Idle();
+
+/**
+\brief Debug function. Returns current function on stack of the thread
+	\param owner Can be NULL for global threads
+	\param name Name of the first function on stack
+	\param backtrace ???
+	\param linenumber ???
+	\return \p string ???
+	@code
+		???
+	@endcode
+*/
+proto owned string ThreadFunction(Class owner, string name, int backtrace, out int linenumber);
+
+//!Helper for passing string expression to functions with void parameter. Example: Print(String("Hello " + var));
+string String(string s)
+{
+	return s;
+}
+
+//!Helper for printing out string expression. Example: PrintString("Hello " + var);
+void PrintString(string s)
+{
+	Print(s);
+}
+
+class array<Class T>
+{
+	/*!
+	O(1) complexity.
+	\return Number of elements of the array
+	*/
+	proto native int Count();
+	/*!
+	Destroyes all elements of the array and sets the Count to 0.
+	The underlying memory of the array is not freed.
+	*/
+	proto native void Clear();
+	/*!
+	Sets n-th element to given value.
+	*/
+	proto void Set(int n, T value);
+	/*!
+	Tries to find the first occurance of given value in the array.
+	\return Index of the first occurance of `value` if found, -1 otherwise
+	*/
+	proto int Find(T value);
+	/*!
+	\return Element at the index `n`
+	*/
+
+	proto T Get(int n);
+	/*!
+	Inserts element at the end of array.
+	\param value
+	Element to be inserted
+	\return
+	Position at which element is inserted
+	*/
+	proto int Insert(T value);
+	/*!
+	Inserts element at certain position and moves all elements behind
+	this position by one.
+	\param value
+	Element to be inserted
+	\param index
+	Position at which element is inserted. Must be less than Array::GetCardinality()
+	\return
+	Number of elements after insertion
+	*/
+	proto int InsertAt(T value, int index);
+	/**
+	\brief Inserts all elements from array
+		\param from \p array<T> array from which all elements will be added
+		@code
+			TStringArray arr1 = new TStringArray;
+			arr1.Insert( "Dave" );
+			arr1.Insert( "Mark" );
+			arr1.Insert( "John" );
+			
+			TStringArray arr2 = new TStringArray;
+			arr2.Insert( "Sarah" );
+			arr2.Insert( "Cate" );
+			
+			arr1.InsertAll(arr2);
+			
+			for ( int i = 0; i < arr1.Count(); i++ )
+			{
+				Print( arr1.Get(i) );
+			}
+			
+			delete arr2;
+			delete arr1;
+
+			>> "Dave"
+			>> "Mark"
+			>> "John"
+			>> "Sarah"
+			>> "Cate"
+		@endcode
+	*/
+	void InsertAll(notnull array<T> from)
+	{
+		for ( int i = 0; i < from.Count(); i++ )
+		{
+			Insert( from.Get(i) );
+		}
+	}
+	/*!
+	Removes element from array. The empty position is replaced by
+	last element, so removal is quite fast but do not retain order.
+	\param index
+	Index of element to be removed
+	*/
+	proto native void Remove(int index);
+	/*!
+	Removes element from array, but retain all elements ordered. It's
+	slower than Remove
+	\param index
+	Index of element to be removed
+	*/
+	proto native void RemoveOrdered(int index);
+	/*!
+	Resizes the array to given size.
+	If the `newSize` is lower than current Count overflowing objects are destroyed.
+	If the `newSize` is higher than current Count missing elements are initialized to zero (null).
+	*/
+	proto native void Resize(int newSize);
+	
+	/*!
+	Resizes the array to given size internally.
+	Is used for optimization purposes when the approx. size is known beforehand
+	*/
+	proto native void Reserve(int newSize);
+
+	/*!
+	Swaps the contents of this and `other` arrays.
+	Does not involve copying of the elements.
+	*/
+	proto native void Swap(notnull array<T> other);
+
+	/*!
+	Sorts elements of array, depends on underlaying type.
+	*/
+	proto native void Sort(bool reverse = false);
+	/*!
+	Copes contents of `from` array to this array.
+	\return How many elements were copied
+	*/
+
+	proto int Copy(notnull array<T> from);
+	proto int Init(T init[]);
+
+	void RemoveItem(T value)
+	{
+		int remove_index = Find(value);
+
+		if ( remove_index >= 0 )
+		{
+			RemoveOrdered(remove_index);
+		}
+	}
+	
+	void RemoveItemUnOrdered(T value)
+	{
+		int remove_index = Find(value);
+
+		if ( remove_index >= 0 )
+		{
+			Remove(remove_index);
+		}
+	}
+	
+	bool IsValidIndex( int index )
+	{
+		return ( index > -1 && index < Count() );
+	}
+	
+	/*
+	T GetChecked( int index )
+	{
+		if( IsValidIndex( index ) )
+			return Get( index );
+		else
+			return null;
+	}
+	*/
+
+	/**
+	\brief Print all elements in array
+		\return \p void
+		@code
+			my_array.Debug();
+
+			>> "One"
+			>> "Two"
+			>> "Three"
+		@endcode
+	*/
+	void Debug()
+	{
+		Print(string.Format("Array count: %1", Count()));
+		for (int i = 0; i < Count(); i++)
+		{
+			T item = Get(i);
+			Print(string.Format("[%1] => %2", i, item));
+		}
+	}
+
+	/**
+	\brief Returns a random index of array. If Count is 0, return index is -1 .
+		\return \p int Random index of array
+		@code
+			Print( my_array.GetRandomIndex() );
+
+			>> 2
+		@endcode
+	*/
+	int GetRandomIndex()
+	{
+		if ( Count() > 0 )
+		{
+			return Math.RandomInt(0, Count());
+		}
+		
+		return -1;	
+	}
+
+	/**
+	\brief Returns a random element of array
+		\return \p int Random element of array
+		@code
+			Print( my_array.GetRandomElement() );
+
+			>> "Three"
+		@endcode
+	*/
+	T GetRandomElement()
+	{
+		return Get(GetRandomIndex());
+	}
+
+	void SwapItems(int item1_index, int item2_index)
+	{
+		T item1 = Get(item1_index);
+		Set(item1_index, Get(item2_index));
+		Set(item2_index, item1);
+	}
+	
+	void InsertArray(array<T> other)
+	{
+		for (int i = 0; i < other.Count(); i++)
+		{
+			T item = other.Get(i);
+			Insert(item);
+		}
+	}
+	
+	void Invert()
+	{
+		int left = 0;
+		int right = Count() - 1;
+		if (right > 0)
+		{
+			while (left < right)
+			{
+				T temp = Get(left);
+				Set(left++, Get(right));
+				Set(right--, temp);
+			}
+		}
+	}
+	
+	/**
+	\brief Returns a index in array moved by specific number
+		\return \p int Moved index in this array
+		@code
+			Print( "Count: "+ my_array.Count() );
+			Print( "Moved 1:"+ my_array.MoveIndex(2, 1) );
+			Print( "Moved 3:"+ my_array.MoveIndex(2, 2) );
+
+			>> "Count: 4"
+			>> "Moved index 2 by 1: 3";
+			>> "Moved index 2 by 2: 0";
+		@endcode
+	*/
+	int MoveIndex(int curr_index, int move_number)
+	{
+		int count = Count();
+		int new_index = curr_index;
+		
+		if ( move_number > 0 )
+		{
+			new_index = curr_index + move_number;
+		}
+		
+		if ( move_number < 0 )
+		{
+			new_index = curr_index - move_number;
+			
+			if ( new_index < 0 )
+			{
+				if ( new_index <= -count )
+				{
+					new_index = (new_index % count);
+				}
+				
+				new_index = new_index + count;
+			}
+		}
+		
+		if ( new_index >= count )
+		{
+			new_index = (new_index % count);
+		}
+		
+		// move_number is 0
+		return new_index;
+	}
+	
+	void ShuffleArray()
+	{
+		for (int i = 0; i < Count(); i++)
+		{
+			SwapItems(i,GetRandomIndex());
+		}
+	}
+	
+	/**
+	\brief Returns an index where 2 arrays start to differ from each other
+		\return \p int Index from where arrays differ
+		@code
+			array<int> arr1 = {0,1,2,3};
+			array<int> arr2 = {0,1,3,2};
+			int differsAt = arr1.DifferentAtPosition(arr2);
+			Print(differsAt);
+	
+			>> 2
+		@endcode
+	*/
+	int DifferentAtPosition(array<T> pOtherArray)
+	{
+		if (Count() != pOtherArray.Count())
+		{
+			ErrorEx("arrays are not the same size");
+			return -1;
+		}
+
+		for (int i = 0; i < pOtherArray.Count(); ++i)
+		{
+			if (Get(i) != pOtherArray.Get(i))
+			{
+				return i;
+			}
+		}
+		
+		return -1;
+	}
+};
+
+//force these to compile so we can link C++ methods to them
+typedef array<string> TStringArray;
+typedef array<float> TFloatArray;
+typedef array<int> TIntArray;
+typedef array<bool> TBoolArray;
+typedef array<Class> TClassArray;
+typedef array<Managed> TManagedArray;
+typedef array<ref Managed> TManagedRefArray;
+typedef array<vector> TVectorArray;
+typedef array<typename> TTypenameArray;
+
+class set<Class T>
+{
+	proto native int Count();
+	proto native void Clear();
+	/*!
+	Tries to find the first occurance of given value in the set.
+	\return Index of the first occurance of `value` if found, -1 otherwise
+	*/
+	proto int Find(T value);
+	proto T Get(int n);
+	/*!
+	Inserts element at the end of array.
+	\param value
+	Element to be inserted
+	\return
+	Position at which element is inserted
+	*/
+	proto int Insert(T value);
+	/*!
+	Inserts element at certain position and moves all elements behind
+	this position by one.
+	\param value
+	Element to be inserted
+	\param index
+	Position at which element is inserted. Must be less than Array::GetCardinality()
+	\return
+	Number of elements after insertion
+	*/
+	proto int InsertAt(T value, int index);
+	/*!
+	Removes element from array, but retain all elements ordered.
+	\param index
+	Index of element to be removed
+	*/
+	proto native void Remove(int index);
+	proto int Copy(set<T> from);
+	proto native void Swap(set<T> other);
+	proto int Init(T init[]);
+	
+	void InsertSet(set<T> other)
+	{
+		int count = other.Count();
+		for (int i = 0; i < count; i++)
+		{
+			T item = other[i];
+			Insert(item);
+		}
+	}
+	
+	void RemoveItem(T value)
+	{
+		int remove_index = Find(value);
+		if (remove_index >= 0)
+		{
+			Remove(remove_index);
+		}
+	}
+	
+	void RemoveItems(set<T> other)
+	{
+		int count = other.Count();
+		for (int i = 0; i < count; i++)
+		{
+			T item = other[i];
+			RemoveItem(item);
+		}
+	}
+	
+	void Debug()
+	{
+		Print(string.Format("Set count: %1", Count()));
+		for (int i = 0; i < Count(); i++)
+		{
+			T item = Get(i);
+			Print(string.Format("[%1] => %2", i, item));
+		}
+	}
+};
+
+//force these to compile so we can link C++ methods to them
+typedef set<string> TStringSet;
+typedef set<float> TFloatSet;
+typedef set<int> TIntSet;
+typedef set<Class> TClassSet;
+typedef set<Managed> TManagedSet;
+typedef set<ref Managed> TManagedRefSet;
+typedef set<typename> TTypenameSet;
+
+typedef int MapIterator;
+/**
+ \brief Associative array template
+ \n usage:
+ @code
+ autoptr map<string, int> prg_count = new map<string, int>;
+
+ // fill
+ project_locations.Insert("dayz", 10);
+ project_locations.Insert("arma", 20);
+ project_locations.Insert("tkom", 1);
+
+ Print(project_locations.Get("arma")); // prints '20'
+
+ @endcode
+
+ */
+class map<Class TKey,Class TValue>
+{
+	/*!
+		\return
+		The number of elements in the hashmap.
+	*/
+	proto native int Count();
+
+	/*!
+		Clears the hash map.
+	*/
+	proto native void Clear();
+	/*!
+		Search for an element with the given key.
+			
+		\param key
+		The key of the element to find
+		\return
+		Pointer to element data if found, NULL otherwise.
+	*/
+	proto TValue Get(TKey key);
+	/*!
+		Search for an element with the given key.
+			
+		\param key
+		The key of the element to find
+		\param val
+		result is stored to val
+		\return
+		returns True if given key exist.
+	*/
+	proto bool Find(TKey key, out TValue val);
+	/*!
+	Return the i:th element in the map.
+	Note: This operation is O(n) complexity. Use with care!
+
+	\param index
+	The position of the element in the map
+	\return
+	The element on the i:th position
+	*/
+	proto TValue GetElement(int index);
+	/*!
+	Return the i:th element key in the map.
+	Note: This operation is O(n) complexity. Use with care!
+
+	\param i
+	The position of the element key in the map
+	\return
+	Return key of i-th element
+	*/
+	proto TKey GetKey(int i);
+	/*!
+	Sets value of element with given key. If element with key not exists, it is created.
+	Note: creating new elements is faster using Insert function.
+	*/
+	proto void Set(TKey key, TValue value);
+	/*!
+	Removes element with given key.
+	*/
+	proto void Remove(TKey key);
+	/*!
+	Removes i:th element with given key.
+	Note: This operation is O(n) complexity. Use with care!
+	\param i
+	The position of the element key in the map
+	*/
+	proto void RemoveElement(int i);
+	/*!
+	Returns if map contains element with given key.
+	*/
+	proto bool Contains(TKey key);
+	/*!
+	Insert new element into hash map.
+		
+	\param key
+	Key of element to be inserted.
+	\param value
+	Data of element to be inserted.
+	*/
+	proto bool Insert(TKey key, TValue value);
+	proto int Copy(map<TKey,TValue> from);
+	
+	array<TKey> GetKeyArray()
+	{
+		array<TKey> keys = new array<TKey>;
+		for (int i = 0; i < Count(); i++)
+		{
+			keys.Insert( GetKey( i ) );
+		}
+		return keys;
+	}
+	
+	array<TValue> GetValueArray()
+	{
+		array<TValue> elements = new array<TValue>;
+		for (int i = 0; i < Count(); i++)
+		{
+			elements.Insert( GetElement( i ) );
+		}
+		return elements;
+	}
+	
+	bool ReplaceKey(TKey old_key, TKey new_key)
+	{
+		if (Contains(old_key))
+		{
+			Set(new_key, Get(old_key));
+			Remove(old_key);
+			return true;
+		}	
+		return false;
+	}
+	
+	TKey GetKeyByValue(TValue value)
+	{
+		TKey ret;
+		for (int i = 0; i < Count(); i++)
+		{
+			if (GetElement(i) == value) 
+			{
+				ret = GetKey(i);
+				break;
+			}
+		}
+
+		return ret;
+	}
+	
+	bool GetKeyByValueChecked(TValue value, out TKey key)
+	{
+		for (int i = 0; i < Count(); i++)
+		{
+			if (GetElement(i) == value) 
+			{
+				key = GetKey(i);
+				return true;
+			}
+		}
+		return false;
+	}
+
+	proto native MapIterator Begin();
+	proto native MapIterator End();
+	proto native MapIterator Next(MapIterator it);
+	proto TKey GetIteratorKey(MapIterator it);
+	proto TValue GetIteratorElement(MapIterator it);
+};
+
+typedef map<int, float>				TIntFloatMap;
+typedef map<int, int>					TIntIntMap;
+typedef map<int, string>			TIntStringMap;
+typedef map<int, Class>				TIntClassMap;
+typedef map<int, Managed>			TIntManagedMap;
+typedef map<int, ref Managed>	TIntManagedRefMap;
+typedef map<int, typename>		TIntTypenameMap;
+typedef map<int, vector>			TIntVectorMap;
+
+typedef map<string, float>		TStringFloatMap;
+typedef map<string, int>			TStringIntMap;
+typedef map<string, string>		TStringStringMap;
+typedef map<string, Class>		TStringClassMap;
+typedef map<string, Managed>	TStringManagedMap;
+typedef map<string, ref Managed>	TStringManagedRefMap;
+typedef map<string, typename>	TStringTypenameMap;
+typedef map<string, vector>		TStringVectorMap;
+
+typedef map<Class, float>		TClassFloatMap;
+typedef map<Class, int>			TClassIntMap;
+typedef map<Class, string>		TClassStringMap;
+typedef map<Class, Class>		TClassClassMap;
+typedef map<Class, Managed>		TClassManagedMap;
+typedef map<Class, ref Managed>		TClassManagedRefMap;	
+typedef map<Class, typename>	TClassTypenameMap;
+typedef map<Class, vector>		TClassVectorMap;
+
+typedef map<typename, float>		TTypeNameFloatMap;
+typedef map<typename, int>			TTypeNameIntMap;
+typedef map<typename, string>		TTypeNameStringMap;
+typedef map<typename, Class>		TTypeNameClassMap;
+typedef map<typename, Managed>		TTypeNameManagedMap;
+typedef map<typename, ref Managed>	TTypeNameManagedRefMap;
+typedef map<typename, typename>		TTypeNameTypenameMap;
+typedef map<typename, vector>		TTypeNameVectorMap;
+
+typedef map<Managed, float>		TManagedFloatMap;
+typedef map<Managed, int>		TManagedIntMap;
+typedef map<Managed, string>	TManagedStringMap;
+typedef map<Managed, Class>		TManagedClassMap;
+typedef map<Managed, Managed>	TManagedManagedMap;
+typedef map<Managed, ref Managed>	TManagedManagedRefMap;
+typedef map<Managed, typename>	TManagedTypenameMap;
+typedef map<Managed, vector>	TManagedVectorMap;
+
+typedef map<ref Managed, float>	TManagedRefFloatMap;
+typedef map<ref Managed, int>		TManagedRefIntMap;
+typedef map<ref Managed, string>	TManagedRefStringMap;
+typedef map<ref Managed, Class>		TManagedRefClassMap;
+typedef map<ref Managed, Managed>	TManagedRefManagedMap;
+typedef map<ref Managed, ref Managed>	TManagedRefManagedRefMap;
+typedef map<ref Managed, typename>	TManagedRefTypenameMap;
+typedef map<ref Managed, vector>	TManagedRefVectorMap;
+
+ //@}

+ 529 - 0
Scripts/1_core/proto/enstring.c

@@ -0,0 +1,529 @@
+/**
+ * \defgroup Strings Strings
+ * @{
+ */
+class string
+{
+	static const string Empty;
+			
+	/**
+	\brief Converts string to integer
+		\return \p int - Converted \p string.
+		@code
+			string str = "56";
+			int i = str.ToInt();
+			Print(i);
+
+			>> i = 56
+		@endcode
+	*/
+	proto native int ToInt();
+	
+	/**
+	\brief Converts string to integer
+		\return \p int - Converted \p string.
+		@code
+			string str = "0xFF";
+			int i = str.HexToInt();
+			Print(i);
+
+			>> i = 255
+		@endcode
+	*/
+	proto native int HexToInt();
+	
+	/**
+	\brief Converts string to float
+		\return \p float - Converted \p string \p in float.
+		@code
+			string str = "56.6";
+			float f = str.ToFloat();
+			Print(f);
+
+			>> f = 56.6
+		@endcode
+	*/
+	proto native float ToFloat();
+			
+	/**
+	\brief Returns a vector from a string
+		\return \p vector Converted s as vector
+		@code
+			string str = "1 0 1";
+			vector v = str.ToVector();
+			Print(v);
+
+			>> v = <1,0,1>
+		@endcode
+	*/
+	proto vector ToVector();
+		
+	
+	/**
+	\brief Convert beautified string into a vector
+	    \param vec \p beautified string
+		\return \p vector resulting vector
+	*/
+	vector BeautifiedToVector()
+	{
+		string copy = value;
+		copy.Replace("<", "");
+		copy.Replace(">", "");
+		copy.Replace(",", " ");
+		return copy.ToVector();
+	}
+	/**
+	\brief Converts string's first character to ASCII code
+		\param str String for convert to ASCII code
+		\return \p ascii code \p int.
+		@code
+			int ascii = "M".ToAscii();
+			Print(ascii);
+
+			>> ascii = 77
+		@endcode
+	*/
+	proto native int ToAscii();
+	
+	/**
+	\brief Returns internal type representation. Can be used in runtime, or cached in variables and used for faster inheritance checking
+		\returns \p typename Type of class
+		@code
+			???
+		@endcode
+	*/
+	proto native typename ToType();
+
+	//! Return string representation of variable
+	static proto string ToString(void var, bool type = false, bool name = false, bool quotes = true);
+	
+	/**
+	\brief Substring of 'str' from 'start' position 'len' number of characters
+		\param start Position in \p str
+		\param len Count of characters
+		\return \p string - Substring of \p str
+		@code
+			string str = "Hello World";
+			string strSub = str.Substring(2, 5);
+			Print(strSub);
+
+			>> strSub = llo W
+		@endcode
+	*/
+	proto string Substring(int start, int len);
+	
+	//! Inverted SubString. This deletes everything in between position_start and position_end.
+	string SubstringInverted( string string_to_split, int position_start, int position_end )
+	{
+		string first_half = string_to_split.Substring(0, position_start);
+		string second_half = string_to_split.Substring( position_end, string_to_split.Length() - position_end );
+		string result = first_half + second_half;
+		return result;
+	}
+	
+	/**
+	\brief Substring of 'str' from 'startChar' position 'len' number of characters for UTF8 strings with multibyte chars
+		\param startChar Position in \p str.
+		\param len Count of characters
+		\return \p string - Substring of \p str with \p startChar character and \p len characters
+		@code
+			string str = "こんにちは世界";
+			string strSub = str.SubstringUtf8(2, 4);
+			Print(strSub);
+
+			>> strSub = にちは世
+		@endcode
+	*/
+	proto string SubstringUtf8(int startChar, int len);
+
+	/**
+	\brief Replace all occurrances of 'sample' in 'str' by 'replace'
+		\param sample string to search in \p str
+		\param replace string which replace \p sample in \p str
+		\return \p int - number of occurrances of 'sample' in 'str' 
+		@code
+		string test = "If the length of the C string in source is less than num, only the content up to the terminating null-character is copied.";
+		Print(test);
+		int count = test.Replace("the", "*");
+		Print(count);
+		Print(test);
+
+		>> string test = 'If the length of the C string in source is less than num, only the content up to the terminating null-character is copied.';
+		>> int count =   4
+		>> string test = 'If * length of * C string in source is less than num, only * content up to * terminating null-character is copied.'
+		@endcode
+	*/
+	proto int Replace(string sample, string replace);
+
+	/**
+	\brief Changes string to lowercase. Returns length
+		\return \p int - Length of changed string
+		@code
+			string str = "Hello World";
+			int i = str.ToLower();
+			Print(str);
+			Print(i);
+
+			>> str = hello world
+			>> i = 11
+		@endcode
+	*/
+	proto int ToLower();
+
+	/**
+	\brief Changes string to uppercase. Returns length
+		\return \p int - Length of changed string
+		@code
+			string str = "Hello World";
+			int i = str.ToUpper();
+			Print(str);
+			Print(i);
+
+			>> str = HELLO WORLD
+			>> i = 11
+		@endcode
+	*/
+	proto int ToUpper();
+
+	/**
+	\brief Returns length of string
+		\return \p int - Length of string
+		@code
+			string str = "Hello World";
+			int i = str.Length();
+			Print(i);
+
+			>> i = 11
+		@endcode
+	*/
+	proto native int Length();
+	
+	/**
+	\brief Returns number of characters in UTF8 string
+		\return \p int - Number of characters in UTF8 string
+		@code
+			string str = "こんにちは世界";
+			int i = str.LengthUtf8();
+			Print(i);
+
+			>> i = 7
+		@endcode
+	*/
+	proto native int LengthUtf8();
+
+	/**
+	\brief Returns hash of string
+		\return \p int - Hash of string
+		@code
+			string str = "Hello World";
+			int hash = str.Hash();
+			Print(hash);
+		@endcode
+	*/
+	proto native int Hash();
+	
+	/**
+	\brief Finds 'sample' in 'str'. Returns -1 when not found
+		\param sample \p string Finding string
+		\return \p int - Returns position where \p sample starts, or -1 when \p sample not found
+		@code
+			string str = "Hello World";
+			Print( str.IndexOf( "H" ) );
+			Print( str.IndexOf( "W" ) );
+			Print( str.IndexOf( "Q" ) );
+
+			>> 0
+			>> 6
+			>> -1
+		@endcode
+	*/
+	proto native int IndexOf(string sample);
+	
+	/**
+	\brief Finds last 'sample' in 'str'. Returns -1 when not found
+		\param sample \p string Finding string
+		\return \p int - Returns position where \p sample starts, or -1 when \p sample not found
+		@code
+			string str = "Hello World";
+			Print( str.IndexOf( "l" ) );
+			
+			>> 9
+		@endcode
+	*/
+	proto native int LastIndexOf(string sample);
+
+	/**
+	\brief Finds 'sample' in 'str' from 'start' position. Returns -1 when not found
+		\param start \p int Start from position
+		\param sample \p string Finding string expression
+		\return \p int - Length of string \p s
+		@code
+			string str = "Hello World";
+			Print( str.IndexOfFrom( 3, "H" ) );
+			Print( str.IndexOfFrom( 3, "W" ) );
+			Print( str.IndexOfFrom( 3, "Q" ) );
+
+			>> -1
+			>> 6
+			>> -1
+		@endcode
+	*/
+	proto native int IndexOfFrom(int start, string sample);
+
+	/**
+	\brief Returns true if sample is substring of string
+		\param sample \p string Finding string expression
+		\return \p bool true if sample is substring of string
+		@code
+			string str = "Hello World";
+			Print( str.IndexOfFrom( 3, "Hello" ) );
+			Print( str.IndexOfFrom( 3, "Mexico" ) );
+			
+			>> true
+			>> false
+		@endcode
+	*/
+	bool Contains(string sample)
+	{
+		return value.IndexOf(sample) != -1;
+	}
+
+	/**
+	\brief Returns trimmed string with removed leading and trailing whitespaces
+		\return \p string - Trimmed string
+		@code
+			string str = " Hello World "
+			Print( str );
+			Print( str.Trim() );
+
+			>> ' Hello World '
+			>> 'Hello World'
+		@endcode
+
+	*/
+	proto string Trim();
+
+	/**
+	\brief Removes leading and trailing whitespaces in string. Returns length
+		\return \p int - Count of chars
+		@code
+			string str = " Hello World ";
+			int i = str.TrimInPlace();
+			Print(str);
+			Print(i);
+
+			>> str = 'Hello World'
+			>> i = 11
+		@endcode
+	*/
+	proto int TrimInPlace();
+	
+	/**
+	\brief Parses one token from input string. Result is put into token string, and type of token is returned. Input string is left-truncated by the resulting token length.
+		\param[out] token \p string Founded string token
+		\return \p int Type of token
+		\verbatim
+	Token types:
+	 0 - error, no token
+	 1 - defined token (special characters etc. . / * )
+	 2 - quoted string. Quotes are removed -> TODO
+	 3 - alphabetic string
+	 4 - number
+	 5 - end of line -> TODO
+		\endverbatim
+		@code
+			string input = "Hello*World";
+			string token1;
+			string token2;
+
+			int result1 = input.ParseStringEx(token1);
+			int result2 = input.ParseStringEx(token2);
+
+			Print( "Token1 = '" + token1 + "' Type = " + result1.ToString() ) );
+			Print( "Token2 = '" + token2 + "' Type = " + result2.ToString() ) );
+			
+			>> 'Toke1 = 'Hello' Type = 3'
+			>> 'Toke1 = '*' Type = 1'
+		@endcode
+	*/
+	proto int ParseStringEx(out string token);
+
+	/**
+	\brief Parses string into array of tokens returns number of tokens
+		\param[out] tokens \p array[] Parsed string in array
+		\return \p int Number of tokens
+		@code
+			string token[2];
+			string str = "Hello World";
+			int result = str.ParseString(token);
+
+			for (int i = 0; i < 2; i++)
+			{
+				Print(token[i]);
+			}
+
+			>> 'Hello'
+			>> 'World'
+		@endcode
+	*/
+	proto int ParseString(out string tokens[]);
+	
+	/**
+	\brief Splits string into array of strings separated by 'sample'
+		\param sample \p string Strings separator
+		\return \p TStringArray Array with strings
+		@code
+			string example = "The quick brown fox jumps over the lazy dog";
+			TStringArray strs = new TStringArray;
+			example.Split(" ", strs);
+			
+			for (int i = 0; i < strs.Count(); i++)
+			{
+				Print(strs.Get(i));
+			}
+
+			>> 'The'
+			>> 'quick'
+			>> 'brown'
+			>> 'fox'
+			>> 'jumps'
+			>> 'over'
+			>> 'the'
+			>> 'lazy'
+			>> 'dog'
+		@endcode
+	*/
+	void Split(string sample, out array<string> output)
+	{
+		int txt_len	= 0;
+		int sep_pos	= -1;
+		int nxt_sep_pos = 0;
+		string text = "";
+
+		bool line_end = false;
+		while (line_end == false)
+		{
+			sep_pos = sep_pos + txt_len + 1;
+			nxt_sep_pos = value.IndexOfFrom(sep_pos, sample);
+			if ( nxt_sep_pos == -1 )
+			{
+				nxt_sep_pos = value.Length();
+				line_end = true;
+			}
+
+			txt_len = nxt_sep_pos - sep_pos;
+			if ( txt_len > 0 )
+			{
+				text = value.Substring(sep_pos, txt_len);
+				output.Insert(text);
+			}
+		}
+	}
+
+	// !Joins array of strings into a single string, separated by 'separator'. Inverse of Split
+	static string Join(string separator, notnull TStringArray tokens)
+	{
+		string output;
+		foreach (int i, string s: tokens)
+		{
+			if (i != 0)
+				output += separator;
+			output += s;
+		}
+		return output;
+	}
+
+	/**
+	\brief Gets n-th character from string
+		\param index character index
+		\return \p string character on index-th position in string
+		\warning VME When index less than 0 or greater than string length  
+		@code
+			string str = "Hello World";
+			Print( str[4] ); // Print( str.Get(4) );
+
+			>> 'o'
+		@endcode
+	*/ 			
+	proto string Get(int index);
+	
+	/**
+	\brief Sets the n-th character in string with the input, replacing previous value
+		\param index index to be replaced
+		\param input single non-terminated character value to replace with
+		\warning VME When index less than 0 or greater than string length  
+		\warning (Diag)		VME When string is empty or greater than length of 1
+				 (Retail)	Calls 'string.Insert' except it replaces only the initial character
+		@code
+			string str = "Hello World";
+			str[4] = "O";
+			Print( str );
+	
+			>> 'HellO World'
+		@endcode
+		
+		@code
+			string str = "Hello World";
+			str[6] = "Test ";
+			Print( str );
+	
+			>> 'Hello Test orld'
+		@endcode
+	*/ 
+	proto void Set(int index, string input);
+
+#ifdef DIAG_DEVELOPER
+	/**
+	\brief Do not use. Re-implemented for verification of new function due to design of previous function allowing for unexpected behavior that modders may depend on.
+		\see string.Set warnings for handling existing mods in Retail 
+		@code
+			string str = "Hello World";
+			str.OldSet(6, "Test ");
+			Print( str );
+	
+			>> 'Hello Test orld'
+		@endcode
+	 */
+	void OldSet(int n, string _value)
+	{
+		string pre = value.Substring(0, n);
+		n += 1;
+		int length = value.Length() - n;
+		string post = value.Substring(n, length);
+		value = pre + _value + post;
+	}
+#endif
+	
+	/**
+	\brief Inserts a string into the n-th index, increasing the string length by the size of the input
+		\param index index to insert at
+		\param input string value to insert with
+		\warning VME When index less than 0 or greater than string length  
+		\warning VME When string is empty
+		@code
+			string str = "Hello World";
+			str.Insert(6, "Test ");
+			Print( str );
+	
+			>> 'Hello Test World'
+		@endcode
+	*/ 
+	proto void Insert(int index, string input);
+	
+	/**
+	\brief Gets n-th character from string
+		\param index character index
+		\return \p string character on index-th position in string
+		@code
+		int a = 5;
+		float b = 5.99;
+		string c = "beta";
+		string 	test = string.Format("Ahoj %1 = %3 , %2", a, b, c);
+		Print(test);	
+		>> 'Ahoj 5 = 'beta' , 5.99'
+		@endcode
+	*/ 			
+	static proto string Format(string fmt, void param1 = NULL, void param2 = NULL, void param3 = NULL, void param4 = NULL, void param5 = NULL, void param6 = NULL, void param7 = NULL, void param8 = NULL, void param9 = NULL);
+};
+
+//@}

+ 534 - 0
Scripts/1_core/proto/ensystem.c

@@ -0,0 +1,534 @@
+/**
+ * \defgroup System System
+ * @{
+ */
+
+/**
+\brief Returns world time
+	\param[out] hour \p int Hour
+	\param[out] minute \p int Minute
+	\param[out] second \p int Second
+	\return \p void
+	@code
+		int hour = 0;
+		int minute = 0;
+		int second = 0;
+
+		GetHourMinuteSecondUTC(hour, minute, second);
+
+		Print(hour);
+		Print(minute);
+		Print(second);
+
+		>> hour = 16
+		>> minute = 38
+		>> second = 7
+	@endcode
+*/
+proto void GetHourMinuteSecond(out int hour, out int minute, out int second);
+
+/**
+\brief Returns world date
+	\param[out] year \p int Year
+	\param[out] month \p int Month
+	\param[out] day \p int Day
+	\return \p void
+	@code
+		int year = 0;
+		int month = 0;
+		int day = 0;
+
+		GetYearMonthDay(year, month, day);
+
+		Print(year);
+		Print(month);
+		Print(day);
+
+		>> year = 2015
+		>> month = 3
+		>> day = 24
+	@endcode
+*/
+proto void GetYearMonthDay(out int year, out int month, out int day);
+
+/**
+\brief Returns UTC world time
+	\param[out] hour \p int Hour
+	\param[out] minute \p int Minute
+	\param[out] second \p int Second
+	\return \p void
+	@code
+		int hour = 0;
+		int minute = 0;
+		int second = 0;
+
+		GetHourMinuteSecondUTC(hour, minute, second);
+
+		Print(hour);
+		Print(minute);
+		Print(second);
+
+		>> hour = 15
+		>> minute = 38
+		>> second = 7
+	@endcode
+*/
+proto void GetHourMinuteSecondUTC(out int hour, out int minute, out int second);
+
+/**
+\brief Returns UTC world date
+	\param[out] year \p int Year
+	\param[out] month \p int Month
+	\param[out] day \p int Day
+	\return \p void
+	@code
+		int year = 0;
+		int month = 0;
+		int day = 0;
+
+		GetYearMonthDayUTC(year, month, day);
+
+		Print(year);
+		Print(month);
+		Print(day);
+
+		>> year = 2015
+		>> month = 3
+		>> day = 24
+	@endcode
+*/
+proto void GetYearMonthDayUTC(out int year, out int month, out int day);
+
+proto string GetProfileName();
+proto string GetMachineName();
+
+//! performance counter. Returns number of CPU ticks between 'prev' and 'now'
+proto native int TickCount(int prev);
+
+/**
+\brief Switches memory validation (huge slowdown! Use with care only for certain section of code!)
+	\param enable \p bool Enable
+	\return \p void
+	@code
+		???
+	@endcode
+*/
+proto native void MemoryValidation(bool enable);
+
+/**
+\brief Returns command line argument
+	\param name of a command line argument
+	\param val \p string value of the param or empty string if the param hasn't been found
+	\return True if param is present, False if hasn't been found
+	@code
+		string param;
+		GetCLIParam("world", param); // return a value when program executed with param -world something
+	@endcode
+*/
+proto bool GetCLIParam(string param, out string val);	
+	
+/**
+\brief Returns if command line argument is present
+	\param name of a command line argument
+	\return True if param is present, False if hasn't been found
+	@code
+		if (IsCLIParam("verbose")) // Prints "something" when program executed with param -verbose
+		{ 
+			Print("something");
+		}
+	@endcode
+*/
+proto native bool IsCLIParam(string param);		
+	
+#ifdef ENF_DONE
+
+//! developer tool - start video grabber
+proto native void StartVideo(string name);
+//! developer tool - stop video grabber
+proto native void StopVideo();
+#endif
+
+
+/**
+ * \defgroup Keyboard Keyboard input API
+ * @{
+ */
+enum KeyCode
+{
+	KC_ESCAPE,
+	KC_1,
+	KC_2,
+	KC_3,
+	KC_4,
+	KC_5,
+	KC_6,
+	KC_7,
+	KC_8,
+	KC_9,
+	KC_0,
+	KC_MINUS,   ///< - on main keyboard 
+	KC_EQUALS,
+	KC_BACK,    ///< backspace 
+	KC_TAB,
+	KC_Q,
+	KC_W,
+	KC_E,
+	KC_R,
+	KC_T,
+	KC_Y,
+	KC_U,
+	KC_I,
+	KC_O,
+	KC_P,
+	KC_LBRACKET,
+	KC_RBRACKET,
+	KC_RETURN,   ///< Enter on main keyboard 
+	KC_LCONTROL,
+	KC_A,
+	KC_S,
+	KC_D,
+	KC_F,
+	KC_G,
+	KC_H,
+	KC_J,
+	KC_K,
+	KC_L,
+	KC_SEMICOLON,
+	KC_APOSTROPHE,
+	KC_GRAVE,    ///< accent grave 
+	KC_LSHIFT,
+	KC_BACKSLASH,
+	KC_Z,
+	KC_X,
+	KC_C,
+	KC_V,
+	KC_B,
+	KC_N,
+	KC_M,
+	KC_COMMA,
+	KC_PERIOD,   ///< . on main keyboard 
+	KC_SLASH,    ///< / on main keyboard 
+	KC_RSHIFT,
+	KC_MULTIPLY,    ///< * on numeric keypad 
+	KC_LMENU,    ///< left Alt 
+	KC_SPACE,
+	KC_CAPITAL,
+	KC_F1,
+	KC_F2,
+	KC_F3,
+	KC_F4,
+	KC_F5,
+	KC_F6,
+	KC_F7,
+	KC_F8,
+	KC_F9,
+	KC_F10,
+	KC_NUMLOCK,
+	KC_SCROLL,    ///< Scroll Lock 
+	KC_NUMPAD7,
+	KC_NUMPAD8,
+	KC_NUMPAD9,
+	KC_SUBTRACT,    ///< - on numeric keypad 
+	KC_NUMPAD4,
+	KC_NUMPAD5,
+	KC_NUMPAD6,
+	KC_ADD,    ///< + on numeric keypad 
+	KC_NUMPAD1,
+	KC_NUMPAD2,
+	KC_NUMPAD3,
+	KC_NUMPAD0,
+	KC_DECIMAL,   ///< . on numeric keypad 
+	KC_OEM_102,    ///< < > | on UK/Germany keyboards 
+	KC_F11,
+	KC_F12,
+	KC_NUMPADEQUALS,    ///< = on numeric keypad (NEC PC98) 
+	KC_PREVTRACK,    ///< Previous Track (DIKC_CIRCUMFLEX on Japanese keyboard) 
+	KC_AT,    ///<                     (NEC PC98) 
+	KC_COLON,    ///<                     (NEC PC98) 
+	KC_UNDERLINE,    ///<                     (NEC PC98) 
+	KC_STOP,    ///<                     (NEC PC98) 
+	KC_AX,    ///<                     (Japan AX) 
+	KC_UNLABELED,    ///<                        (J3100) 
+	KC_NEXTTRACK,    ///< Next Track 
+	KC_NUMPADENTER,    ///< Enter on numeric keypad 
+	KC_RCONTROL,
+	KC_MUTE,    ///< Mute 
+	KC_CALCULATOR,    ///< Calculator 
+	KC_PLAYPAUSE,    ///< Play / Pause 
+	KC_MEDIASTOP,    ///< Media Stop 
+	KC_VOLUMEDOWN,    ///< Volume - 
+	KC_VOLUMEUP,    ///< Volume + 
+	KC_WEBHOME,    ///< Web home 
+	KC_NUMPADCOMMA,    ///< , on numeric keypad (NEC PC98) 
+	KC_DIVIDE,    ///< / on numeric keypad 
+	KC_SYSRQ,
+	KC_RMENU,    ///< right Alt 
+	KC_PAUSE,    ///< Pause 
+	KC_HOME,    ///< Home on arrow keypad 
+	KC_UP,    ///< UpArrow on arrow keypad 
+	KC_PRIOR,    ///< PgUp on arrow keypad 
+	KC_LEFT,    ///< LeftArrow on arrow keypad 
+	KC_RIGHT,    ///< RightArrow on arrow keypad 
+	KC_END,    ///< End on arrow keypad 
+	KC_DOWN,    ///< DownArrow on arrow keypad 
+	KC_NEXT,    ///< PgDn on arrow keypad 
+	KC_INSERT,    ///< Insert on arrow keypad 
+	KC_DELETE,    ///< Delete on arrow keypad 
+	KC_LWIN,    ///< Left Windows key 
+	KC_RWIN,    ///< Right Windows key 
+	KC_APPS,    ///< AppMenu key 
+	KC_POWER,    ///< System Power 
+	KC_SLEEP,    ///< System Sleep 
+	KC_WAKE,    ///< System Wake 
+	KC_MEDIASELECT   ///< Media Select 
+};
+
+/*!
+Gets key state
+\param key	Key code
+\returns 0 when not pressed, 15. bit set when pressed, 0.-14. bit pressed count 
+*/
+proto native int KeyState(KeyCode key);
+
+/*!
+Clears the key state.
+Call this function if you want to overcome autorepeating in reporting key state. If called, the KeyState returns pressed only after the key is released and pressed again.
+*/
+proto native void ClearKey(KeyCode key);
+/** @}*/
+
+//! returns index of defined key in InputDevice by its name
+//proto native int GetDefKey(string name);
+//proto native int DefKeyState(int defkey, bool clear);
+
+
+/**
+ * \defgroup Mouse Mouse API
+ * @{
+ */
+
+enum MouseState
+{
+	LEFT,
+	RIGHT,
+	MIDDLE,
+	X,
+	Y,
+	WHEEL
+};
+//const int MB_PRESSED_MASK
+
+/*!
+Returns state of mouse button. It's combination of number of release/pressed edges and mask MB_PRESSED_MASK
+that is set when button is pressed.
+If you want just to check if button is pressed, use this: if(GetMouseState(MouseState.LEFT) & MB_PRESSED_MASK)) Print("left button pressed");
+*/	
+proto native int GetMouseState(MouseState index);
+
+// Gets current mouse position
+proto void GetMousePos(out int x, out int y);
+// Gets current screen size (resolution)
+proto void GetScreenSize(out int x, out int y);
+
+/** @}*/
+
+/**
+ * \defgroup Gamepad API
+ * @{
+ */
+
+enum GamepadButton
+{
+	BUTTON_NONE,
+	MENU,
+	VIEW,
+	A,
+	B,
+	X,
+	Y,
+	PAD_UP,
+	PAD_DOWN,
+	PAD_LEFT,
+	PAD_RIGHT,
+	SHOULDER_LEFT,
+	SHOULDER_RIGHT,
+	THUMB_LEFT,
+	THUMB_RIGHT
+};
+
+enum GamepadAxis
+{
+	LEFT_THUMB_HORIZONTAL,
+	LEFT_THUMB_VERTICAL,
+	RIGHT_THUMB_HORIZONTAL,
+	RIGHT_THUMB_VERTICAL,
+	LEFT_TRIGGER,
+	RIGHT_TRIGGER,
+};
+
+//! return if the button is pressed or not
+proto native int GetGamepadButton(GamepadButton button);
+//! return value in gamepad axis <-1000; 1000>
+proto native float GetGamepadAxis(GamepadAxis axis);
+
+/** @}*/
+
+//----------------------------------------------
+/**
+ * \defgroup File FileIO API
+ * @{
+ */
+
+enum FileMode
+{
+	READ,
+	WRITE,
+	APPEND
+};
+	
+typedef int[] ParseHandle;
+typedef int[] FileHandle;
+
+proto native ParseHandle BeginParse(string filename);
+proto int ParseLine(ParseHandle tp, int num, string tokens[]);
+proto native void EndParse(ParseHandle file);
+
+//!Check existence of file
+proto bool FileExist(string name);
+
+/**
+\brief Opens File
+	@param name of a file to open, (you can use filesystem prefixes ('$profile','$saves','$mission'). For accessing profile dir use '$profile', e.g. '$profile:myfilename.txt')
+	@param mode constants FileMode.WRITE, FileMode.READ or FileMode.APPEND flag can be used
+	\return file handle ID or 0 if fails
+	\n usage :
+	@code
+	FileHandle file = OpenFile("$profile:testiik.txt", FileMode.WRITE);
+	//FileHandle file = OpenFile("$profile:testiik.txt", FileMode.APPEND);
+	if (file != 0)
+	{
+		FPrintln(file, "line1");
+		FPrintln(file, "line2");
+		FPrintln(file, "line3");
+		CloseFile(file);
+	}
+	@endcode
+*/
+proto FileHandle		OpenFile(string name, FileMode mode);
+
+/**
+Reads raw data from file.
+\param param_array Receiving array for the data. Valid types are int[] or string
+\param length Length of data
+\returns number of read bytes
+*/
+proto int ReadFile(FileHandle file, void param_array, int length);
+
+/**
+\brief Close the File
+	@param file File handle ID of a opened file
+	\return void
+	\n usage :
+	@code
+	FileHandle file = OpenFile("$profile:testiik.txt", FileMode.WRITE);
+	if (file != 0)
+	{
+		FPrintln(file, "line1");
+		FPrintln(file, "line2");
+		FPrintln(file, "line3");
+		CloseFile(file);
+	}
+	@endcode
+*/
+proto void		CloseFile(FileHandle file);
+
+/**
+\brief Write to file
+	@param file File handle ID of a opened file
+	@param var Value to write
+	\return void
+	\n usage :
+	@code
+	FileHandle file = OpenFile("$profile:testiik.txt", FileMode.WRITE);
+	if (file != 0)
+	{
+		FPrint(file, "A");
+		FPrint(file, "B");
+		FPrint(file, "C");
+		CloseFile(file);
+	}
+	@endcode
+*/
+proto void		FPrint(FileHandle file, void var);
+
+/**
+\brief Write to file and add new line
+	@param file File handle ID of a opened file
+	@param var Value to write
+	\return void
+	\n usage :
+	@code
+	FileHandle file = OpenFile("$profile:testiik.txt", FileMode.WRITE);
+	if (file != 0)
+	{
+		FPrintln(file, "line1");
+		FPrintln(file, "line2");
+		FPrintln(file, "line3");
+		CloseFile(file);
+	}
+	@endcode
+*/
+proto void		FPrintln(FileHandle file, void var);
+
+/**
+\brief Get line from file, every next call of this function returns next line
+	@param file File handle ID of a opened file
+	@param var Value to write
+	\return int Count of chars or -1 if is not any for read (end of file is EMPTY line)
+	\n usage :
+	@code
+		FileHandle file_handle = OpenFile("$profile:testiik.txt", FileMode.READ);
+		string line_content;
+
+		while ( FGets( file_handle,  line_content ) > 0 )
+		{
+			Print(line_content);
+		}
+
+		CloseFile(file_handle);
+	@endcode
+*/
+proto int		FGets(FileHandle file, string var);
+
+typedef int[] FindFileHandle;
+
+enum FileAttr
+{
+	DIRECTORY, ///<File is directory
+	HIDDEN, ///<File is hidden
+	READONLY, ///<File is read-only
+	INVALID ///<Invalid file
+};
+
+enum FindFileFlags
+{
+	DIRECTORIES, ///<Looks for files in fs directories only.
+	ARCHIVES,	///<Looks for files in archive only. (.pak)
+	ALL ///<Looks in archives and fs directories.
+}
+
+proto FindFileHandle FindFile(string pattern, out string fileName, out FileAttr fileAttributes, FindFileFlags flags);
+proto bool FindNextFile(FindFileHandle handle, out string fileName, out FileAttr fileAttributes);
+proto native void CloseFindFile(FindFileHandle handle);
+
+//!Makes a directory
+proto native bool MakeDirectory(string name);
+
+//!delete file. Works only on "$profile:" and "$saves:" locations
+proto native bool DeleteFile(string name);
+
+//! copy file. destName must be "$profile:" or "$saves:" location
+proto native bool CopyFile(string sourceName, string destName);
+/** @}*/
+
+ //@}

+ 244 - 0
Scripts/1_core/proto/envisual.c

@@ -0,0 +1,244 @@
+/**
+ * \defgroup Visual Visual objects
+ * @{
+ */
+
+//! Loads object from data, or gets it from cache. Object must be released when not used
+proto native vobject GetObject(string name);
+
+/*!
+Release object. When there are not any other references, object is stored into cache and ready to be victed if necessary.
+\param object Object handle
+\param flag If RF_RELEASE is used, the object is evicted immediatelly, if not used by anyone else
+*/
+proto native void ReleaseObject(vobject object, int flag = 0);
+
+//! Returns number of frames, if the object is animation
+proto native int GetNumAnimFrames(vobject anim);
+
+//! Returns name of visual object
+proto string vtoa(vobject vobj);
+
+/**
+ * \defgroup MeshObject Mesh object (XOB)
+ * @{
+ */
+
+proto int GetObjectMaterials(vobject object, string materials[]);
+
+// dynamic model creation (for dynamic aabb triggers)
+//proto void CreateModel(IEntity ent, vector mins, vector maxs);
+//proto void RemoveModel(IEntity ent);
+
+//! Dynamic MeshObject
+proto vobject CreateXOB(int nsurfaces, int nverts[], int numindices[], string materials[]);
+proto void UpdateVertsEx(notnull IEntity ent, int surf, vector verts[], float uv[]);
+proto void UpdateIndices(vobject obj, int surf, int indices[]);
+
+proto native void	SetBone(notnull IEntity ent, int bone, vector angles, vector trans, float scale);
+proto native bool	SetBoneMatrix(notnull IEntity ent, int bone, vector mat[4]);
+proto native void	SetBoneGlobal(notnull IEntity ent, int bone, vector mat[4]);
+proto native bool	GetBoneMatrix(notnull IEntity ent, int bone, vector mat[4]);
+proto native bool	GetBoneLocalMatrix(notnull IEntity ent, int bone, vector mat[4]);
+
+proto native void	SetAnimFrame(notnull IEntity ent, int slot, float frame);
+
+//! BoneMask == NULL means that all bits are set
+//! WARNING: Non-managed, needs manual delete call, should not be ref'd
+class BoneMask
+{
+	int Mask[8]
+}
+
+enum AnimFlags
+{
+	//! animation is played only once and then if freezes at the last frame. EntityEvent.ANIMEND is called
+	ONCE,
+/*! defaultne zustava animace pri prehravani a AF_ONCE po skonceni na posledni frame "zamrzla", dokud neni nahrazena jinou,
+ nebo neni kanal vynulovan. Pokud se nastavi AF_BLENDOUT, postara se engine o vyhozeni animace sam a pro preblendovani pouzije hodnotu
+ blendout. Pokud je odchycen EOnAnimEnd a byla zmenena animace na jinou, nebo byl kanal rucne vynulovan, tak se tato
+ funkcnost neprovede. */
+	BLENDOUT,
+
+//! animation waits on the first frame. Frame is set by calling SetFrame()
+	USER,
+
+//! forces animation to start from begining (including blending)
+	RESET,
+
+/*! defaul framerate is from anim.def. If it is missing, parametr fps applies
+It is possible to use fps parameter even when the framerate is defined in the anim.def, is using this flag
+*/
+	FORCEFPS,
+
+//! EntityEvent.ANIMEND will not be called
+	NOANIMEND,
+
+//! Animhooks will not be called
+	NOANIMHOOKS
+};
+
+proto native void	SetAnimSlot(notnull IEntity ent, int slot, vobject anim, float blendin, float blendout, BoneMask mask, int fps, AnimFlags flags);
+
+// changes a mask and does the blending if the blendin is set
+proto native void ChangeAnimSlotMask(notnull IEntity ent, int slot, float blendin, BoneMask mask);
+
+// changes animation framerate to fps param
+proto native void ChangeAnimSlotFPS(notnull IEntity ent, int slot, int fps);
+
+// set mask for a channel. There are 12 chanels and mask is using first for bits 0..3
+proto native void	SetAnimMask(notnull IEntity ent, int mask);
+
+// clears chanal mask, return bits which were cleared
+proto native int	ClearAnimMask(notnull IEntity ent, int mask);
+
+//vrati nastavene bity tech kanalu, ktere maji nastavenou animaci, nejsou na konci
+// a pro ktere byla nastavena vstupni maska.
+//Je tim mozno se dotazat na stav vice slotu najednou
+proto native int IsAnimSlotPlaying(notnull IEntity ent, int mask);
+//mask - 16bitu, pro 16 anim slotu. Maximalni hodnota je tedy 0xffff!
+
+//sets how much this morph affect object
+proto native bool SetMorphState(notnull IEntity ent, string morph, float value);
+//morph name
+//value 0...1
+//@}
+
+
+/**
+ * \defgroup ParticleEffect Particle effect API
+ * @{
+ */
+
+enum EmitorParam
+{
+	//! Vector3 R/W
+	CONEANGLE,
+	
+	//! Vector3 R/W
+	EMITOFFSET,
+	
+	//! Float R/W
+	VELOCITY,
+	
+	//! Float R/W
+	VELOCITY_RND,
+	
+	//! Float R/W
+	AVELOCITY,
+	
+	//! Float R/W
+	SIZE,
+	
+	//! Float R/W
+	STRETCH,
+
+	//! begin with random rotation. Bool R/W
+	RANDOM_ANGLE,
+	
+	//! rotate in random direction. Bool R/W
+	RANDOM_ROT,
+
+	//! Float R/W
+	AIR_RESISTANCE,
+	
+	//! Float R/W
+	AIR_RESISTANCE_RND,
+
+	//! Float R/W
+	GRAVITY_SCALE,
+
+	//! Float R/W
+	GRAVITY_SCALE_RND,
+	
+	//! Float R/W
+	BIRTH_RATE,
+
+	//! Float R/W
+	BIRTH_RATE_RND,
+
+	//! Float R/W
+	LIFETIME,
+
+	//! Float R/W
+	LIFETIME_RND,
+
+	//! Bool R/W
+	LIFETIME_BY_ANIM,
+
+	//! Bool R/W
+	ANIM_ONCE,
+
+	//! Bool R/W
+	RAND_FRAME,
+
+	//! efector's total time. Float R/W
+	EFFECT_TIME,
+
+	//! should efector repeate after time up? Bool R/W
+	REPEAT,
+
+	//! current efector's time. Float R/W
+	CURRENT_TIME,
+
+	//! number of active particles. Int R
+	ACTIVE_PARTICLES,
+
+	//! Bool R/W
+	SORT,
+
+	//! Bool R/W
+	WIND,
+
+	//! Float R/W
+	SPRING
+};
+
+// return total count of active particles in all emitors
+// internally does a sum
+// HasActiveParticles is better when just needing to check if there are any active
+proto native int GetParticleCount(notnull IEntity ent);
+
+// return if there are any active particles
+proto bool HasActiveParticle(notnull IEntity ent);
+
+int ParticleGetCount(IEntity ent)
+{
+	return GetParticleCount(ent);
+}
+
+bool ParticleHasActive(IEntity ent)
+{
+	return HasActiveParticle(ent);
+}
+
+// gets name of defined emitors in a particle effect
+// return number of emitors and their names in an array (max defines max. emitors to return)
+proto int GetParticleEmitors(notnull IEntity ent, out string emitors[], int max);
+
+// return number of emitors
+proto int GetParticleEmitorCount(notnull IEntity ent);
+
+// sets a parametr of the particle emitor
+// if the emitor == - 1, it sets the parameter for all emitors
+proto void SetParticleParm(notnull IEntity ent, int emitor, EmitorParam parameter, void value);
+
+//gets parameter of particle emitor
+proto void GetParticleParm(notnull IEntity ent, int emitor, EmitorParam parameter, out void value);
+
+//gets original parameter of particle emitor
+proto void GetParticleParmOriginal(notnull IEntity ent, int emitor, EmitorParam parameter, out void value);
+
+//Force-changes particle emitor position to the current one.
+//Used for sudden changes of particle position to avoid spreading emitted
+//particles between previous and the new one position
+proto native void ResetParticlePosition(notnull IEntity ent);
+
+//Restart particle effect to its default state. This means no 
+//particles, timer reset and so on. Usefull for implementing
+//particle cache.
+proto native void RestartParticle(notnull IEntity ent);
+//@}
+
+
+//@}

+ 281 - 0
Scripts/1_core/proto/envrdevice.c

@@ -0,0 +1,281 @@
+#ifdef GAME_TEMPLATE
+
+/**
+* \defgroup VRDeviceAPI generic and platform specific devices
+* @{
+*/
+
+enum VRDeviceType
+{
+	DEVICE_TYPE_OCULUS,
+	DEVICE_TYPE_PS4
+}
+
+enum VRStatus
+{
+	VR_STATUS_UNKNOWN,					//< Unknown state, probably uninitialized.
+	VR_STATUS_VISIBLE,					//< The HMD is being used for rendering.
+	VR_STATUS_PRESENT,					//< The HMD port is open.
+	VR_STATUS_MOUNTED,					//<	The HMD is mounted on users head.
+	VR_STATUS_DISPLAY_LOST,			//< The HMD was present and disappeared.
+	VR_STATUS_SHOULD_QUIT,			//< Application requested exit.
+	VR_STATUS_SHOULD_RECENTER,	//< The HMD Recenter request event was triggered. 
+	VR_STATUS_TRACKED,					//< The tracking data for the HMD are up to date.
+	VR_STATUS_CALIBRATING,			//< The HMD is being calibrated.
+}
+
+enum VRHandEnum
+{
+	VR_HAND_LEFT, //< HMD controller left hand.
+	VR_HAND_RIGHT //< HMD controller right hand.
+}
+
+enum VREye
+{
+	VR_EYE_LEFT, // HMD left eye.
+	VR_EYE_RIGHT // HMD right eye.
+}
+
+/*!
+	VRDevice interface common for all VR implementations.
+
+	DO NOT INHERIT FROM THIS CLASS!
+*/
+class VRDevice : Managed
+{
+	/*!
+		\brief returns VRDevice instance.
+		\return device instance.
+	*/
+	proto native static VRDevice GetInstance();
+
+	/*!
+		\brief returns status flags.
+
+		\return current device state flags.
+	*/
+	proto native VRStatus 				GetStatusFlags();
+	/*!
+		\brief returns device name.
+		\return device brand name.
+	*/
+	proto native owned string	GetName();
+	/*!
+		\brief returns device type. 
+		\return device type enum.
+	*/
+	proto native VRDeviceType GetDeviceType();
+	/*!
+		\brief Forces immediate head recenter.
+
+		Uses the current scene position and orientation
+		as the new camera origin.
+	*/
+	proto native void 								RecenterHeadTracking();
+	/*!
+		\brief returns HMD head position .
+		\return position in world space.
+	*/
+	proto native vector 						GetHeadPosition();
+	/*!
+		\brief returns HMD head orientation. 
+		\return Euler angles in device space. (Yaw, Pitch, Roll)
+	*/
+	proto native vector 						GetHeadOrientation();
+	/*!
+		\brief returns HMD controller's position.
+
+		\param hand left/right hand enum.
+		\return position in world space.
+	*/
+	proto native vector 						GetHandPosition(VRHand hand);
+	/*!
+		\brief returns HMD controller's orientation.
+
+		\param hand left/right hand enum.
+		\return Euler angles in device space. (Yaw, Pitch, Roll)
+	*/
+	proto native vector 						GetHandOrientation(VRHand hand);
+	/*!
+		\brief returns HMD Eye's position.
+
+		\param eye left/right eye enum.
+		\return position in world space.
+	*/
+	proto native vector 						GetEyePosition(VREye eye);
+	/*!
+		\brief returns HMD Eye's orientation.
+		
+		\param eye left/right eye enum.
+		\return Euler angles in device space. (Yaw, Pitch, Roll)
+	*/
+	proto native vector							GetEyeOrientation(VREye eye);
+	/*!
+		\brief Sets up current vr scale.
+		
+		All translations will get scaled by this value.
+		With higher scale values will the world around look smaller.
+
+		"Warning: The tracking errors will render more visible with high scale."
+		\param scale the scale amount.
+	*/
+	proto native void 								SetScale(float scale);
+	/*!
+		\brief returns current vr scale.
+		\return the scale amount. 
+	*/
+	proto native float 							GetScale();
+
+	/*!
+		\brief returns current FOV's tangent values.
+
+		In VR mode the FOV should be asymmetric.
+		\returns tangent values of asymetric FOV.
+	*/
+	proto external void 						GetEyeFOV(VREye eye, out float leftTan, out float rightTan, out float upTan, out float downTan);
+};
+
+enum PSVrHeadRecenterFlagsEnum
+{
+	VR_RECENTER_POSITION,
+	VR_RECENTER_ORIENTATION
+}
+
+enum PSVrBrightnessRiskEnum
+{
+	VR_BRIGHTNESS_RISK_LOW,
+	VR_BRIGHTNESS_RISK_HIGH,
+	VR_BRIGHTNESS_RISK_MAX
+}
+
+enum PSVrTrackingQualityEnum
+{
+	VR_TRACKING_QUALITY_NONE,
+	VR_TRACKING_QUALITY_NOT_VISIBLE,
+	VR_TRACKING_QUALITY_PARTIAL,
+	VR_TRACKING_QUALITY_FULL
+}
+
+enum PSVrDialogStatusEnum
+{
+	VR_DIALOG_UNKNOWN,
+	VR_DIALOG_OK,
+	VR_DIALOG_CANCELED,
+	VR_DIALOG_RUNNING	
+}
+
+/*!
+	PS4 specific VR interface.
+*/
+class VRDevice_PS4 : VRDevice
+{
+	/*!
+		\brief Switches VR device into 2D "theater" mode.
+
+		Don't forget to set appropriate FOV.
+
+		At the moment the device uses the render targets of the
+		left eye. These render targets are 8:9 and we are still rendering
+		both eyes. If the feature gets used in a actual gameplay we can
+		extend it to separate set of 16:9 render targets.
+
+		\param enabled enable/disable flag.
+	*/
+	proto native void Set2D(bool enabled);
+	/*!
+		\brief Pops up HMD service dialog.
+		\return true when dialog was opened and his state was resolved as OK.
+	*/
+	proto native bool ShowHmdServiceDialog();
+	/*!
+		\brief Pops up HMD setup dialog.
+		\return true when dialog was opened and closed successfully.
+	*/
+	proto native bool ShowHmdSetupDialog();
+	/*!
+		\brief Returns current setup dialog state.
+		\return dialog state enum.
+	*/
+	proto native PSVrDialogStatusEnum GetSetupDialogStatus();
+	/*!
+		\brief Returns current service dialog state.
+		\return dialog state enum.
+	*/
+	proto native PSVrDialogStatusEnum GetServiceDialogStatus();
+
+	/*!
+		\brief HMD recentering hint flags setup.
+	*/
+	proto native void SetRecenterHeadFlags(PSVrHeadRecenterFlagsEnum flags);
+	/*!
+		\brief Returns HMD recentering flags.
+		\return recentering enum.
+	*/
+	proto native PSVrHeadRecenterFlagsEnum GetRecenterHeadFlags();
+	/*!
+		\brief Returns the eye offset in device space.
+		\return 3D position centered around device space center.
+	*/
+	proto native vector GetEyeOffset(VREye eye);
+	/*!
+		\brief Sets up the minimal displayable color.
+
+		Setup this value when smears start appearing in 
+		dark environments.
+	*/
+	proto native void SetMinOutputColor(int color);
+	/*!
+		\brief Per eye FOV setup.
+
+		Keep in mind that changing the values from device presets
+		may cause user discomfort.
+	*/
+	proto native void SetEyeFOV(VREye eye, float leftTan, float rightTan, float upTan, float downTan);
+	/*!
+		\brief Resets the FOV settings to device preset value.
+	*/
+	proto native void ResetToDeviceFOV(VREye eye);
+	/*!
+		\brief Sets up the render target size multiplier.
+
+		Set this value before the device gets initialized.
+	*/
+	proto native void SetOversamplingFactor(float factor);
+	/*!
+		\brief Returns HMD tracking status.
+		\param bRisk tracked scene brightness risk.
+		\param posQuality precision of the HMD position.
+		\param orQuality precision of tthe HMD orientation.
+		\return false when the HMD port is not open.
+	*/
+	proto bool GetHmdTrackingStatus(	out PSVrBrightnessRiskEnum bRisk, 
+																		out PSVrTrackingQualityEnum posQuality, 
+																		out PSVrTrackingQualityEnum orQuality);
+	/*!
+		\brief Returns Move controller tracking status.
+
+		\param hand identifier of the contoller.
+		\param bRisk tracked scene brightness risk.
+		\param posQuality precision of the controllers position.
+		\param orQuality precision of the controllers orientation.
+		\return false when the Move port is not open.
+	*/
+	proto bool GetMoveTrackingStatus(	VRHand hand, 
+																						out PSVrBrightnessRiskEnum bRisk, 
+																						out PSVrTrackingQualityEnum posQuality, 
+																						out PSVrTrackingQualityEnum orQuality);
+}				
+
+/*!
+	Oculus specific VR interface.
+*/
+class Oculus : VRDevice
+{
+	// TODO:
+}
+
+/*
+* @}
+*/
+
+#endif

+ 712 - 0
Scripts/1_core/proto/enwidgets.c

@@ -0,0 +1,712 @@
+/**
+ * \defgroup WidgetAPI Widget UI system
+ * @{
+ */
+
+#ifdef DOXYGEN
+/** @name WidgetType
+ *  Following WidgetType constants are available to script 
+ */
+///@{
+
+	//!Single-line text. See enf::TextWidget
+	TextWidgetTypeID,
+	//!Multi-line text. See enf::MultilineTextWidget
+	MultilineTextWidgetTypeID,
+	//!Multi-line edit box. See enf::MultilineTextWidget
+	MultilineEditBoxWidgetTypeID,
+	//!Multi-line text with images in text. See enf::RichTextWidget
+	RichTextWidgetTypeID,
+	//! Render target for enf::BaseWorld. See enf::RenderTargetWidget
+	RenderTargetWidgetTypeID,
+	//! Picture, or multiple picture. See enf::ImageWidget
+	ImageWidgetTypeID,
+	//!Console. See enf::ConsoleWidget
+	ConsoleWidgetTypeID,
+	//!Video player. See enf::VideoWidget
+	VideoWidgetTypeID,
+	//! Texture used as render target for children widgets. See enf::RTTextureWidget
+	RTTextureWidgetTypeID,
+	//! Dummy frame, used as hierarchy node and clipper
+	FrameWidgetTypeID,
+	//! Dummy frame, used for embedding another layout and as hierarchy node and clipper
+	EmbededWidgetTypeID,
+	ButtonWidgetTypeID,
+	CheckBoxWidgetTypeID,
+	WindowWidgetTypeID,
+	ComboBoxWidgetTypeID,
+	SimpleProgressBarWidgetTypeID,
+	ProgressBarWidgetTypeID,
+	SliderWidgetTypeID,
+	BaseListboxWidgetTypeID,
+	TextListboxWidgetTypeID,
+	GenericListboxWidgetTypeID,
+	EditBoxWidgetTypeID,
+	PasswordEditBoxWidgetTypeID,
+	WorkspaceWidgetTypeID,
+	GridSpacerWidgetTypeID,
+	WrapSpacerWidgetTypeID,
+	ScrollWidgetTypeID,	
+///@}
+#else
+	typedef TypeID WidgetType;
+#endif
+
+typedef TypeID EventType;
+
+enum WidgetFlags
+{
+	SOURCEALPHA, //< takes alpha from texture * alpha from color. If not set, considers texture as non-transparent and transparency is set only by color
+	BLEND,	//< texture is blended with a surface base on alpha
+	ADDITIVE,	//< texture is added to a surface based on alpha
+	VISIBLE,	//<Widget is visible - ShowWidget(w, true)
+	NOWRAP,	//< Do not do texture wrapping
+	CENTER,	//< Centers TextWidgetTypeID
+	VCENTER,	//< Centers TextWidgetTypeID verticaly
+	HEXACTPOS,
+	VEXACTPOS,
+	EXACTPOS,	//< Uses physical resolution (g_iWidth, h_iHeight)
+	HEXACTSIZE,	//< Uses physical resolution (g_iWidth)
+	VEXACTSIZE,	//< Uses physical resolution (h_iHeight)
+	EXACTSIZE,	//< Uses physical resolution
+	NOFILTER,	//< no texture filtering (no blur)
+	RALIGN,	//< Right alignment TextWidgetTypeID
+	STRETCH,	//< Stretch texture to a full size
+	FLIPU,	//< Flips texture in U axis
+	FLIPV,	//< Flips texture in V axis
+	CUSTOMUV,	//< ignores STRETCH/FLIPU/FLIPV and take custom UV set by SetWidgetUV()
+	IGNOREPOINTER,
+	DISABLED,
+	NOFOCUS,
+	CLIPCHILDREN,
+	RENDER_ALWAYS,
+	NOCLEAR,
+	DRAGGABLE
+};
+
+//------------------------------------------
+enum WidgetAlignment
+{
+	WA_LEFT			= 0,
+	WA_RIGHT		= 1,
+	WA_CENTER		= 2,
+	WA_TOP			= 0,
+	WA_BOTTOM		= 1,
+}
+
+//------------------------------------------
+//! Defined in code
+/*enum LinebreakOverrideMode
+{
+	LINEBREAK_DEFAULT,
+	LINEBREAK_WESTERN,
+	LINEBREAK_ASIAN
+};*/
+
+//------------------------------------------
+class Widget: Managed
+{
+	proto void ~Widget();
+	proto private void Widget();
+	
+	proto static string TranslateString(string stringId);
+	
+	//! Set global LV of widgets, value between [-15, 0], default: 0, lower value is less bright
+	proto static void SetLV(float lv);
+	//! Set global LV of the text in widgets, value between [-15, 0], default: 0, lower value is less bright
+	proto static void SetTextLV(float lv);
+	//! Set global lighting of objects in widgets, value between [0, 1], default: 1, lower value is less bright
+	proto static void SetObjectLighting(float lighting);
+	
+	proto native owned string GetName();
+	proto native void SetName(string name);
+	proto native owned string GetTypeName();
+	proto native WidgetType GetTypeID();
+	proto native void Show(bool show, bool immedUpdate = true);
+	proto native void Enable(bool enable);
+	proto native int GetFlags();
+	proto native int SetFlags(int flags, bool immedUpdate = true); //! ADDS the value to the existing flag
+	proto native int GetSort();
+	proto native void SetSort(int sort, bool immedUpdate = true);
+	proto native int ClearFlags(int flags, bool immedUpdate = true); //! SUBSTRACTS the value to the existing flag
+	proto native bool IsControlClass();
+	proto native owned string GetStyleName();
+	proto void GetUserData(out Class data);
+	proto native void SetUserData(Class data);
+	proto native int GetUserID();
+	proto native void SetUserID(int id);
+	proto native bool IsVisible();
+	proto native bool IsVisibleHierarchy();
+	proto native void SetPos(float x, float y, bool immedUpdate = true);
+	proto native void SetSize(float w, float h, bool immedUpdate = true);
+	proto native void SetScreenPos(float x, float y, bool immedUpdate = true);
+	proto native void SetScreenSize(float w, float h, bool immedUpdate = true);
+	proto native void SetColor(int color);
+	proto native int GetColor();
+	proto native void SetRotation(float roll, float pitch, float yaw, bool immedUpdate = true);
+	//! returns rotation of widget in order roll, pitch, yaw
+	proto native vector GetRotation();
+	proto native void SetAlpha(float alpha);
+	proto native float GetAlpha();
+	proto void GetPos(out float x, out float y);
+	proto void GetSize(out float width, out float height);
+	proto void GetScreenPos(out float x, out float y);
+	proto void GetScreenSize(out float width, out float height);
+
+  proto native void SetTransform(vector mat[4], bool immedUpdate = true);
+
+  proto native Widget GetParent();
+	proto native Widget GetChildren();
+	proto native Widget GetSibling();
+	proto native void AddChild(Widget child, bool immedUpdate = true);
+	proto native void RemoveChild(Widget child);
+
+	proto native volatile void Update();
+
+	proto void GetScript(out Class data);
+
+	proto native Widget FindWidget(string pathname);	//find Widget by path. e.g FindWidget("widget1.widget2.widget3.mywidget")
+	proto native Widget FindAnyWidget(string pathname);	//find Widget by name e.g. FindWidget("widget1")
+	proto native Widget FindAnyWidgetById(int user_id);	//find Widget by userID
+
+	proto native void SetHandler(ScriptedWidgetEventHandler eventHandler);
+	proto native void Unlink(); //destroys widget and all its children
+};
+
+class WorkspaceWidget: Widget
+{
+	//!Create widgets by \ref WidgetType
+	proto native external Widget CreateWidget(WidgetType type, int left, int top, int width, int height, WidgetFlags flags, int color, int sort, Widget parentWidget = NULL);
+	//!Create widgets from *.layout file
+	proto native external Widget CreateWidgets(string layout, Widget parentWidget = NULL, bool immedUpdate = true);	
+};
+
+proto native Widget GetWidgetUnderCursor();
+proto native Widget CancelWidgetDragging();
+proto native Widget GetDragWidget();
+proto native void ReportMouse(int mousex, int mousey, Widget rootWidget);
+
+class TextWidget extends Widget
+{
+  	proto native void SetTextSpacing(int horiz, int vert);
+	//! set text exact size. Exact Text flag must be enabled. 0 equals original size.
+	proto native void SetTextExactSize(int size);
+  	proto native void SetTextOffset(int left, int top);
+	proto native void SetText(string text, bool immedUpdate = true);
+	proto native void SetOutline(int outlineSize, int argb = 0xFF000000);
+	proto native int GetOutlineSize();
+	proto native int GetOutlineColor();
+	proto native void SetShadow(int shadowSize, int shadowARGB = 0xFF000000, float shadowOpacity = 1, float shadowOffsetX = 0, float shadowOffsetY = 0);
+	proto native int GetShadowSize();
+	proto native int GetShadowColor();
+	proto native float GetShadowOpacity();
+	proto void GetShadowOffset(out float sx, out float sy);
+	proto native void SetItalic(bool italic);
+	proto native bool GetItalic();
+	proto native void SetBold(bool bold);
+	proto native bool GetBold();
+	
+	//! Returns text size in pixels
+	proto void GetTextSize(out int sx, out int sy);
+	proto void SetTextFormat(string text, void param1 = NULL, void param2 = NULL, void param3 = NULL, void param4 = NULL, void param5 = NULL, void param6 = NULL, void param7 = NULL, void param8 = NULL, void param9 = NULL);
+	
+	//! Get text proportion - ratio between button height and button text height in interval <0,1>
+	proto native float GetTextProportion();
+	//! Set text proportion - ratio between button height and button text height in interval <0,1>
+	proto native void SetTextProportion(float val);
+};
+
+class MultilineTextWidget extends TextWidget
+{
+	proto native float SetLineBreakingOverride(int mode);
+};
+
+class RichTextWidget extends TextWidget
+{
+	proto native float GetContentHeight();
+	proto native float GetContentOffset();
+	proto native void  SetContentOffset(float offset, bool snapToLine = false);
+	proto native void  ElideText(int line, float maxWidth, string str);
+	proto native int   GetNumLines();
+	proto native void  SetLinesVisibility(int lineFrom, int lineTo, bool visible);
+	proto native float GetLineWidth(int line);
+	proto native float SetLineBreakingOverride(int mode);
+};
+
+class RenderTargetWidget extends Widget
+{
+//!when period > 1 then every n-th frame will be rendered. Offset is initial counter.
+	proto native void SetRefresh(int period, int offset);
+	proto native void SetResolutionScale(float xscale, float ycale);
+};
+
+class RTTextureWidget extends Widget
+{
+};
+
+class ImageWidget extends Widget
+{
+	/*!
+	Loads image. When image of this 'num' is already loaded, then is replaced
+	by new one.
+	\param num Number of image (0...7)
+	\param name Name of image file
+	\param noCache Do not cache the texture
+	\return True when image is loaded, false otherwise
+	*/
+	proto native bool LoadImageFile(int num, string name, bool noCache = false);
+	proto native void SetImageTexture(int image, RTTextureWidget texture);
+	//! returns size of image
+	proto void GetImageSize(int image, out int sx, out int sy);
+	
+	/*!
+	Switches to another image, if it's loaded
+	\param num Number of image.
+	\return True when there is such image, false otherwise.
+	*/
+	proto native bool SetImage(int num);
+	//!Returns active image
+	proto native int GetImage();
+	/*!
+	When WF_CUSTOMUV is set, we can supply our own UV coords instead of computed ones.
+	\param uv
+	Pointer to array of at least 8 floats (4 corners * 2 floats for u/v)
+	*/
+	proto native void SetUV(float uv[4][2]);
+	
+	/*!
+	Loads texture as mask used for alpha masking.
+	\param resource Resource name of the texture to load
+	\return True if texture was successfully loaded, false otherwise
+	*/
+	proto native bool LoadMaskTexture(string resource);
+	
+	/*!
+	Progress determines which alpha values are opaque using the mask. For progress x, 
+	pixels with alpha in mask < x will be opaque and alpha in mask > x will be transparent.
+	For smooth transition see GetMaskTransitionWidth.
+	\return Progress from 0 to 1 representing alpha range which is visible in the mask
+	*/
+	proto native float GetMaskProgress();
+	
+	/*!
+	See GetMaskProgress for explanation.
+	\param value Expected in range [0; 1]
+	*/
+	proto native void SetMaskProgress(float value);
+	
+	/*!
+	Transition width 0.1 and progress 0.2 mean that values in mask lower than progress will be opaque.
+	Values higher than (progress + width) will be transparent and values between progress and (progress + width)
+	will be smoothly transitioned.
+	\return Width of the alpha mask transition representing softness of the transition.
+	*/
+	proto native float GetMaskTransitionWidth();
+
+	/*!
+	See GetMaskTransitionWidth for transition width explanation.
+	\param value Expected in range [0; 1]
+	*/
+	proto native void SetMaskTransitionWidth(float value);
+};
+
+class MultilineEditBoxWidget extends TextWidget
+{
+	proto native int GetLinesCount();
+	proto native int GetCarriageLine();
+	proto native int GetCarriagePos();
+	proto void GetText(out string text);
+	proto native void SetLine(int line, string text);
+	proto void GetLine(int line, out string text);
+};
+
+class UIWidget extends Widget
+{
+	proto native void SetTextColor(int color);
+	proto native void SetTextOutline(int outlineSize, int argb = 0xFF000000);
+	proto native int GetTextOutlineSize();
+	proto native int GetTextOutlineColor();
+	proto native void SetTextShadow(int shadowSize, int shadowARGB = 0xFF000000, float shadowOpacity = 1.0, float shadowOffsetX = 0.0, float shadowOffsetY = 0.0);
+	proto native int GetTextShadowSize();
+	proto native int GetTextShadowColor();
+	proto native float GetTextShadowOpacity();
+	proto native float GetTextShadowOffsetX();
+	proto native float GetTextShadowOffsetY();
+	proto native void SetTextItalic(bool italic);
+	proto native bool GetTextItalic();
+	proto native void SetTextBold(bool bold);
+	proto native bool GetTextBold();
+};
+
+class CanvasWidget extends Widget
+{
+	proto native void DrawLine(float x1, float y1, float x2, float y2, float width, int color);
+	proto native void Clear();
+};
+
+class EditBoxWidget extends UIWidget
+{
+	proto string GetText();
+	proto native void SetText(string str);
+};
+
+class PasswordEditBoxWidget extends EditBoxWidget
+{
+	proto native void SetHideText(bool hide);
+};
+
+class SliderWidget extends UIWidget
+{
+	proto native void SetMinMax(float minimum, float maximum);
+	proto native float GetMin();
+	proto native float GetMax();
+	proto native float GetCurrent();
+	proto native void SetCurrent(float curr);
+	proto native float GetStep();
+	proto native void SetStep(float step);
+};
+
+class SimpleProgressBarWidget extends UIWidget
+{
+	proto native float GetMin();
+	proto native float GetMax();
+	proto native float GetCurrent();
+	proto native void SetCurrent(float curr);
+};
+
+class ProgressBarWidget extends SimpleProgressBarWidget
+{
+};
+
+class ButtonWidget extends UIWidget
+{
+	proto native bool GetState();
+ 
+	proto native bool SetState(bool state);
+
+	proto native void SetText(string text);
+
+	proto void GetText(out string text);
+
+	proto native void SetTextOffset(float xoffset, float yoffset);
+/**
+\param align ALIGN_CENTER, ALIGN_LEFT, ALIGN_RIGHT
+*/
+	proto native void SetTextHorizontalAlignment(int align);
+/**
+\param align ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM
+*/
+	proto native void SetTextVerticalAlignment(int align);
+
+	//! Get text proportion - ratio between button height and button text height in interval <0,1>
+	proto native float GetTextProportion();
+	//! Set text proportion - ratio between button height and button text height in interval <0,1>
+	proto native void SetTextProportion(float val);
+};
+
+class XComboBoxWidget extends UIWidget
+{
+	proto native int AddItem(string item);
+	proto native void ClearAll();
+	proto native void SetItem(int item, string value);
+	proto native void RemoveItem(int item);
+	proto native int GetNumItems();
+	proto native int SetCurrentItem(int n);
+	proto native int GetCurrentItem();
+};
+
+class CheckBoxWidget extends UIWidget
+{
+	proto native void SetText(string str);
+	proto native bool IsChecked();
+	proto native void SetChecked(bool checked);
+};
+
+class BaseListboxWidget extends UIWidget
+{
+	proto native void ClearItems();
+	proto native int GetNumItems();
+	proto native void SelectRow(int row);
+	proto native int GetSelectedRow();
+	proto native void RemoveRow(int row);
+	proto native void EnsureVisible(int row);
+};
+
+class SimpleListboxWidget extends BaseListboxWidget
+{
+};
+
+class TextListboxWidget extends SimpleListboxWidget
+{
+	//! Insert new Row, if row = -1, new Row is inserted at the end otherwise at row index.
+	proto native int AddItem(string text, Class userData, int column, int row = -1);
+	proto native void SetItem(int position, string text, Class userData, int column);
+/**
+\brief Get item
+	\param row \p int Index of row
+	\param column \p int Index of column
+	\return \p string Value in widget on row and column
+	@code
+		string value;
+		textListboxWidg.GetItemText(2, 0, value);
+	@endcode
+*/
+	proto bool GetItemText(int row, int column, out string text);
+	proto void GetItemData(int row, int column, out Class data);
+	
+	proto native void SetItemColor(int row, int column, int color );
+};
+
+class SpacerBaseWidget extends UIWidget
+{
+	proto native void AddChildAfter(Widget child,Widget after, bool immedUpdate = true);
+}
+
+class SpacerWidget extends SpacerBaseWidget
+{
+	proto native WidgetAlignment GetContentAlignmentH();
+	proto native void SetContentAlignmentH(WidgetAlignment alignment);
+	proto native WidgetAlignment GetContentAlignmentV();
+	proto native void SetContentAlignmentV(WidgetAlignment alignment);
+}
+
+class GridSpacerWidget extends SpacerWidget
+{
+}
+
+class WrapSpacerWidget extends SpacerWidget
+{
+}
+
+class ScrollWidget extends SpacerBaseWidget
+{
+	proto native float GetScrollbarWidth();
+	proto native bool IsScrollbarVisible(); //reflects native C++ side scrollbar state
+
+	proto native float GetContentWidth();
+	proto native float GetContentHeight();
+	
+	proto native float GetHScrollPos();
+	proto native float GetHScrollPos01();
+	proto native bool HScrollStep(int steps);
+	proto native void HScrollToPos(float pos);
+	proto native void HScrollToPos01(float pos01);
+	proto native void HScrollToWidget(Widget child);
+
+	proto native float GetVScrollPos();
+	proto native float GetVScrollPos01();
+	proto native bool VScrollStep(int steps);
+	proto native void VScrollToPos(float pos);
+	proto native void VScrollToPos01(float pos01);
+	proto native void VScrollToWidget(Widget child);
+};
+
+//! Legacy, do not use
+enum VideoCommand
+{
+	PLAY,
+	STOP,
+	REWIND,
+	POSITION,
+	REPEAT,
+	ISPLAYING,
+	KILL
+};
+
+enum VideoState
+{
+	//! There is no video
+	NONE,
+	//! The video is playing
+	PLAYING,
+	//! The video is paused
+	PAUSED,
+	//! The video is paused at the beginning of the video
+	STOPPED,
+	//! The video is paused at the end of the video
+	FINISHED,
+};
+
+enum VideoCallback
+{
+	ON_PLAY,
+	ON_PAUSE,
+	ON_STOP,
+	ON_END,
+	ON_LOAD,
+	ON_SEEK,
+	ON_BUFFERING_START,
+	ON_BUFFERING_END,
+};
+
+class VideoWidget extends Widget
+{
+	//! Load a video file
+	proto native bool Load(string name, bool looping = false, int startTime = 0);
+	//! Unload the video, freeing up all resources
+	proto native void Unload();
+	
+	//! Starts video playback
+	proto native bool Play();
+	//! Pauses video playback
+	proto native bool Pause();
+	//! Stop video playback (cancels everything and sets it back at time 0)
+	proto native bool Stop();
+	
+	//! Set the desired time for the video (preload decides whether it will already load the next frames too)
+	proto native bool SetTime(int time, bool preload);	
+	//! Get the current time of the video
+	proto native int GetTime();
+	//! Get the total time of the video
+	proto native int GetTotalTime();
+	
+	//! Set whether the video should loop
+	proto native void SetLooping(bool looping);	
+	//! Whether looping is enabled
+	proto native bool IsLooping();
+	
+	//! QoL direct method to check for playing state (buffering while playing will still return true)
+	proto native bool IsPlaying();
+	//! Get the current state of the video
+	proto native VideoState GetState();
+	
+	/**
+	\brief Enable/Disable subtitles
+	\warning Subtitles need font to be assigned to VideoWidget in layout to work
+	\note Subtitles are in the format "videoName_Language.srt"
+	\note It is best to have the English one without language specified "videoName.srt"
+	*/
+	proto native void DisableSubtitles(bool disable);
+	//! Check if subtitles are disabled (enabled by default if available, so it will return false even if there are none)
+	proto native bool IsSubtitlesDisabled();
+	
+	//! Set a callback for a certain video event
+	proto void SetCallback(VideoCallback cb, func fn);
+	
+	//! Legacy, preferably not used, left for backwards compat
+	int Play(VideoCommand cmd)
+	{
+		// Yes, some things here do not do what the name implies
+		// And it returns 0 whether successful or not
+		// But this is what the old functionality looked like
+		// So for true backwards compat, it will be left like this
+		switch (cmd)
+		{
+			case VideoCommand.PLAY:
+				Play();
+				break;
+			case VideoCommand.STOP:
+				Pause();
+				break;
+			case VideoCommand.REWIND:
+				SetTime(0, true);
+				break;		
+			case VideoCommand.POSITION:
+				return GetTime();
+			case VideoCommand.REPEAT:
+				SetLooping(true);
+				break;
+			case VideoCommand.ISPLAYING:
+				return IsPlaying();
+			case VideoCommand.KILL:
+				Unload();
+				break;
+			default:
+				return 0;
+		}
+		
+		return 0;
+	}
+	
+	//! Legacy, preferably not used, left for backwards compat
+	bool LoadVideo(string name, int soundScene)
+	{
+		return Load(name);
+	}
+};
+
+/*! sets Widget typu RTTextureWidgetTypeID, to which it is possible to reference in shader as $rendertarget
+it is posible to use only after object selection. When selecting another object, it is necessary to set GUI widget again
+*/
+proto native void SetGUIWidget(IEntity ent, int index, RTTextureWidget w);
+
+enum ControlID
+{
+	CID_NONE = 0,
+	CID_SELECT = 1,//select/use focused
+	CID_BACK,
+	CID_LEFT, //navigation
+	CID_RIGHT,
+	CID_UP,
+	CID_DOWN,
+	CID_MENU, //get to main menu
+	CID_DRAG, //probably needed only for consoles
+	CID_TABLEFT,
+	CID_TABRIGHT,
+	CID_RADIALMENU,
+	CID_COUNT
+};
+
+class ScriptedWidgetEventHandler: Managed
+{
+	bool OnClick(Widget w, int x, int y, int button);
+	bool OnModalResult(Widget w, int x, int y, int code, int result);
+	bool OnDoubleClick(Widget w, int x, int y, int button);
+	bool OnSelect(Widget w, int x, int y);
+	bool OnItemSelected(Widget w, int x, int y, int row, int column, int oldRow, int oldColumn);
+	bool OnFocus(Widget w, int x, int y);
+	bool OnFocusLost(Widget w, int x, int y);
+	bool OnMouseEnter(Widget w, int x, int y);
+	bool OnMouseLeave(Widget w, Widget enterW, int x, int y);
+	bool OnMouseWheel(Widget w, int x, int y, int wheel);
+	bool OnMouseButtonDown(Widget w, int x, int y, int button);
+	bool OnMouseButtonUp(Widget w, int x, int y, int button);
+	//! control is one of ControlID 
+	bool OnController(Widget w, int control, int value);
+	bool OnKeyDown(Widget w, int x, int y, int key);
+	bool OnKeyUp(Widget w, int x, int y, int key);
+	bool OnKeyPress(Widget w, int x, int y, int key);
+	bool OnChange(Widget w, int x, int y, bool finished);
+	bool OnDrag(Widget w, int x, int y);
+	bool OnDragging(Widget w, int x, int y, Widget reciever);
+	bool OnDraggingOver(Widget w, int x, int y, Widget reciever);
+	bool OnDrop(Widget w, int x, int y, Widget reciever);
+	bool OnDropReceived(Widget w, int x, int y, Widget reciever);
+	bool OnResize(Widget w, int x, int y);
+	bool OnChildAdd(Widget w, Widget child);
+	bool OnChildRemove(Widget w, Widget child);
+	bool OnUpdate(Widget w);
+	bool OnEvent(EventType eventType, Widget target, int parameter0, int parameter1);
+};
+
+//Common Widget API
+proto native void SetCursorWidget(Widget cursor);
+//! direct mouse cursor visibility control
+proto native void ShowCursorWidget(bool show);
+proto native bool LoadWidgetImageSet(string filename);
+proto native void LoadWidgetStyles(string filename);
+// sets active window (widget which owns some control inputs like buttons, listboxes etc.). Necessary for controlling the focus by keyboard/joypad. In case when setFocus is set to true, it sets focus on a first child Widget, which may receive the focus (is not disabled, set as NoFocus etc.)
+proto native bool SetActiveWindow(Widget w, bool resetFocus);
+
+// sets focus (necessary when using keyboard/joyped) to a particular widget. Widget must have some inputs like button, listbox, checkbox, combobox etc.
+proto native void SetFocus(Widget w);
+
+proto native void SetModal(Widget w);
+
+proto native Widget GetFocus();
+
+//RenderTargetWidgetTypeID
+proto native void SetWidgetWorld(RenderTargetWidget w, IEntity wrldEntity, int camera);
+
+
+#ifdef PS3
+	/*!
+	circle and cross can be swapped when license area is japan/asia
+	*/
+	proto native bool IsCircleToCrossSwapped();
+#endif
+
+proto native bool ReloadTexture(string path);
+
+
+//@}

+ 439 - 0
Scripts/1_core/proto/enworld.c

@@ -0,0 +1,439 @@
+/**																																											 /**
+ * \defgroup World World
+ * @{
+ */
+
+//----------------------------------------------
+/**
+ * \defgroup WorldCommon World
+ * @{
+ */
+
+typedef int[] WorldHandle;
+
+proto native float GetWorldTime();
+
+/*! Sets current world. It allows to work with entities outside world processing
+// return previous world
+*/
+proto native WorldHandle SetCurrentWorld(WorldHandle world);
+
+//proto native void SchedulePreload(vector pos, float radius);
+
+proto native IEntity FindEntityByName(IEntity worldEnt, string name);
+proto native IEntity FindEntityByID(IEntity worldEnt, int ID);
+
+//!returns number of active (simulated) Entities in the world
+proto native int GetNumActiveEntities(IEntity worldEntity);
+//!returns active entity
+proto native IEntity GetActiveEntity(IEntity worldEntity, int index);
+//@}
+
+//----------------------------------------------
+/**
+ * \defgroup Camera Camera
+ * @{
+ */
+
+enum CameraType
+{
+	PERSPECTIVE,
+	ORTHOGRAPHIC
+};
+
+//! sets which camera will be a listener (for sound engine)
+proto native void SetListenerCamera(int camera);
+
+/*!
+Changes camera position
+\param cam Index of camera
+\param origin	position
+\param angle	orientation
+*/
+proto native void SetCamera(int cam, vector origin, vector angle);
+
+//! Changes camera matrix
+proto native void SetCameraEx(int cam, const vector mat[4]);
+
+//!Returns current camera transformation
+proto native void GetCamera(int cam, out vector mat[4]);
+
+proto native void SetCameraVerticalFOV(int cam, float fovy);
+proto native void SetCameraFarPlane(int cam, float farplane);		//default 160000 units
+proto native void SetCameraNearPlane(int cam, float nearplane);	//default 5 units
+
+proto native void SetCameraType(int cam, CameraType type);
+
+/*! 
+\brief Post-process effect type.
+\attention Keep enum names in synch with post-process effect material class names. Postfix "Effect" is appended automatically.
+*/
+enum PostProcessEffectType
+{
+	None,
+	UnderWater,
+	SSAO,
+	DepthOfField,
+	HBAO,
+	RotBlur,
+	GodRays,
+	Rain,
+	Snowfall,
+	FilmGrain,
+	RadialBlur,
+	ChromAber,
+	WetDistort,
+	DynamicBlur,
+	ColorGrading,
+	Colors,
+	Glow,
+	SMAA,
+	FXAA,
+	Median,//unused?
+	SunMask,
+	GaussFilter,
+	SSR, //not available
+	Distort,
+	Ghost
+};
+/*!
+set postprocess effect to camera
+To disable effect in some prioroty ppEffect, just set effectName or name to NULL
+\param cam 		number of camera
+\param priority		priority of effect
+\param type	type of effect
+\param materialPath 		material
+*/
+proto native void SetCameraPostProcessEffect(int cam, int priority, PostProcessEffectType type, string materialPath);
+		
+//ent can be NULL for world-space coords
+proto vector	ProjectVector(int cam, IEntity ent, vector vec);
+proto vector	UnprojectVector(int cam, float x, float y, vector dir);
+
+//@}
+
+//----------------------------------------------
+/**
+ * \defgroup Light Light API
+ * @{
+ */
+
+//!Light handle
+typedef int[] HLIGHT;
+
+enum LightType
+{
+	POINT, //< point light, all directional light
+	SPOT,	//<	spot light, direction is determined by owner (entity)
+	DIRECTIONAL,
+	AMBIENT
+};
+
+enum LightFlags
+{
+/*!
+Dynamic light. There is limit 512 dynamic lights per world and
+32 per camera view. They are faster when moving and changing shape.
+Also they are always attached to owner entity
+*/
+	DYNAMIC, 
+	CASTSHADOW,
+//! for cheaper dynamic lights, like muzzle flashes (might use cheaper rendering method)
+	CHEAP
+};
+
+/*!
+creates light
+*/
+proto HLIGHT AddLight(IEntity owner, LightType type, LightFlags flags, float radius, vector color);
+//!removes light
+proto native bool RemoveLight(HLIGHT light);
+proto native bool SetLightEx(HLIGHT light, float radius, vector color);
+//!sets lookup texture for projection lights
+proto native bool SetLightTexture(HLIGHT light, string cubemap);
+proto native int SetLightFlags(HLIGHT light, LightFlags flags);
+proto native int ClearLightFlags(HLIGHT light, LightFlags flags);
+//!Sets light cone in degrees (for LightType.SPOT).
+proto native bool SetLightCone(HLIGHT light, float cone);
+
+/*!
+scene multiplicator of light (based on measured scene light levels) - preexposure of light
+*/
+proto native float GetSceneHDRMul(int camera);
+//@}
+
+
+
+//----------------------------------------------
+/**
+ * \defgroup WorldTrace Trace&Visibility API
+ * @{
+ */
+
+enum TraceFlags
+{
+	BONES, //< tests collision geometries around bones of animated objects
+	ENTS, //< tests entities
+	WORLD, //< tests world bounding box
+	ONLY_PHYSICS,
+	WATER, //< tests collision with water surface
+	PASSTRANSLUCENT,//< Do not intersects with entities with EntityFlags.TRANSLUCENT set
+	RAGDOLLS, //< tests ragdolls
+	VISTEST, //< performs visibility test first. Not necessary for entities receiving EntityEvent.VISIBLE, because there is a certainty that a camera will see them
+	NOTRACE,
+	TRANSPARENT_OCCLUDERS
+};
+
+enum TraceShape
+{
+  LINE,
+  BOX,
+  OBB,
+  SPHERE
+};
+
+//! collision and tracing
+//! WARNING: Non-managed, needs manual delete call, should not be ref'd
+class TraceContact
+{
+	float	Fraction;
+	int		Content;
+	int		Surfparm;
+	int		MaterialFlags;
+	int		Triangle;
+	int		SurfaceID;
+	owned string	MaterialName;
+	owned string	OriginalMaterialName;
+	float		Plane[4];
+	vector	Point;
+}
+
+proto native bool TraceLineToEntity(IEntity ent, vector start, vector end, out TraceContact contact);
+
+//bool FilterCallback(Class target [, vector rayorigin, vector raydirection])
+
+class TraceParam: Managed
+{
+	vector		Start;
+	vector		End;
+	int			LayerMask = 0xffffffff;
+	TraceFlags	Flags;
+	IEntity		Exclude;
+	
+};
+
+class TraceSphere: TraceParam
+{
+	float			Radius;	
+};
+
+class TraceBox: TraceParam
+{
+	vector		Mins;
+	vector		Maxs;
+};
+
+class TraceOBB: TraceBox
+{
+	vector		Mat[3];
+};
+
+/*!
+traces line start->end, return 0..1 if trace was sucessfull.
+// It take bboux from ent
+// flag like in P2PVisibilityEx will be added
+//OUTPUT:
+\param cent		[out] traced entity
+\param plane	[out] traced polygon plane (X,Y,Z,D)
+\param surfparm	 [out] traced surface parameters
+\returns	value 0...1, percentage of a path traveled
+*/
+proto volatile float TraceMove(TraceParam param, out IEntity cent, out float plane[4], out int surfparm, func filtercallback);
+
+
+/*!
+tests visibility
+\param from
+\param to
+\param flags
+//TraceFlags.VISTEST	- 
+//TraceFlags.DETAIL		- test agains detail brushes
+//TraceFlags.ENT			- test against brush entities
+//TraceFlags.NOTRACE	- doesn't test geometry (has meaning in conjuction with s TraceFlags.VISTEST)
+\returns		true is visible/false not visibel
+*/
+proto native int P2PVisibilityEx(vector from, vector to,int flags);
+
+//! finds all entities in a radius
+proto int SphereQuery(vector origin, float radius, out IEntity visents[], int ents, int fmask);
+
+/*!tests if bbox is visible according to view-frustum and PVS
+\param flags & 1 - test also PVS
+\returns true/false is/isn't visible
+*/
+proto native bool IsBoxVisible(vector mins, vector maxs, int flags);
+
+/*!finds all visible entities (rought, according to a visibility. It is convinient for entitie selection where we want to do more precise visibility test)
+\param origin		-		position it is looked from
+\param look		-		look direction
+\param angle		-		view angle (usuably 90). -1 if we do not care about the view angle
+\param ents		-		array to which entities will be stored
+\param maxents	-		length of the array (prevents overflowing the array)
+\param fmask		-		flag mask (SetFlags()). Entity must have all flags set.
+						it is possible to use reserved flags like EntityFlags.USER1, EntityFlags.USER2, EntityFlags.USER6 for fast finding of entities in custom categories
+*/
+proto int		VisEntities(vector origin, vector look, float angle, float radius, out IEntity ents[2], int maxents, int fmask);
+
+/*!
+Object that handles visibility on GPU. Used for coronas etc.
+*/
+class OcclusionQuery
+{
+	proto private void ~OcclusionQuery();
+
+	/*!
+	return Query result
+	\returns  -1 result is not ready yet, try it later.
+  >0 point is visible
+ ==0 point is not visible
+	*/
+	proto native int GetResult();
+
+	//!Sets world position
+	proto native void SetPosition(vector pos);
+	//!Destroys the object
+	proto native void Destroy();
+};
+
+//@}
+
+//----------------------------------------------
+/**
+ * \defgroup Decals Decals API
+ * @{
+ */
+typedef int[] hDecal;
+
+/*!
+Creates single visual mark, e.g. from shots
+//when lifetime=0, pointer to decal is returned, that can be removed by RemoveDecal then
+\param entity		entity where the landmark should be created
+\param origin		first point of the decal, nothing is done now
+\param project	projection direction (length is far clipping distance)
+\param nearclip	near clipping distance
+\param materialName Material used for decal
+\param lifetime	Lifetime in seconds
+\param flags Not used ATM
+\return Decal pointer or null
+*/
+proto native hDecal CreateDecal(IEntity entity, vector origin, vector project, float nearclip, float angle, float size, string materialName, float lifetime, int flags);
+
+proto native void RemoveDecal(hDecal decal);
+
+/*!
+Creates continous visual mark, e.g. from wheel when a car is moving on the ground
+\param entity		entity where the landmark should be created (only terrain is supported ATM)
+\param origin		first point of the decal, nothing is done now
+\param normal		normal of surface
+\param edgesize	Edge size of decal
+\param lifetime	Lifetime in seconds
+\param materialName Material used for decal
+\param prev			Previous decal, we are connecting to
+\param alpha		translucency of point
+\return Decal pointer or null
+*/
+proto native hDecal CreateLandMarkDecal(IEntity entity, vector origin, vector normal, float edgeSize, float lifeTime, string materialName, hDecal prevDecal, float alpha);
+
+
+/*!
+is it possible to add new point to landmark decal?
+\param lmDecal		entity to add new landmark point
+\param entity		entity to add new landmark point
+\param mat			material of decal
+\param newpoint 	new point to add
+\return
+	LMD_ERROR 	= error when adding new point (invalid decal)
+	LMD_VALID 	= can add new point
+	LMD_DIFF_ENT 	= new point is on different entity
+	LMD_TOO_FAR	= new point is too far from previous point
+*/
+proto native int CanAddToLandMarkDecal(hDecal lmDecal, IEntity entity, string mat, vector newPoint);
+
+/*!
+add new point to decal, internally, new point is added when previous point is in some
+distance or the angle is more than some threshold
+\param lmDecal		entity to add new landmark point
+\param point		contact point
+\param normal		normal of contact
+\param alpha		translucency in point
+\return true if everything was OK, false if not. In this case, the application MUST not used later the pointer to decal, it's finalized internally !
+*/
+proto native bool AddPointToLandMarkDecal(hDecal lmDecal, vector point, vector normal, float alpha);
+
+/*!
+finalize landmark adding, e.g. when entity lose contact with ground -> the pointer to decal
+should have only world and entity if it has something to render, otherwise it's destroyed here
+\param lmDecal		entity to add new landmark point
+\param addAlpha	if to add last point with transition to zero alpha
+\param alphaDist	distance to add last point
+*/
+proto native void FinalizeLandMarkDecal(hDecal lmDecal, bool addAlpha, float alphaDist);
+
+/*!
+return if landmark was finalized
+\param lmDecal		decal to test
+*/
+proto native bool IsLandMarkFinalized(hDecal lmDecal);
+
+/*!
+return last landmark point or -65535.0 in all components
+\param lmDecal		decal to test
+*/
+proto native vector GetLastLandMarkPoint(hDecal lmDecal);
+
+/*!
+set global parameters for landmark generation
+\param minSegmentLength		minimum length segment, when new point is added (4 default), when is less, just the end position is on the fly updated
+\param maxSegmentLength		maximum segment length, when length is bigger, the path is finished
+\param degAngle				angle in degrees, when is more, the path is finished
+*/
+proto native void SetGlobalLandMarkParams(float minSegmentLength, float maxSegmentLength, float degAngle);
+
+
+//@}
+
+
+//----------------------------------------------
+/**
+ * \defgroup Ocean Ocean API
+ * @{
+ */
+
+/*!
+Is ocean availabled
+*/
+proto native bool IsOcean();
+
+/*!
+Get water ocean height at given point
+\param worldX		world x position
+\param worldZ		world z position
+*/
+proto native float GetOceanHeight(float worldX, float worldZ);
+
+
+/*!
+Get water ocean height and displacement at given point, returns vector(displaceX, height, displaceZ)
+\param worldX		world x position
+\param worldZ		world z position
+*/
+proto native vector GetOceanHeightAndDisplace(float worldX, float worldZ);
+
+
+
+//@}
+
+
+
+//@}
+ 

+ 390 - 0
Scripts/1_core/proto/proto.c

@@ -0,0 +1,390 @@
+/** @file */
+
+
+/*
+Function/method modifiers:
+proto	- prototyping of internal function (C++ side)
+native - native call convention of internal function (C++ side)
+volatile - internal function that may call back to script (hint for
+  compiler that context need to be saved on stack)
+private - function may not be called from script
+event - hint for tools that the function should be exposed as
+ Entity script event.
+
+Variable modifiers:
+owned - modifier for returing internal functions. Tells to script-VM,
+that returning variable (string or array) must not be released
+out - modifier for function parameters. It tells that variable will
+ be changed by function call (used mainly by internal functions)
+inout - modifier for function parameters. It tells that variable will
+ be used and then changed by function call (used mainly by internal functions)
+
+const - constants. May not be modified.
+reference - hint for tools (Material editor), that the variable may be used
+ as parameter in material
+*/
+
+
+/*===================================================================*/
+/*							Enforce engine API						 */
+/*===================================================================*/
+
+//placeholder
+class AnimEvent
+{
+	int type;
+	int slot;
+};
+
+class SoundEvent
+{
+	int type;
+	int handle;
+};
+
+
+typedef int[] vobject;
+
+class vobject
+{
+	proto native IEntitySource ToEntitySource();
+}
+
+#ifdef ENF_DONE
+
+//------------------------------------------
+// SOUND API
+//------------------------------------------
+//TODO:
+typedef int[] HSOUND;
+
+//flags
+//!Play once and invoke EntityEvent.SOUNDEND event
+//SFX_ONCE
+//!Music. Has separate volume control, can be replaced by custom music
+//SFX_MUSIC
+//!Ambient, not positional sound
+//SFX_AMBIENT
+//!Positional sound
+//SFX_3D
+//!Don't even start if not hearable. Valid only together with SFX_3D!
+//SFX_DISCARDABLE
+//!Sound is positional. XSoundSource::GetSoundOrientation is called. Valid only together with SFX_3D!
+//SFX_DIRECTIONAL
+////!Sound is moveable. XSoundSource::GetSoundVelocity is called. Valid only together with SFX_3D!
+//SFX_DOPPLER
+//!Position is not changing, XSoundSource::GetSoundPosition/GetSoundOrientation is called only once upon start! Valid only together with SFX_3D!
+//SFX_STATIC
+//!Don't test hearability. Valid only together with SFX_3D!
+//SFX_NOTEST
+
+//proto volatile HSOUND PlaySound(int soundScene, IEntity source, string sshader, int flags);
+proto volatile native void EndSound(HSOUND snd);
+
+//volume 0...1. Logaritmic scale
+proto native int SetSoundVolume(HSOUND sound, float volume)
+proto native int SetSoundFrequency(HSOUND sound, int freq)
+
+
+//returns 0, if soundid is not valid
+proto native int GetSoundLength(HSOUND sound)
+
+//returns -1, if soundid is not valid
+proto native int GetSoundPosition(HSOUND sound)
+
+//defaultne se pouziva EAX prostredi nadefinovane v mape, ale lze ho prebit touto fci.
+// Mohou se michat dve ruzna prostredi v pomeru danem hodnotou fade (fade==0 -> 100% env1, fade==1 -> 100% env2).
+//pokud chceme michat aktualni prostredi s nejakym jinym, lze pouzit zastupny nazev "$current".
+//Tim lze dosahnout nafadovani vlastniho prostredi, kdyz fci postupne volame napr. takto:
+//SetEAXEnvironment("$current", "Drugged", fade)
+//pricemz hodnota fade postupne narusta od nuly do jedne
+//proto native bool SetEAXEnvironment(string env1, string env2, float fade)
+#endif
+
+class PacketOutputAdapter
+{
+	proto native void WriteBool(bool value);			//size: 1 byte
+	proto native void WriteInt(int value);				//size: 4 bytes
+	proto native void WriteFloat(float value);		//size: 4 bytes
+	proto native void WriteString(string value);		//size: n bytes (string length)
+	proto native void WriteVector(vector value);		//size: 12 bytes
+	proto native void WriteMatrixAsQuaternionVector(vector mat[4]);	//size: 28 bytes
+	proto native void WriteIntAsByte(int value);		//write int in range <-128, 127>			size: 1 byte
+	proto native void WriteIntAsUByte(int value);	//write int in range <0, 255>				size: 1 byte
+	proto native void WriteIntAsHalf(int value);		//write int in range <-32768, 32768>	size: 2 bytes
+	proto native void WriteIntAsUHalf(int value);	//write int in range <0, 65535>			size: 2 bytes
+	proto native void WriteFloatAsByte(float value, float min, float max);	//					size: 1 byte
+	proto native void WriteFloatAsHalf(float value, float min, float max);	//					size: 2 bytes
+};
+
+class PacketInputAdapter
+{
+	proto native bool ReadBool();
+	proto native int ReadInt();
+	proto native float ReadFloat();
+	proto string ReadString();
+	proto native vector ReadVector();
+	proto void ReadMatrixAsQuaternionVector(vector mat[4]);
+	proto native int ReadIntAsByte();
+	proto native int ReadIntAsUByte();
+	proto native int ReadIntAsHalf();
+	proto native int ReadIntAsUHalf();
+	proto native float ReadFloatAsByte(float min, float max);
+	proto native float ReadFloatAsHalf(float min, float max);
+};
+
+/*!
+makes screenshot and stores it in to a DDS format file
+if the name begins with '$' the screenshot in stored in the fullpath according to the name parameter
+otherwise the screenshot is stored in "$profile:ScreenShotes/DATE TIME-NAME.dds" where DATE, TIME AND NAME are replaced by actual values
+\param name name of the screenshot
+*/
+proto native void MakeScreenshot(string name);
+
+/*!
+Returns actual fps (average in last 10 frames)
+*/
+proto native int GetFPS();
+
+//----------------------------------------------
+/** \name SkyDome API */
+//@{
+
+/*!
+load all sky presets from xml file
+\param presetFile	name of XML file with presets
+*/
+proto native int LoadSkyPresets(string presetsFile);
+
+/*!
+initialize sky with preset, must be called to set the global planets setting
+\param presetName	name of preset to be set (one of presets from file loaded using LoadSkyPresets)
+*/
+proto native int InitSky(string presetName);
+
+/*!
+set sky preset to day time and stormy parameter
+\param presetName	name of preset to be set (one of presets from file loaded using LoadSkyPresets)
+\param stormy		stormy parameter <0, 1>
+\param dayTime		day of time <0, 1>
+*/
+proto native int SetSkyPreset(string presetName, float stormy, float dayTime);
+
+/*!
+lerp two sky presets and set the result using day time
+\param presetName1	name of preset1 to be set (one of presets from file loaded using LoadSkyPresets)
+\param presetName2	name of preset2 to be set (one of presets from file loaded using LoadSkyPresets)
+\param dayTime		day of time <0, 1>
+\param stormy1		stormy parameter for preset1 <0, 1>
+\param stormy2		stormy parameter for preset2 <0, 1>
+\param lerpVal		lerp value between two presets
+*/
+proto native int LerpSkyPreset(string presetName1, string presetName2, float dayTime, float stormy1, float stormy2, float lerpVal);
+
+/*!
+lerp three sky presets using barycentric coordinates and set the result using day time
+\param presetName1	name of preset1 to be set (one of presets from file loaded using LoadSkyPresets)
+\param presetName2	name of preset2 to be set (one of presets from file loaded using LoadSkyPresets)
+\param presetName2	name of preset3 to be set (one of presets from file loaded using LoadSkyPresets)
+\param dayTime		day of time <0, 1>
+\param stormy1		stormy parameter for preset1 <0, 1>
+\param stormy2		stormy parameter for preset2 <0, 1>
+\param stormy3		stormy parameter for preset3 <0, 1>
+\param w1		weight for preset1
+\param w2		weight for preset2
+\param w3		weight for preset3
+*/
+proto native int LerpSkyPreset3(string presetName1, string presetName2, string presetName3, float dayTime, float stormy1, float stormy2, float stormy3, float w1, float w2, float w3);
+
+/*!
+user can set planets to its own positions on skydome using SetSkyPresetPlanet function,
+if disabled, the planets are positioned automatically using sky preset setting
+\param enabled 	enable/disable
+*/
+proto native void SetSkyUserPlanets(bool enabled);
+
+/*!
+set planet position
+\param index		index of planet, 0 = sun usually
+\param azimuthDeg	azimuth position in degrees
+\param zenithDeg	zenith position in degrees
+*/
+proto native bool SetSkyPlanet(int index, float azimuthDeg, float zenithDeg);
+
+/*!
+set planet size in degrees
+\param index		index of planet, 0 = sun usually
+\param angleDeg		angle size in degrees
+*/
+proto native bool SetSkyPlanetSize(int index, float angleDeg);
+
+/*!
+set UTC time for real time stars
+\param year
+\param month
+\param day
+\param hour
+\param minute
+\param sec
+\param offsetSec	to take into account time difference between Greenwich and local time (position dependency, summer/winter time)
+*/
+proto native void SetStarsObserverTime(int year, int month, int day, int hour, int minute, float sec, int offsetSec);
+
+/*!
+set observer position
+\param latitudeDeg	latitude in degrees
+\param longitudeDeg	longitude in degrees
+*/
+proto native void SetStarsObserverPosition(float latitudeDeg, float longitudeDeg);
+
+/*!
+update of stars
+\param update 	true = automatic stars update, false = update is on user by SetStarsRotMatrix
+*/
+proto native void  SetRealStarAutoUpdate(bool update);
+
+
+/*!
+night sky layer rotation matrix
+\param mat	rotation matrix
+*/
+proto native void SetNightLayerRotMatrix(vector mat[3]);
+
+/*!
+stars rotation matrix, is different from night rotation matrix
+because we don't know the time when night layers was captured
+\param mat	rotation matrix
+*/
+proto native void SetStarsRotMatrix(vector mat[3]);
+
+//@}
+
+//----------------------------------------------
+/** \name Materials API */
+//@{
+typedef int[] Material;
+
+class Material
+{
+	/*!
+	set parametr of material by string name
+	\param paramName	name of parameter
+	\param value		value
+	*/
+	proto bool SetParam(string propertyName, void value);
+
+	/*!
+	reset parametr of material to default value
+	\param paramName	name of parameter
+	*/
+	proto native void ResetParam(string propertyName);
+
+	/*!
+	set parametr index for faster access to material properties
+	\param paramName	name of parameter
+	\return parameter index
+	*/
+	proto native int GetParamIndex(string paramName);
+
+	/*!
+	set parametr of material by index
+	\param paramName	name of parameter
+	\param value		value
+	*/
+	proto void SetParamByIndex(int paramIndex, void value);
+};
+//@}
+
+int VectortoRGBA( vector vec, float h)
+{
+float x,y,z;
+int r,g,b,a,rgba;
+
+	x = vec[0];
+	y = vec[1];
+	z = vec[2];
+
+	x = x * 127.0 + 128.0;
+	y = y * 127.0 + 128.0;
+	z = z * 127.0 + 128.0;
+	h = h * 255.0;
+
+	a = (int)h << 24;
+	r = (int)x << 16;
+	g = (int)y << 8;
+	b = z;
+
+	return r | g | b | a;
+}
+
+
+//-----------------------------------------------------------------
+int ARGB(int a, int r, int g, int b)
+{
+	a = a << 24;
+	r = r << 16;
+	g = g << 8;
+	return a | r | g | b;
+}
+
+//-----------------------------------------------------------------
+//! Converts <0.0, 1.0> ARGB into color
+int ARGBF(float fa, float fr, float fg, float fb)
+{
+	return ARGB((float)(fa * 255.0), (float)(fr * 255.0), (float)(fg * 255.0), (float)(fb * 255.0));
+}
+
+//-----------------------------------------------------------------
+int AWHITE(int a)
+{
+	return a << 24 | 0xffffff;
+}
+
+//-----------------------------------------------------------------
+int LerpARGB(int c1, int c2)
+{
+	int cb1, cb2;
+	const int cmask = 0x00ff00ff;
+
+	cb1 = c1 >> 8 & cmask;
+	cb2 = c2 >> 8 & cmask;
+	cb1 = cb1 + cb2 >> 1;
+
+	c1 = c1 & cmask;
+	c2 = c2 & cmask;
+	c1 = c1 + c2 >> 1;
+
+	return cb1 << 8 | c1;
+}
+
+//-------------------------------------------------------------------------
+class Link<Class T>
+{
+	proto private native void Init(T init);
+	proto private native Object Get();	
+
+	void Release()
+	{
+		T obj = Get();
+		if(obj)
+			obj.Release();
+	}	 
+	void Link(T init)
+	{
+		Init(init);
+	}
+	
+	T Ptr()
+	{
+		return Get();
+	}
+
+	bool IsNull()
+	{
+		if(!Get())
+			return true;
+		
+		return false;
+	}
+};
+

+ 112 - 0
Scripts/1_core/proto/serializer.c

@@ -0,0 +1,112 @@
+//-----------------------------------------------------------------------------
+/**
+ \brief Serialization general interface. Serializer API works with:
+	- primitive types: int, float, string, bool, vector
+	- dynamic containers: array, set, map
+	- static arrays
+	- complex types: classes
+ \note Serializer provides deep serialization (it serialize class memebers and their members etc). To avoid serialization of certain class variable, use NonSerialized attribute.
+ \par usage:
+ @code
+	class MyData
+	{
+		int m_id;
+		autoptr map<string, float> m_values;
+	
+		[NonSerialized()]
+		string m_dbg; // I don't want to serialize this variable
+	}
+
+	void Serialize(Serializer s)
+	{
+		int statArray[4] = {6,9,2,3};
+		array<int> dynArray = {8,5,6,4};
+		autoptr MyData data = new MyData();
+	
+		data.m_id = 965;
+		data.m_values = map<string, float>;
+		data.m_values.Insert("value1", 5.98);
+		data.m_values.Insert("value2", 4.36);
+	
+		s.Write(10);
+		s.Write("Hello");
+		s.Write(statArray);
+		s.Write(dynArray);
+		s.Write(data);
+	}
+
+	void Deserialize(Serializer s)
+	{
+		int statArray[4];
+		array<int> dynArray;
+		MyData data;
+		int someInt;
+		string someString;	
+	
+		s.Read(someInt);
+		s.Read(someString);
+		s.Read(statArray);
+		s.Read(dynArray);
+		s.Read(data);
+	}
+ 
+ @endcode
+ */
+class Serializer: Managed
+{
+	proto bool Write(void value_out);
+	proto bool Read(void value_in);
+
+	proto native bool CanWrite();
+	proto native bool CanRead();
+	
+	protected void Serializer() {}
+	protected void ~Serializer() {}
+};
+
+/**
+ \brief Serializer API implementation for File IO. See Serializer for more info.
+ \n usage:
+ @code
+void TestSave()
+{
+	FileSerializer file = new FileSerializer();
+	string names[3] = {"alpha", "beta", "gama"};
+	
+	if (file.Open("test.save", FileMode.WRITE))
+	{
+		file.Write(10);
+		file.Write("lalala");
+		file.Write(name);
+		file.Close();
+	}
+}
+	
+void TestLoad()
+{
+	FileSerializer file = new FileSerializer();
+	int intVal;
+	string stringVal;
+	string names[3];
+		
+	if (file.Open("test.save", FileMode.READ))
+	{
+		file.Read(intVal);
+		file.Read(stringVal);
+		file.Read(names);
+		file.Close();
+	}
+}	
+ 
+ @endcode
+ */
+class FileSerializer: Serializer
+{
+	void FileSerializer() {}
+	void ~FileSerializer() {}
+	
+	proto native bool Open(string path, FileMode mode = FileMode.READ);
+	proto native bool IsOpen();
+	proto native void Close();
+}
+	

+ 12 - 0
Scripts/1_core/script.c

@@ -0,0 +1,12 @@
+//some example "reference" variables for use in material editor
+reference float g_testVariable1;
+reference float g_testVariable2;
+reference float g_testVariable3;
+
+class TestClass
+{
+	//some example "reference" variables for use in material editor
+	reference float testVar1;
+	reference float testVar2;
+	reference float testVar3;
+}

+ 151 - 0
Scripts/1_core/workbenchapi.c

@@ -0,0 +1,151 @@
+typedef int[] WBModuleDef;
+typedef int[] ScriptEditor;
+typedef int[] ResourceBrowser;
+typedef int[] WorldEditor;
+
+class Workbench
+{
+	static proto native WBModuleDef GetModule(string type);
+	static proto native bool OpenModule(string type);
+	static proto native bool CloseModule(string type);
+	static proto native void Dialog(string caption, string text);
+	static proto int ScriptDialog(string caption, string text, Class data);
+	static proto bool SearchResources(string filter, func callback);
+	static proto native int RunCmd(string command, bool wait = false);
+	static proto void GetCwd(out string currentDir);
+	static proto bool GetAbsolutePath(string relativePath, out string absPath);
+};
+
+class WBModuleDef
+{
+	proto native external bool SetOpenedResource(string filename);
+	proto native external int GetNumContainers();
+	proto native external BaseContainer GetContainer(int index = 0);
+	proto external bool GetCmdLine(string name, out string value);
+	proto native external bool Save();
+	proto native external bool Close();
+};
+
+class ScriptEditor: WBModuleDef
+{
+	proto external bool GetCurrentFile(out string filename);
+	proto native external int GetCurrentLine();
+};
+
+class ResourceBrowser: WBModuleDef
+{
+	proto external bool GetCurrentFile(out string filename);
+};
+
+class WorldEditor: WBModuleDef
+{
+	proto native external WorldEditorAPI GetAPI();
+};
+
+class WorldEditorAPI
+{
+	proto native bool BeginTerrainAction(string historyPointName = "", string historyPointIcon = "");
+	proto native void EndTerrainAction(string historyPointName = "");
+	proto native bool BeginEntityAction(string historyPointName = "", string historyPointIcon = "");	//begin of logical edit action
+	proto native bool EndEntityAction(string historyPointName = "");	//end of edit action
+	proto native bool IsDoingEditAction();	//true, if code stay betwen BeginEntityAction() and EndEntityAction()
+	proto native bool UndoOrRedoIsRestoring();		//true, if editor is restoring undo or redo state
+	proto native bool IsModifyingData();
+	proto native IEntity SourceToEntity(IEntitySource entSrc);
+	proto native IEntitySource EntityToSource(IEntity ent);
+	proto native IEntitySource FindEntityByName(string name);
+	
+	proto native external void SetEntitySelection(IEntity ent);
+	proto native external void AddToEntitySelection(IEntity ent);
+	proto native void ClearEntitySelection();
+	proto native void RemoveFromEntitySelection(IEntity ent);
+	proto native void SetPropertySelection(string id);
+	
+	proto native external bool ModifyEntityKey(IEntity ent, string key, string value);
+	proto native external bool ModifyEntityTemplateKey(IEntitySource tmpl, string key, string value);
+		
+	proto native external IEntity CreateEntity(string className, string name, int layerId, vector coords, vector angles);
+	proto native external IEntity CreateClonedEntity(IEntity ent, string name);
+	proto native external bool DeleteEntity(IEntity ent);
+	proto native bool DeleteEntities(out array<IEntity> ents);
+	proto native IEntity GetEntityUnderCursor();
+	
+	proto native external bool TraceWorldPos(int x, int y, int traceFlags, out vector traceStart, out vector traceEnd, out vector traceDir);
+
+	proto native int GetSelectedEntitiesCount();
+	proto native IEntity GetSelectedEntity(int n = 0);
+	
+	private void WorldEditorAPI() {}
+	private void ~WorldEditorAPI() {}	
+};
+
+class WorldEditorTool
+{
+	//! Filled by workbench
+	WorldEditorAPI m_API;
+	
+	void OnKeyPressEvent(int key) {}
+	void OnKeyReleaseEvent(int key) {}
+	void OnEnterEvent() {}
+	void OnLeaveEvent() {}
+	void OnMouseMoveEvent(float x, float y) {}
+	void OnMouseDoubleClickEvent(float x, float y) {}
+	void OnMousePressEvent(float x, float y) {}
+	void OnMouseReleaseEvent(float x, float y) {}
+	void OnWheelEvent(int delta) {}
+	
+	private void WorldEditorTool() {}
+	private void ~WorldEditorTool() {}
+};
+
+class WorkbenchPlugin
+{
+	void Run() {}
+	void RunCommandline() {}
+	void Configure() {}
+};
+
+class ButtonAttribute
+{
+	string m_Label;
+	bool m_Focused;
+	
+	void ButtonAttribute(string label = "ScriptButton", bool focused = false)
+	{
+		m_Label = label;
+		m_Focused = focused;
+	}
+};
+
+/*!
+Attribute for Workbench plugin definition:
+	name - ui name in Script Tools menu
+	description - tooltip
+	shortcut - shortcut in simple text form e.g. "ctrl+g"
+	icon - relative path to icon file (32x32 png)
+	wbModules - list of strings representing Workbench modules where this tool should be avalaible (e.g. {"ResourceManager", "ScriptEditor"}). Leave null or empty array for any module.
+*/
+class WorkbenchPluginAttribute
+{
+	string m_Name;
+	string m_Icon;
+	string m_Shortcut;
+	string m_Description;
+	ref array<string> m_WBModules;
+		
+	void WorkbenchPluginAttribute(string name, string description = "", string shortcut = "", string icon = "", array<string> wbModules = null)
+	{
+		m_Name = name;
+		m_Icon = icon;
+		m_Shortcut = shortcut;
+		m_Description = description;
+		m_WBModules = wbModules;
+	}
+};
+
+/*!
+Attribute for Workbench tool definition
+*/
+class WorkbenchToolAttribute: WorkbenchPluginAttribute
+{
+}

+ 276 - 0
Scripts/2_gamelib/components/gamelibcomponents.c

@@ -0,0 +1,276 @@
+#ifdef COMPONENT_SYSTEM
+//Generic components from GameLib (script side of c++ classes)
+
+typedef int[] IEntityComponentSource;
+class IEntityComponentSource: BaseContainer
+{
+};
+
+//!Entity touch event types
+enum TouchEvent
+{
+	ON_ENTER,
+	ON_STAY,
+	ON_EXIT
+};
+
+//!Builtin component types
+//TypeID MeshObjectTypeID;
+//TypeID HierarchyTypeID;
+//TypeID RigidBodyTypeID;
+//TypeID SphereGeometryTypeID;
+//TypeID BoxGeometryTypeID;
+
+
+class GenericComponent : Managed
+{
+	/**
+	* Gets current eventmask of the component.
+	* \return Returns bitmask of events the component accepts
+	*/
+	proto native int GetEventMask();
+	
+	/**
+	* Sets eventmask. Component accepts only events which has set bits in eventmask.
+	* Bits are or'ed with existing bitmask. See enf::EntityEvents.
+	* When this method is called in the constructor of the component, it will not properly set the eventmask to the parent entity. You may consider OnComponentInsert event.
+	* \param mask Mask of those bits, which will be set.
+	* \return Returns bitmask of events the component accepts (result of mask|GetEventMask())
+	*/
+	proto native int SetEventMask(IEntity owner, int mask);
+	
+	/**
+	* Clears bitmask. Component accepts only events which has set bits in eventmask.
+	* Only bits set in the mask are cleared. See enf::EntityEvents
+	* \param mask Mask of those bits, which will be cleared.
+	* \return returns these bits that were set before and now are cleared.
+	*/
+	proto native int ClearEventMask(IEntity owner, int mask);
+
+	/**
+	* Activate component and calls EOnActivate().
+	*/
+	proto native void Activate(IEntity owner);
+
+	/**
+	* Deactivate component and calls EOnDectivate().
+	*/
+	proto native void Deactivate(IEntity owner);
+
+	/**
+	* Returns activity state.
+	* \return Returns true, if component is active.
+	*/
+	proto native bool IsActive();
+	
+	//! Constructor
+	protected void GenericComponent(IEntityComponentSource src, IEntity ent);	
+}
+
+class GenericComponentClass
+{
+	bool DependsOn(typename otherClass, TypeID otherTypeID) {}
+}
+
+/**
+* Parent class for all components created in script.
+* Every ScriptComponent is being created in Entity's constructor and may receive following events
+* 1. OnComponentInsert is being called when component is created. This is last event Workbench sends in World Editor edit mode.
+* 2. EOnInit is being called after all components have been inserted and if the component registered event mask EV_INIT
+* 3. EOnActivate is being called if the entity was flagged as TFL_ACTIVE and if the component is active. The component is active by default.
+* 4. EOnXXXs are being called base on event mask component registered
+* 5. EOnDeactivate is being called when Deactivate is called or when the component is being to be removed. Component must be active to be deactivated.
+* 6. OnComponentRemove is being called after a component is removed.
+* 7. EOnDelete is being called after entity is going to be destroyed.
+*/
+class ScriptComponent : GenericComponent
+{
+	/*
+	Event when owner entity is touched
+	\param owner
+	Touched entity
+	\param extra
+	Bitmask of touch types TODO
+	*/
+	protected void EOnTouch(IEntity owner, int extra);
+
+	/*!
+	Event after component is initialized. At this point all entity's components have recieved OnComponentInsert.
+	\param owner
+	\param extra
+	Number of entity
+	*/
+	protected void EOnInit(IEntity owner, int extra);
+
+	/*!
+	Extra event of various functional extensions. ATM it's used
+	by Trigger when some insider is leaving
+	\param owner
+	owner actor of event
+	\param extra
+	Extra value of event
+	*/
+	protected void EOnExtra(IEntity owner, int extra);
+
+	/*!
+	Event when we are out of visibility
+	\param owner
+	\param extra
+	Frame number
+	*/
+	protected void EOnNotVisible(IEntity owner, int extra);
+
+	/*!
+	Event when we are visible
+	\param owner
+	\param extra
+	Frame number
+	*/
+	protected void EOnVisible(IEntity owner, int extra);
+
+	/*!
+	Event every frame
+	\param owner
+	\param timeSlice
+	Time passed since last frame
+	*/
+	protected void EOnFrame(IEntity owner, float timeSlice);
+
+	/*!
+	Even after physics update
+	\param owner
+	\param extra
+	Frame number
+	*/
+	protected void EOnPostFrame(IEntity owner, int extra);
+
+	/*!
+	Event from animation system
+	\param owner
+	\param extra
+	extra data
+	*/
+	protected void EOnAnimEvent(IEntity owner, AnimEvent extra);
+
+	/*!
+	Event from sound system
+	\param owner
+	\param extra
+	extra data
+	*/
+	protected void EOnSoundEvent(IEntity owner, SoundEvent extra);
+
+	/*!
+	Event after simulated by physics engine (once per frame)
+	\param owner
+	\param timeslice
+	Time slice of simulation step
+	*/
+	protected void EOnPostSimulate(IEntity owner, float timeslice);
+
+	/*!
+	Event before simulated by physics engine (called from sub-iterations!
+	\param owner
+	\param timeslice
+	Time slice of simulation step
+	*/
+	protected void EOnSimulate(IEntity owner, float timeslice);
+
+	/*!
+	Event when joint attached to RigidBody of this entity is broken
+	\param owner
+	owner Entity attached to the joint
+	\param extra
+	Not used ATM
+	*/
+	protected void EOnJointBreak(IEntity owner, int extra);
+	/*!
+	Event when physics engine has moved with this Entity
+	\param owner
+	World Entity
+	\param extra
+	Not used ATM
+	*/
+	protected void EOnPhysicsMove(IEntity owner, int extra);
+
+	/*!
+	Event when physics engine registered contact with owner RigidBody
+	\param owner
+	\param contact
+	Structure describing the contact
+	*/
+	protected void EOnContact(IEntity owner, Contact extra);
+
+	/**
+    * Event when component is activated.
+    */
+    protected void EOnActivate(IEntity owner);
+
+    /**
+    * Event when component is deactivated.
+    */
+    protected void EOnDeactivate(IEntity owner);
+
+	/*!
+	Event when a component is created and added to Entity.
+	\param owner Entity into which component is added
+	\param other Component which is being added into Entity
+	*/
+	protected void OnComponentInsert(IEntity owner, ScriptComponent other);
+
+	/*!
+	Event when a component is being removed from Entity.
+	\param owner Entity from which component is being removed
+	\param other Component which is being removed from the Entity
+	*/
+	protected void OnComponentRemove(IEntity owner, ScriptComponent other);
+
+	/*!
+	Called when Entity is being to be destroyed (deleted) or component to be deleted (see Game::DeleteScriptComponent).
+	\param owner Entity which owns the component
+	*/
+	protected void OnDelete(IEntity owner);
+}
+
+typedef int[] SoundHandle;
+
+class SignalInput
+{
+	string m_name;
+	float m_value;
+	
+	void SignalInput()
+	{
+		m_value = 0;
+	}
+};	
+
+class BaseSoundComponent : GenericComponent
+{
+	/* Get list of 'events'. */
+	proto native int GetEventNames(out array<string> events);
+	/* Get list of 'signals. '*/
+	proto native int GetSignalNames(out array<string> signals);
+	/* Convert signal name to index. */
+	proto native int GetSignalIndex(string name);
+	/* Set signal value by 'name'. */
+	proto native void SetSignalValueName(string signal, float value);
+	/* Set signal value by 'index'. */
+	proto native void SetSignalValue(int index, float value);
+	/* Play 'event'. */
+	proto native SoundHandle Play(string name);
+	/* Play sounds based on triggers. */
+	proto native SoundHandle Update();
+	/* Terminate 'sound'. */
+	proto native void Terminate(SoundHandle handle);
+	/* Check if 'sound' is played. */
+	proto native bool IsPlayed(SoundHandle handle);
+	/* Validate handle. */
+	proto native bool IsHandleValid(SoundHandle handle);
+	/* Set sound position. */
+	proto native void SetTransform(vector[] transf);
+	/* Enable debug mode. */
+	proto native void SetDebug(bool value);
+};
+
+#endif

+ 141 - 0
Scripts/2_gamelib/entities/gamelibentities.c

@@ -0,0 +1,141 @@
+//Generic entities from GameLib (script side of c++ classes)
+
+#ifdef COMPONENT_SYSTEM
+class GenericEntity extends IEntity
+{
+	//native method implemented on c++ side
+	proto native void Show(bool show);
+	
+	/*!
+	Finds first occurance of the coresponding component.
+	\param typeName type of the component
+	*/
+	proto native GenericComponent FindComponent(typename typeName);
+	
+	/*!
+	inserts instance of the script component to the entity.
+	Calls OnComponentInsert on all entity's components to inform that this new component was inserted. The new instance have to FindScriptComponents in order to work with them.
+	Calls EOnInit on the component if component sets EV_INIT mask.
+	Calls EOnActivate on the component if the component is active (default)
+	\param component instance
+	*/
+	proto native void InsertComponent(GenericComponent component);
+	
+	/*!
+	Removes component from entity. Doesn't delete the entity.
+	Calls EOnDeactivate on the component.
+	Calls OnComponentRemove on all entity's components to inform that this new component was removed.
+	\param component instance
+	*/
+	proto native void RemoveComponent(GenericComponent component);
+	
+	/*!
+	Removes and deletes component from entity.
+	Calls EOnDeactivate on the component.
+	Calls OnComponentRemove on all entity's components to inform that this new component was removed.
+	Calls OnDelete on the component.
+	\param component instance
+	*/
+	proto native void DeleteComponent(GenericComponent component);
+
+#ifdef WORKBENCH
+	/*!
+	Called after updating world in Workbench. The entity must be selected.
+	*/
+	void _WB_AfterWorldUpdate(float timeSlice) {};
+#endif
+}
+
+class GenericWorldEntity extends GenericEntity
+{
+}
+
+class GenericTerrainEntity extends GenericEntity
+{
+}
+
+class LightEntity extends GenericEntity
+{
+	/*!
+	Sets diffuse part of light.
+	\param color Color of light
+	*/
+	proto native external void SetDiffuseColor(int color);
+	proto native external int GetDiffuseColor();
+	
+	proto native external void SetRadius(float radius);
+	proto native external float GetRadius();
+	
+	/*!
+	Sets cone of light. It's meaningful for LT_SPOT only!
+	\param angle
+	*/
+	proto native external void SetConeAngle(float angle);
+	/*!
+	Gets cone of light. It's meaningful for LT_SPOT only!
+	\return Cone of light
+	*/
+	proto native external float GetConeAngle();
+	
+	proto native external void SetCastShadow(bool enable);
+	proto native external bool IsCastShadow(bool enable);
+}
+
+class GenericWorldLightEntity extends GenericEntity
+{
+}
+
+class GenericWorldFogEntity extends GenericEntity
+{
+}
+
+class BasicEntity extends GenericEntity
+{
+}
+
+class WorldEntityClass
+{
+}
+
+class WorldEntity extends GenericWorldEntity
+{
+}
+
+class ModelEntity extends BasicEntity
+{
+}
+
+enum CharacterMovement
+{
+	MOVEMENTTYPE_IDLE,
+	MOVEMENTTYPE_WALK,
+	MOVEMENTTYPE_RUN,
+	MOVEMENTTYPE_SPRINT
+};
+
+enum CharacterStance
+{
+	STANCE_ERECT,
+	STANCE_CROUCH,
+	STANCE_PRONE,
+	STANCE_ERECT_RAISED,
+	STANCE_CROUCH_RAISED,
+	STANCE_PRONE_RAISED
+};
+
+class CharacterEntity extends BasicEntity
+{
+	proto native void Teleport(vector transform[4]);
+	proto native CharacterMovement GetCurrentMovement();
+	proto native CharacterStance GetCurrentStance();
+}
+
+class BasicCamera extends BasicEntity
+{
+}
+
+class VRHandEntity extends GenericEntity
+{
+}
+
+#endif

+ 79 - 0
Scripts/2_gamelib/entities/rendertarget.c

@@ -0,0 +1,79 @@
+#ifdef GAME_TEMPLATE
+
+[EditorAttribute("box", "GameLib/Scripted", "Render target", "-0.25 -0.25 -0.25", "0.25 0.25 0.25", "255 0 0 255")]
+class RenderTargetClass
+{
+
+}
+
+RenderTargetClass RenderTargetSource;
+
+class RenderTarget: GenericEntity
+{
+	[Attribute("0", "slider", "Camera index", "0 31 1")]
+	int CameraIndex;
+	[Attribute("0", "editbox", "Position X <0, 1>")]
+	float X;
+	[Attribute("0", "editbox", "Position Y <0, 1>")]
+	float Y;
+	[Attribute("1", "editbox", "Render target width <0, 1>")]
+	float Width;
+	[Attribute("1", "editbox", "Render target height <0, 1>")]
+	float Height;
+	[Attribute("-1", "editbox", "Sort index (the lesser the more important)")]
+	int Sort;
+	[Attribute("0", "combobox", "Autoinit", "", { ParamEnum("No", "0"), ParamEnum("Yes", "1") } )]
+	int AutoInit;
+	[Attribute("0", "combobox", "Forcing creation of render target for camera #0 in Workbench", "", { ParamEnum("No", "0"), ParamEnum("Yes", "1") } )]
+	bool ForceCreation;
+	bool m_Show = true; // when autoinit, wait with showing the render target after all entities are created (EOnInit)
+	ref RenderTargetWidget m_RenderWidget;
+	
+	void RenderTarget(IEntitySource src, IEntity parent)
+	{
+		SetFlags(EntityFlags.ACTIVE, false);
+
+		if (AutoInit)
+		{
+			m_Show = false;
+			SetEventMask(EntityEvent.INIT);
+			Init();
+		}
+	}
+
+	void ~RenderTarget()
+	{
+		delete m_RenderWidget;
+	}
+	
+	void Init()
+	{
+		#ifdef WORKBENCH // Workbench is using its own renderer for main camera, it is not using render target widget.
+			if (!ForceCreation && CameraIndex == 0)
+				return;
+		#endif
+
+		int screenW, screenH;
+		GetScreenSize(screenW, screenH);
+
+		int posX = (float)(screenW * X);
+		int posY = (float)(screenH * Y);
+		int widthPix = (float)(screenW * Width);
+		int heightPix = (float)(screenH * Height);
+		if (Class.CastTo(m_RenderWidget, GetGame().GetWorkspace().CreateWidget(RenderTargetWidgetTypeID, posX, posY, widthPix, heightPix, WidgetFlags.VISIBLE | WidgetFlags.HEXACTSIZE | WidgetFlags.VEXACTSIZE | WidgetFlags.HEXACTPOS | WidgetFlags.VEXACTPOS, 0xffffffff, Sort)))
+		{	
+			m_RenderWidget.Show(m_Show);	
+			SetWidgetWorld(m_RenderWidget, GetGame().GetWorldEntity(), CameraIndex);
+		}
+	}
+	override void EOnInit(IEntity other, int extra) //!EntityEvent.INIT
+	{
+		if (m_RenderWidget)
+		{
+			m_Show = true;
+			m_RenderWidget.Show(m_Show);
+		}
+	}
+}
+
+#endif

+ 172 - 0
Scripts/2_gamelib/entities/scriptcamera.c

@@ -0,0 +1,172 @@
+#ifdef GAME_TEMPLATE
+
+[EditorAttribute("box", "GameLib/Scripted", "Script camera", "-0.25 -0.25 -0.25", "0.25 0.25 0.25", "255 0 0 255")]
+class ScriptCameraClass
+{
+
+}
+
+ScriptCameraClass ScriptCameraSource;
+
+class ScriptCamera: GenericEntity
+{
+	[Attribute("60", "slider", "Field of view", "0 180 1")]
+	float FOV;
+	[Attribute("1", "editbox", "Near plane clip")]
+	float NearPlane;
+	[Attribute("4000", "editbox", "Far plane clip")]
+	float FarPlane;
+	
+	[Attribute("1", "combobox", "Projection type", "", ParamEnumArray.FromEnum(CameraType) )]
+	int Type;
+	[Attribute("5", "slider", "Camera speed", "0 20 1")]
+	float Speed;
+	[Attribute("1", "combobox", "Free Fly", "", ParamEnumArray.FromEnum(EBool) )]
+	bool FreeFly;
+	[Attribute("0", "combobox", "Invert vertical", "", ParamEnumArray.FromEnum(EBool) )]
+	bool Inverted;
+	[Attribute("0", "slider", "Camera index", "0 31 1")]
+	int Index;
+	float m_MouseSensitivity = 0.001; // should be somewhere else.
+	float m_GamepadSensitivity = 0.2; // should be somewhere else.
+	int m_GamepadFreeFly;
+
+	// debug variables
+	int m_DbgListSelection = 0;
+	ref array<string> m_DbgOptions = {"Perspective", "Orthographic"};
+
+	void ScriptCamera(IEntitySource src, IEntity parent)
+	{
+		SetFlags(EntityFlags.ACTIVE, false);
+		SetEventMask(EntityEvent.FRAME);
+
+		SetCameraVerticalFOV(Index, FOV);
+		SetCameraFarPlane(Index, FarPlane);
+		SetCameraNearPlane(Index, NearPlane);
+		SetCameraType(Index, Type);
+		m_DbgListSelection = Type - 1;
+		SetCamera(Index, GetOrigin(), GetYawPitchRoll());
+
+		vector camMat[4];
+		GetTransform(camMat);
+		SetCameraEx(Index, camMat);
+		m_GamepadFreeFly = FreeFly;
+	}
+
+	override protected void EOnFrame(IEntity other, float timeSlice) //EntityEvent.FRAME
+	{
+		GetGame().GetInputManager().ActivateContext("ScriptCameraContext");
+		
+		if (GetGame().GetInputManager().GetActionTriggered("CamFreeFly"))
+		{
+			FreeFly = !FreeFly;
+		}
+		
+		if (FreeFly)
+		{
+			FreeFly(timeSlice);
+		}
+		else
+		{
+			vector camMat[4]; // matrix can be set outside the class
+			GetTransform(camMat);
+			SetCameraEx(Index, camMat);
+		}
+		
+		if (GameSettings.Debug)
+		{
+			DebugInfo();
+		}
+	}
+
+	protected void FreeFly(float timeSlice)
+	{
+		vector camPosition = GetOrigin();
+		vector angles = GetYawPitchRoll();
+		vector camMat[4];
+		GetTransform(camMat);	
+		InputManager imanager = GetGame().GetInputManager();
+		imanager.ActivateContext("ScriptCameraFreeFlyContext");
+		
+		// get input
+		float turnX 		= imanager.LocalValue("CamTurnRight") * 20.0 * timeSlice;
+		float turnY 		= imanager.LocalValue("CamTurnUp") * 20.0 * timeSlice;
+		float turnZ			= imanager.LocalValue("CamRotate") * 20.0 * timeSlice;
+		float moveForward	= imanager.LocalValue("CamForward");
+		float moveRight 	= imanager.LocalValue("CamRight");
+		float moveAscend 	= imanager.LocalValue("CamAscend");
+		float speedDelta   	= imanager.LocalValue("CamSpeedDelta") * timeSlice;
+		bool speedBoostHigh   	= imanager.GetActionTriggered("CamSpeedBoostHigh");
+		bool speedBoostLow  = imanager.GetActionTriggered("CamSpeedBoostLow");
+
+		Speed = Math.Clamp(Speed + speedDelta * Speed * 0.25, 0.1, 1000.0);
+		
+		float finalSpeed = Speed;
+		if (speedBoostLow)
+			finalSpeed *= 25;
+		else if (speedBoostHigh)
+			finalSpeed *= 5;
+
+		// rotation
+		angles[0] = turnX + angles[0];
+		if (Inverted)
+			angles[1] = turnY + angles[1];
+		else
+			angles[1] = -turnY + angles[1];
+
+		angles[2] = turnZ + angles[2];
+		
+		// movement
+		vector move = vector.Zero;
+		vector forward = camMat[2];
+		vector up = camMat[1];
+		vector side = camMat[0];
+		
+		move += forward * moveForward;
+		move += side    * moveRight;
+		move += up      * moveAscend;
+		
+		// ------------		
+		camPosition = (move * timeSlice * finalSpeed) + camPosition;
+		
+		Math3D.YawPitchRollMatrix(angles, camMat);
+		camMat[3] = camPosition;
+		SetTransform(camMat);
+		SetCameraEx(Index, camMat);
+	}
+
+	protected void DebugInfo()
+	{
+		InputManager imanager = GetGame().GetInputManager();
+		DbgUI.Begin(String("Camera #" + Index.ToString()), 0, Index * 300);
+
+		DbgUI.Text(String("Position : " + GetOrigin().ToString()));
+		DbgUI.Text(String("Orientation (Y, P, R): " + GetYawPitchRoll().ToString()));
+		DbgUI.Text(String("Speed : " + Speed.ToString()));
+		DbgUI.Text(String("Mouse sensitivity : " + (2000 - (1 / m_MouseSensitivity)).ToString()));
+		DbgUI.Check("Select Free fly", FreeFly);
+		DbgUI.List("Camera type", m_DbgListSelection, m_DbgOptions);
+		if (m_DbgListSelection + 1 != Type)
+		{
+			Type = m_DbgListSelection + 1;
+			SetCameraType(Index, Type);
+		}
+		
+		float sensitivity = 2000 - (1 / m_MouseSensitivity);
+		DbgUI.SliderFloat("Mouse sensitivity", sensitivity, 1, 1999);
+		m_MouseSensitivity = 1 / (2000 - sensitivity);
+		
+		DbgUI.Text("CamTurnRight: " + imanager.LocalValue("CamTurnRight"));
+		DbgUI.Text("CamTurnUp: " + imanager.LocalValue("CamTurnUp"));
+		DbgUI.Text("CamSpeedDelta: " + imanager.LocalValue("CamSpeedDelta"));
+		DbgUI.Text("CamForward: " + imanager.LocalValue("CamForward"));
+		DbgUI.Text("CamRight: " +imanager.LocalValue("CamRight"));
+		DbgUI.Text("CamAscend: " + imanager.LocalValue("CamAscend"));
+		DbgUI.Text("CamSpeedBoostHigh: " + imanager.GetActionTriggered("CamSpeedBoostHigh"));
+		DbgUI.Text("CamSpeedBoostLow:" + imanager.GetActionTriggered("CamSpeedBoostLow"));		
+		
+		DbgUI.End();
+	}
+}
+
+#endif

+ 40 - 0
Scripts/2_gamelib/entities/scriptlight.c

@@ -0,0 +1,40 @@
+#ifdef GAME_TEMPLATE
+
+[EditorAttribute("box", "GameLib/Scripted", "Script light", "-0.25 -0.25 -0.25", "0.25 0.25 0.25", "255 0 0 255")]
+class ScriptLightClass
+{
+
+}
+
+ScriptLightClass ScriptLightSource;
+
+class ScriptLight: GenericEntity
+{
+	[Attribute("1", "flags", "Flags", "", { ParamEnum("Point", "1"), ParamEnum("Spot", "2"), ParamEnum("Directional", "4") } )]
+	int Flags;
+	[Attribute("1", "combobox", "Type", "", { ParamEnum("Point", "1"), ParamEnum("Spot", "2"), ParamEnum("Directional", "3") } )]
+	int Type;
+	[Attribute("1", "editbox", "Radius", "", NULL )]
+	float Radius;
+	[Attribute("1 1 1", "color", "Color", "", NULL )]
+	vector Color;
+	[Attribute("1", "editbox", "Intensity", "", NULL )]
+	float Intensity;
+	HLIGHT m_light;
+	
+	void ScriptLight(IEntitySource src, IEntity parent)
+	{
+		//SetFlags(this, EntityFlags.ACTIVE | EntityFlags.SOLID | EntityFlags.VISIBLE);
+		m_light = AddLight(this, LightType.POINT, LightFlags.DYNAMIC|LightFlags.CASTSHADOW, Radius, Color * Intensity);
+	}
+
+	void ~ScriptLight()
+	{
+		if(m_light)
+		{
+			RemoveLight(m_light);
+		}
+	}
+}
+
+#endif

+ 62 - 0
Scripts/2_gamelib/entities/scriptmodel.c

@@ -0,0 +1,62 @@
+#ifdef GAME_TEMPLATE
+
+[EditorAttribute("box", "GameLib/Scripted", "Script model", "-0.25 -0.25 -0.25", "0.25 0.25 0.25", "255 0 0 255", "0 0 0 0", true, true, true)]
+class ScriptModelClass
+{
+
+}
+
+ScriptModelClass ScriptModelSource;
+
+class ScriptModel: GenericEntity
+{
+	[Attribute("", "resourceNamePicker", "Model", "xob")]
+	string Model;
+	[Attribute("1", "combobox", "Physics", "", { ParamEnum("None", "2"), ParamEnum("Static", "1"), ParamEnum("Dynamic", "0") } )]
+	int Type;
+
+	void ScriptModel(IEntitySource src, IEntity parent)
+	{
+		if (Model== "")
+			return;
+
+		SetFlags(EntityFlags.ACTIVE | EntityFlags.SOLID | EntityFlags.VISIBLE, false);
+		
+		vobject vobj = GetObject(Model);
+		SetObject(vobj, "");
+		ReleaseObject(vobj, false);
+
+		if (Type == 1)
+		{
+			dBodyCreateStatic(this, 0xffffffff); // todo - defines for layer mask			
+		}
+		else if (Type == 0)
+		{
+			if(!dBodyCreateDynamic(this, 1.0, 0xffffffff))
+			{
+				//create implicit box
+				vector mins, maxs;
+				GetBounds(mins, maxs);
+				vector center = (mins + maxs) * 0.5;
+				vector size = maxs - mins;
+								
+				PhysicsGeomDef geoms[] = {PhysicsGeomDef("", dGeomCreateBox(size), "material/default", 0xffffffff)};
+				dBodyCreateDynamicEx(this, center, 1, geoms);
+			}
+			if(dBodyIsSet(this))
+			{
+				dBodySetMass(this, 1.0);
+				dBodyActive(this, ActiveState.ACTIVE);
+				dBodyDynamic(this, true);
+			}
+		}
+	}
+
+	void ~ScriptModel()
+	{
+		if(dBodyIsSet(this))
+			dBodyDestroy(this);
+	}
+}
+
+#endif

+ 97 - 0
Scripts/2_gamelib/entities/worldsmenu.c

@@ -0,0 +1,97 @@
+#ifdef GAME_TEMPLATE
+
+[EditorAttribute("box", "GameLib/Scripted", "Worlds menu", "-0.25 -0.25 -0.25", "0.25 0.25 0.25", "255 0 0 255")]
+class WorldsMenuClass
+{
+
+}
+
+WorldsMenuClass WorldsMenuSource;
+
+class WorldsMenu: GenericEntity
+{
+	int m_DbgListSelection = 0;
+	int m_WorldsCount = 0;
+	string DEFAULT_WORLD = "worlds/default.ent";
+	ref array<string> m_DbgOptions = {};
+	ref ImageWidget m_MouseWidget;
+	
+	void WorldsMenu(IEntitySource src, IEntity parent)
+	{
+		SetFlags(EntityFlags.ACTIVE, false);
+		SetEventMask(EntityEvent.POSTFRAME);
+		
+		Class.CastTo(m_MouseWidget, GetGame().GetWorkspace().CreateWidgets("gui/layouts/mouse.layout"));
+		m_MouseWidget.SetSort(1024);
+		SetCursorWidget(m_MouseWidget);
+		
+		LoadWorlds();
+	}
+	
+	void ~WorldsMenu()
+	{
+		delete m_MouseWidget;
+	}
+
+	array<string> GetWorldList()
+	{
+		return m_DbgOptions;
+	}
+
+	override void EOnPostFrame(IEntity other, int extra) //EntityEvent.POSTFRAME
+	{
+		InputManager im = GetGame().GetInputManager();
+		im.ActivateContext("MenuContext");
+		bool menuSelect = im.GetActionTriggered("MenuSelect");
+		bool menuBack = im.GetActionTriggered("MenuBack");
+		
+		DbgUI.Begin("Load world", 400, 100);
+
+		DbgUI.Text("Select world to load from worlds directory");
+
+		if (m_DbgOptions.Count() > 0)
+		{
+			DbgUI.List("Worlds", m_DbgListSelection, m_DbgOptions);
+			if (DbgUI.Button("Start") || menuSelect)
+			{
+				string worldToLoad = m_DbgOptions.Get(m_DbgListSelection);
+				GetGame().SetWorldFile(worldToLoad, true);
+			}
+		}
+		if (DbgUI.Button("Exit") || menuBack)
+		{
+			GetGame().RequestClose();
+		}		
+		DbgUI.End();
+	}
+
+	void LoadWorlds()
+	{
+		string fileName;
+		FileAttr fileAttr;
+		FindFileHandle worlds = FindFile("worlds/*.ent", fileName, fileAttr, 0);
+		
+		if (!worlds)
+			return;
+
+		InsertWorldToList(fileName);
+
+		while(FindNextFile(worlds, fileName, fileAttr))
+		{
+			InsertWorldToList(fileName);
+		}
+
+		CloseFindFile(worlds);
+
+		m_WorldsCount = m_DbgOptions.Count();
+	}
+
+	void InsertWorldToList(string fileName)
+	{
+		string path = String("worlds/" + fileName);
+		if (path != DEFAULT_WORLD)
+			m_DbgOptions.Insert(String(path));
+	}
+}
+
+#endif

+ 158 - 0
Scripts/2_gamelib/gamelib.c

@@ -0,0 +1,158 @@
+#ifdef GAME_TEMPLATE
+Game g_Game;
+
+Game GetGame()
+{
+	return g_Game;
+}
+
+class Game
+{
+	ScriptModule GameScript;
+	
+	ScriptModule GetScriptModule()
+	{
+		return GameScript;
+	}
+	
+	void SetDebug(bool isDebug) {}
+	//! 
+	/**
+  	\brief Called when some system event occur.
+  	@param eventTypeId event type.
+	@param params Param object, cast to specific param class to get parameters for particular event.
+	*/
+	void OnEvent(EventType eventTypeId, Param params)
+	{
+		Print("OnEvent");
+	}
+
+	/**
+	\brief Called after full initialization of Game instance
+	*/
+	void OnAfterInit()
+	{
+		Print("OnAfterInit");
+	}
+	
+	/**
+  	\brief Called on World update
+	@param timeslice time elapsed from last call
+	*/
+	void OnUpdate(float timeslice) 
+	{
+
+	}
+
+	/**
+  	\brief Sets world file to be loaded. Returns false if file doesn't exist.
+	@param path Path to the ent file
+	@param reload Force reload the world
+	*/
+	proto native bool SetWorldFile(string path, bool reload);
+
+	/**
+  	\brief Returns path of world file loaded
+	*/
+	proto native owned string GetWorldFile();
+
+	/**
+  	\brief Event which is called right before game starts (all entities are created and initialized). Returns true if the game can start.
+	*/
+	bool OnGameStart()
+	{
+		return true;
+	}
+
+	/**
+  	\brief Event which is called right before game end.
+	*/
+	void OnGameEnd()
+	{
+	}
+
+	/**
+  	\brief Creates loading screen
+	*/
+	void ShowLoadingAnim()
+	{
+	}
+
+	/**
+  	\brief Hides loading screen
+	*/
+	void HideLoadingAnim()
+	{
+	}
+
+	/**
+  	\brief Used for updating the loading screen
+	@param timeslice
+	@param progress loading progress between 0 and 1
+	*/
+	void UpdateLoadingAnim(float timeslice, float progress)
+	{
+	}
+
+	/**
+	\brief Safely instantiate the entity and calls EOnInit if the entity sets event mask EntityEvent.INIT.
+	@param typename Name of entity's type to instantiate.
+	@return instantiated entity
+	*/
+	proto native IEntity SpawnEntity(typename typeName);
+
+	/**
+	\brief Safely instantiate the entity from template (with all components) and calls EOnInit if the entity sets event mask EntityEvent.INIT.
+	@param templateResource Template resource of the entity to instantiate.
+	@return instantiated entity
+	*/
+	proto native IEntity SpawnEntityTemplate(vobject templateResource);
+
+	/**
+	\brief Safely instantiate the component from template, insert it to entity and calls EOnInit if the component sets event mask EntityEvent.INIT.
+	@param owner Entity which will own the component
+	@param templateResource Template resource of the component to instantiate.
+	@return instantiated component
+	*/
+	proto native GenericComponent SpawnComponentTemplate(IEntity owner, vobject templateResource);
+
+	proto native IEntity FindEntity(string name);
+
+	proto native WorkspaceWidget GetWorkspace();
+
+	/**
+	\brief Setting request flag for engine to exit the game
+	*/
+	proto native void RequestClose();
+
+	/**
+	\brief Setting request flag for the engine to reinitialize the game
+	* Doesn't do anything in Workbench
+	*/
+	proto native void RequestReload();
+
+	/**
+	\brief Returns version of the game
+	*/
+	proto native owned string GetBuildVersion();
+
+	/**
+	\brief Returns date and time when the game was built
+	*/
+	proto native owned string GetBuildTime();
+
+	/**
+  	\brief Returns World entity when in game or in play mode in WE. NULL otherwise.
+	*/
+	proto native GenericWorldEntity GetWorldEntity();
+	
+	proto native InputManager GetInputManager();
+	proto native MenuManager GetMenuManager();
+	proto native int GetTickCount();
+}
+
+void GameLibInit()
+{
+
+}
+#endif

+ 46 - 0
Scripts/2_gamelib/inputmanager.c

@@ -0,0 +1,46 @@
+#ifdef GAME_TEMPLATE
+
+enum InputTrigger
+{
+	UP, 			///< call listener when button/key is released
+	DOWN,		 	///< call listener when button/key is pressed
+	PRESSED, 		///< call listener in each tick when button/key is pressed
+	VALUE		 	///< call listener in each tick with current value
+};
+
+class ActionManager
+{
+	void ActionManager(ActionManager parent);
+	proto native external bool RegisterAction(string actionName);
+	proto native external bool RegisterContext(string contextName);
+	
+	proto native external float LocalValue(string actionName);
+	proto native external bool GetActionTriggered(string actionName);
+	
+	proto native external bool ActivateAction(string actionName, int duration = 0);	
+	proto native external bool IsActionActive(string actionName);
+	
+	proto native external bool ActivateContext(string contextName, int duration = 0);	
+	proto native external bool IsContextActive(string contextName);
+	
+	proto external void AddActionListener(string actionName, InputTrigger trigger,  func callback);
+	
+	proto native external void SetContextDebug(string contextName, bool bDebug);
+	
+	proto native void SetParent(ActionManager parent);
+	proto native void SetDebug(bool bDebug);
+};
+
+class InputManager: ActionManager
+{
+	private void InputManager(ActionManager parent) {};
+	private void ~InputManager() {};
+	
+	proto native external void ResetAction(string actionName);
+	proto native void SetCursorPosition(int x, int y);
+	proto native external bool RegisterActionManager(ActionManager pManager);
+	proto native external bool UnregisterActionManager(ActionManager pManager);
+};
+
+#endif
+

+ 95 - 0
Scripts/2_gamelib/menumanager.c

@@ -0,0 +1,95 @@
+#ifdef GAME_TEMPLATE
+
+enum DialogPriority
+{
+	INFORMATIVE,
+	WARNING,
+	CRITICAL	
+};
+
+enum DialogResult
+{
+	PENDING,
+	OK,
+	YES,
+	NO,
+	CANCEL,
+};
+
+enum ScriptMenuPresetEnum
+{
+	
+};
+
+class MenuManager
+{
+	proto native MenuBase OpenMenu(ScriptMenuPresetEnum preset, int userId = 0, bool unique = false);
+	proto native MenuBase OpenDialog(ScriptMenuPresetEnum preset, int priority = DialogPriority.INFORMATIVE, int iUserId = 0, bool unique = false);
+	proto native MenuBase FindMenuByPreset(ScriptMenuPresetEnum preset);
+	proto native MenuBase FindMenuByUserId(int userId);
+	proto native MenuBase GetTopMenu();
+	
+	proto native bool IsAnyMenuOpen();	
+	proto native bool IsAnyDialogOpen();
+
+	proto native bool CloseMenuByPreset(ScriptMenuPresetEnum preset);
+	proto native bool CloseMenuByUserId(int userId);
+	proto native bool CloseMenu(MenuBase menu);
+	
+	protected void MenuManager();
+	protected void ~MenuManager();
+};
+
+class MenuBindAttribute
+{
+	string m_MenuItemName;
+	
+	void MenuBindAttribute(string menuItemName = "")
+	{
+		m_MenuItemName = menuItemName;
+	}
+}
+
+class MenuBase: ScriptedWidgetEventHandler
+{
+	proto native int GetUserId();
+	proto native Widget GetRootWidget();
+	proto external MenuBase BindItem(string menuItemName, func callback);
+	proto native MenuBase SetLabel(string menuItemName, string text);
+	proto native Widget GetItemWidget(string menuItemName);
+	proto native MenuManager GetManager();
+	proto native void Close();
+	
+	void	OnMenuFocusGained() {}
+	void	OnMenuFocusLost() {}
+	void	OnMenuShow() {}
+	void	OnMenuHide() {}
+	void	OnMenuOpen() {}
+	void	OnMenuClose() {}
+	void	OnMenuInit() {}
+	void	OnMenuUpdate(float tDelta) {}
+	void	OnMenuItem(string menuItemName, bool changed, bool finished) {}
+	
+	protected void MenuBase();
+	protected void ~MenuBase();
+};
+
+class MessageBox: MenuBase
+{
+	[MenuBindAttribute()]
+	void Ok()
+	{
+		Close();
+	}
+}
+
+#ifdef PLATFORM_WINDOWS
+class WorldEditorIngame: MenuBase
+{
+	proto native bool LoadWorld(string worldFilePath);
+	proto native bool SaveWorld();
+};
+#endif
+
+#endif
+

+ 38 - 0
Scripts/2_gamelib/settings.c

@@ -0,0 +1,38 @@
+#ifdef GAME_TEMPLATE
+
+class Settings
+{
+	static void		OnChange(string variableName) {}
+	static void 	OnAnyChange() {}	
+	static void 	OnLoad() {}
+	static void 	OnSave() {}
+	static void 	OnReset() {}
+	static void 	OnRevert() {}
+	static void 	OnApply() {}
+	
+	private void Settings() {}
+	private void ~Settings() {}
+};
+
+class GameSettings: Settings
+{
+	[Attribute("false", "checkbox", "Is debug mode enabled")]
+	static bool Debug;
+	
+	override static void OnAnyChange() 
+	{
+		GetGame().SetDebug(Debug);
+	}
+}
+
+class SettingsMenu: MenuBase
+{
+	proto native external bool AddSettings(typename settingsClass);	
+	proto native void Save();	
+	proto native void Reset();
+	proto native void Revert();
+	proto native void Apply();
+	proto native void Back();
+};
+#endif
+

+ 216 - 0
Scripts/2_gamelib/tools.c

@@ -0,0 +1,216 @@
+/**
+ \brief ScriptCallQueue Class provide "lazy" calls - when we don't want to execute function immediately but later during frame update (used mainly in UI)
+ \n usage:
+ @code
+	class Arkanoid extends Game
+	{
+		ref ScriptCallQueue m_CallQueue = new ScriptCallQueue();
+	
+		ScriptCallQueue GetCallQueue() { 
+			return m_CallQueue;
+		}
+	
+		override void OnUpdate(float timeslice)
+		{
+			m_CallQueue.Tick(timeslice);
+			...
+		}
+		...
+	}
+
+	class MyObject
+	{
+		int m_cnt = 0;
+	
+		void Hello(int p1, string p2)
+		{
+			Print("Hello( " + p1 + " , " + p2 + ")");
+		}
+	
+		void Test()
+		{
+			Print(m_cnt);
+			m_cnt++;
+			
+			if (m_cnt > 10)
+			{
+				ScriptCallQueue queue = GetGame().GetCallQueue();
+				queue.Remove(Test);
+			}
+		}
+	}
+
+	void Test(MyObject obj)
+	{
+		ScriptCallQueue queue = GetGame().GetCallQueue(); 
+		queue.CallLater(obj.Hello, 5000, false, 65, "world"); // adds call 'obj.Hello(65, "world")' into queue, and it will be executed once after 5s
+		queue.CallLater(obj.Test, 3000, true); // adds call 'obj.Test()' into queue, and it will be executed each 3s
+		queue.Call(obj.Hello, 72, "world 2"); // adds call 'obj.Hello(72, "world 2")' into queue, and it will be executed next frame (on next call of ScriptCallQueue.Tick)
+	}
+ @endcode
+ */
+class ScriptCallQueue
+{
+	//! executes calls on queue if their time is already elapsed, if 'repeat = false' call is removed from queue
+	proto native void Tick(float timeslice);
+	//! adds call into the queue with given parameters and arguments (arguments are held in memory until the call is executed/removed or ScriptCallQueue is destroyed)
+	proto void Call(func fn, void param1 = NULL, void param2 = NULL, void param3 = NULL, void param4 = NULL, void param5 = NULL, void param6 = NULL, void param7 = NULL, void param8 = NULL, void param9 = NULL);
+	//! adds call into the queue with given parameters and arguments (arguments are held in memory until the call is executed/removed or ScriptCallQueue is destroyed)
+	proto void CallByName(Class obj, string fnName , Param params = NULL);
+	//! adds call into the queue with given parameters and arguments (arguments are held in memory until the call is executed/removed or ScriptCallQueue is destroyed)
+	proto void CallLater(func fn, int delay = 0, bool repeat = false, void param1 = NULL, void param2 = NULL, void param3 = NULL, void param4 = NULL, void param5 = NULL, void param6 = NULL, void param7 = NULL, void param8 = NULL, void param9 = NULL);	
+	//! adds call into the queue with given parameters and arguments (arguments are held in memory until the call is executed/removed or ScriptCallQueue is destroyed)
+	proto void CallLaterByName(Class obj, string fnName, int delay = 0, bool repeat = false, Param params = NULL);	
+	//! remove specific call from queue	
+	proto void Remove(func fn);
+	//! return Remaining time to the call execution (in miliseconds)
+	proto int GetRemainingTime(func fn);
+	//! remove specific call from queue	
+	proto void RemoveByName(Class obj, string fnName);
+	//! return Remaining time to the call execution (in miliseconds)
+	proto int GetRemainingTimeByName(Class obj, string fnName);
+	//! remove all calls from queue
+	proto native void Clear();
+};
+
+/**
+ \brief ScriptInvoker Class provide list of callbacks
+ \n usage:
+ @code
+	class Player
+	{
+		ref ScriptInvoker m_DeathInvoker	= new ScriptInvoker();
+	
+		void OnKilled()
+		{
+			m_DeathInvoker.Invoke(this);		
+		}
+	}
+
+	void LogPlayerDeath(p)
+	{
+		Print("RIP " + p);
+	}		
+
+	class Game
+	{
+		void RemovePlayer(Player p)
+		{
+		}
+
+		void GameOver()
+		{
+		}
+	}
+
+	void OnPlayerSpaned(Player p)
+	{
+		Game game = GetGame();
+		p.m_DeathInvoker.Insert(LogPlayerDeath);
+		p.m_DeathInvoker.Insert(game.RemovePlayer);
+		p.m_DeathInvoker.Insert(game.GameOver);
+	}
+ @endcode
+ */
+class ScriptInvoker
+{
+	//! invoke call on all inserted methods with given arguments
+	proto void Invoke(void param1 = NULL, void param2 = NULL, void param3 = NULL, void param4 = NULL, void param5 = NULL, void param6 = NULL, void param7 = NULL, void param8 = NULL, void param9 = NULL);
+	//! insert method to list
+	proto bool Insert(func fn, int flags = EScriptInvokerInsertFlags.IMMEDIATE);	
+	//! remove specific call from list
+	proto bool Remove(func fn, int flags = EScriptInvokerRemoveFlags.ALL);
+	//! count how many times this fn is actively present in the Invoker
+	proto int Count(func fn);
+	//! remove all calls from list
+	proto native void Clear();
+};
+
+enum EScriptInvokerInsertFlags
+{
+	NONE,
+	/**
+	\brief It gets added in immediately, which means that when called while an invoker is running, it will call this newly added call in the same run
+		\note Default flag, as that is the original behaviour, although it might cause endless Insert chain now... (still better than undefined behaviour)
+		\note In case of "Possible endless Insert detected" VME, either create an exit, remove the IMMEDIATE flag or make the insert UNIQUE
+		\note The Endless Insert is detected by seeing if "amount of calls > initial size + 128"
+	*/
+	IMMEDIATE,
+	/**
+	\brief Only one call to this instance+method is ever expected
+		\note Will throw a VME when a second one is attempted to be added
+		\note If it was already added without the flag, it will also throw a VME and keep the first of all previously inserted
+	*/
+	UNIQUE,
+}
+
+enum EScriptInvokerRemoveFlags
+{
+	NONE,
+	/**
+	\brief Default flag
+		\note Don't use this if you want it to remove only the last insert instead of all of them
+	*/
+	ALL,
+}
+
+/**
+ \brief Designed to hold 1 valid call
+*/
+class ScriptCaller
+{
+	//! ScriptCaller is meant to be created through Create
+	private void ScriptCaller();
+	//! Creates a ScriptCaller
+	static proto ScriptCaller Create(func fn);
+	//! Replaces the current registered func with the new one, throws errors if unsuccessful
+	proto void Init(func fn);	
+	//! Invoke call on the registered func, throws errors if unsuccessful
+	proto void Invoke(void param1 = null, void param2 = null, void param3 = null, void param4 = null, void param5 = null, void param6 = null, void param7 = null, void param8 = null, void param9 = null);
+
+	//! Checks if the ScriptCaller is valid
+	proto bool IsValid();
+
+	/**
+	\brief Compares this script caller against another script caller
+		\note May return true even if either one is invalid
+
+	@code
+		class SomeClass
+		{
+			void SomeMethod()
+			{
+			}
+		}
+
+		void Test()
+		{
+			SomeClass instanceA = new SomeClass();
+			SomeClass instanceB = new SomeClass();
+
+			ScriptCaller callerA;
+			ScriptCaller callerB;
+
+			//! Two methods that are to the same instance
+			callerA = ScriptCaller.Create(instanceA.SomeMethod);
+			callerB = ScriptCaller.Create(instanceA.SomeMethod);
+
+			Print(callerA.Equals(callerB)); //! "1"
+			Print(callerA == callerB); //! "0"
+			Print(callerA); //! "ScriptCaller callerA = ScriptCaller<87bc2d40>"
+			Print(callerB); //! "ScriptCaller callerB = ScriptCaller<87bc3600>"
+
+			//! Two methods belonging to different instances
+			callerA = ScriptCaller.Create(instanceA.SomeMethod);
+			callerB = ScriptCaller.Create(instanceB.SomeMethod);
+
+			Print(callerA.Equals(callerB)); //! "0"
+			Print(callerA == callerB); //! "0"
+			Print(callerA); //! "ScriptCaller callerA = ScriptCaller<87bc3c40>"
+			Print(callerB); //! "ScriptCaller callerB = ScriptCaller<87bc2d40>"
+		}
+	@endcode
+	*/
+	proto bool Equals(notnull ScriptCaller other);
+
+};

+ 8 - 0
Scripts/3_game/ai/aiagent.c

@@ -0,0 +1,8 @@
+class AIAgent : Managed
+{
+	private void AIAgent();
+	private void ~AIAgent();
+	
+	proto native void SetKeepInIdle(bool enable);
+	proto native AIGroup GetGroup();
+}

+ 15 - 0
Scripts/3_game/ai/aigroup.c

@@ -0,0 +1,15 @@
+class AIGroup : Managed
+{
+	private void AIGroup();
+	private void ~AIGroup();
+	
+	/*!
+	Manual group management - add / remove agents from group.
+	Don't forget to remove agent from old group.
+	Caution! Empty groups are deleted on the next frame.
+	*/
+ 	proto native void AddAgent(notnull AIAgent agent);
+ 	proto native void RemoveAgent(notnull AIAgent agent);
+	
+	proto native AIGroupBehaviour GetBehaviour();
+};

+ 32 - 0
Scripts/3_game/ai/aigroupbehaviour.c

@@ -0,0 +1,32 @@
+class AIGroupBehaviour : Managed
+{
+	private void AIGroupBehaviour();
+	private void ~AIGroupBehaviour();
+}
+
+class BehaviourGroupInfectedPackWaypointParams
+{
+	vector m_CenterPosition;
+	float m_Radius;
+	
+	void BehaviourGroupInfectedPackWaypointParams(vector pos, float radius)
+	{
+		m_CenterPosition = pos;
+		m_Radius = radius;
+	}
+}
+
+class BehaviourGroupInfectedPack : AIGroupBehaviour
+{
+	/*!
+	Group waypoints initialization
+	/param 	[in] 	waypointDefaultIndex 		Starting waypoint. Index to array of waypoints specified by waypointParams. Acceptable range is [0, waypointParams.Count() - 1]
+	/param 	[in]	forwardDirection			Waypoints traverse order.
+	/param 	[in]	loop						Specifies what happens after last waypoint is reached. true - cycle waypoints, false - patrol waypoints
+	*/
+	proto native void SetWaypoints(array<ref BehaviourGroupInfectedPackWaypointParams> waypointParams, int waypointDefaultIndex, bool forwardDirection, bool loop);
+
+	proto native void SetWaypointsTraverseDirection(bool forwardDirection);
+	proto native void SetWaypointsLoop(bool loop);
+	proto native void SetCurrentWaypoint(int waypointIndex);
+}

+ 123 - 0
Scripts/3_game/ai/aiworld.c

@@ -0,0 +1,123 @@
+enum PGPolyFlags
+{
+	NONE,
+
+	WALK,			// Ability to walk (ground, grass, road)
+	DISABLED,		// Disabled polygon
+	DOOR,			// Ability to move through doors
+	INSIDE,			// Ability to move inside buildings
+
+	SWIM,			// Ability to swim (water)
+	SWIM_SEA,		// Ability to swim (sea water)
+
+	LADDER,			// Ability to climb on ladders
+	JUMP_OVER,		// Ability to do jumps overs
+	JUMP_DOWN,		// Ability to jump down
+	CLIMB,			// Ability to climb up
+	CRAWL,			// Ability to crawl
+	CROUCH,			// Ability to crouch
+
+	UNREACHABLE,
+
+	ALL,
+
+	JUMP,			// JUMP_OVER | JUMP_DOWN
+	SPECIAL			// JUMP | CLIMB | CRAWL | CROUCH
+}
+
+enum PGAreaType
+{
+	NONE,
+
+	TERRAIN,
+
+	WATER,
+	WATER_DEEP,
+	WATER_SEA,
+	WATER_SEA_DEEP,
+	OBJECTS_NOFFCON,
+
+	OBJECTS,
+	BUILDING,
+	ROADWAY,
+	TREE,
+	ROADWAY_BUILDING,
+
+	DOOR_OPENED,
+	DOOR_CLOSED,
+
+	LADDER,
+	CRAWL,
+	CROUCH,
+	FENCE_WALL,
+	JUMP
+}
+
+/*!
+Filter for FindPath, RaycastNavMesh, SampleNavmeshPosition
+*/
+class PGFilter : Managed
+{
+	// Uses PGPolyFlags bitmasks
+	proto native int GetIncludeFlags();
+	proto native int GetExcludeFlags();
+	proto native int GetExlusiveFlags();
+	proto native void SetFlags(int includeFlags, int excludeFlags, int exclusiveFlags);
+
+	proto native void SetCost(PGAreaType areaType, float cost);
+}
+
+class AIWorld : Managed
+{
+	private void AIWorld();
+	private void ~AIWorld();
+
+	/*!
+	Creates group with group behaviour specified by templateName param.
+	AIGroups lifetime is managed by AIWorld, e.g. empty groups are deleted automatically.
+	*/
+	proto native AIGroup CreateGroup(string templateName);
+	/*!
+	Creates group with no group behaviour
+	*/
+	proto native AIGroup CreateDefaultGroup();
+	/*!
+	Destroys group and all AIAgents attached
+	*/
+	proto native void DeleteGroup(notnull AIGroup group);
+	
+	/*!
+	Finds path on navmesh using path graph filter. 
+	
+	/param 	[in]	from 			starting position
+	/param 	[in] 	to 				ending position
+	/param 	[in] 	pgFilter 		filter used for searching
+	/param 	[out] 	waypoints		waypoints array including starting and ending position
+	/returns	true - if path has been found
+	*/
+	proto native bool FindPath(vector from, vector to, PGFilter pgFilter, out TVectorArray waypoints);
+	
+	/*!
+	Raytest in navmesh
+	
+	/param 	[in]	from 			starting position
+	/param 	[in] 	to 				ending position
+	/param 	[in] 	pgFilter 		filter used for searching
+	/param 	[out] 	hitPos			hit position
+	/param 	[out] 	hitNormal		hit normal
+	/returns	true - if ray hits navmesh edge
+	*/
+	proto native bool RaycastNavMesh(vector from, vector to, PGFilter pgFilter, out vector hitPos, out vector hitNormal);
+	
+	/*!
+	Finds closest point on navmesh within maxDistance radius using path graph filter. 
+	
+	/param 	[in]	position 			position wanted
+	/param 	[in] 	maxDistance 		search radius
+	/param 	[in] 	pgFilter 		filter used for searching
+	/param 	[out] 	sampledPosition		closest position on navmesh to position
+	/returns	true - function succeedes and found position is written to output paramter "sampledPosition"
+	/returns	false - function failed to find position on navmesh within given radius, output paramter is left intact
+	*/
+	proto native bool SampleNavmeshPosition(vector position, float maxDistance, PGFilter pgFilter, out vector sampledPosition);	
+}

+ 147 - 0
Scripts/3_game/aibehaviour.c

@@ -0,0 +1,147 @@
+/** @file 
+
+  this file is interface to AI Behaviour
+
+*/
+
+/*
+class AIMessage: Managed
+
+{
+	Param m_Parameters;
+	int m_CrcMessage;
+	Param GetParameters();
+	int GetTypeNameCRC();
+}
+
+class AIMessageTest : AIMessage
+{
+	int GetTypeNameCRC() {return testCRC;}
+	//static int testCRC = 5;	
+}
+
+*/
+
+
+class AIBehaviourHLData
+{
+	private void AIBehaviourHLData() {}
+	private void ~AIBehaviourHLData() {}
+	
+	//void ParseConfig(ParamEntryPar param, AIWorld* world, AIAgentTemplate* agentTemplate) {};
+	void OnParseConfig();	
+	
+	//Can be use only inside OnParseConfig function
+	proto native void ParseBehaviourSlot(string name);
+	proto native void ParseAlertLevel(string name);
+	proto native float ReadParamValue(string paramName, float defValue);
+	
+}
+
+
+class AIBehaviourHL
+{
+	private void AIBehaviourHL() {}
+	private void ~AIBehaviourHL() {}
+	
+	proto native AIBehaviourHLData GetTemplateData();
+	
+	void OnInit(){};
+	//private void AIBehaviourHL_script() {};
+	//private void ~AIBehaviourHL_script() {};
+
+	void Simulate (float timeDelta)
+	{
+		//time = time + timeDelta; 
+		//Print("A2");
+	}
+	
+	
+	//void OnNoise(AINoiseInfo noise, EntityAI source){}
+	void OnDamage(float damage, EntityAI source){}
+
+	void OnDamageInflicted(){}
+	void OnAnimationEvent(int nameCrc){}
+	//void OnMessage(AIMessage message){}
+	//void OnBehaviourSwitched(AIBehaviour* behaviour){}
+	proto native void SetNextBehaviour(int BehaviourCrc);
+	proto native void SwitchToNextBehaviour();
+	
+	static proto void RegAIBehaviour(string behname,typename behClass, typename behClassData);
+};
+
+
+class AIBehaviourHLZombie2 : AIBehaviourHL
+{
+	//AIBehaviourHLDataZombie2 data;
+	//int state;
+	//float time;
+	AIBehaviourHLDataZombie2 GetData()
+	{
+		return AIBehaviourHLDataZombie2.Cast( GetTemplateData() );
+	}
+	
+	private void AIBehaviourHLZombie2() {}
+	private void ~AIBehaviourHLZombie2() {}
+	
+	override void OnInit()
+	{
+		SetNextBehaviour(0x7b9a4ee9);
+		SwitchToNextBehaviour();
+		//Print("OnInit");
+		//data = GetData();
+		//float a = data.m_fDamageToCrawl;
+		//Print(a);
+	}
+	
+	override void Simulate (float timeDelta)
+	{
+		//time = time + timeDelta; 
+		//Print("B2");
+	}
+	
+	void ShowDebugInfo() 
+	{
+		//Print(time);
+	};
+	
+	//void OnMessage(AIMessage message)
+	//{
+		//int ID = message.GetTypeNameCRC();
+		//Print(ID);
+		
+	//}
+};
+
+class AIBehaviourHLDataZombie2 : AIBehaviourHLData
+{
+	float m_fDamageToCrawl;
+	float m_fCrawlProbability;
+
+	private void AIBehaviourHLDataZombie2() {}
+	private void ~AIBehaviourHLDataZombie2() {}
+	
+	override void OnParseConfig()
+	{
+		Print("zombie data parse config start");
+		
+		ParseBehaviourSlot("Calm");
+		ParseBehaviourSlot("Attracted");
+		ParseBehaviourSlot("Disturbed");
+		ParseBehaviourSlot("Alerted");
+		
+		ParseAlertLevel("Calm");
+		ParseAlertLevel("Disturbed");
+		ParseAlertLevel("Attracted");
+		ParseAlertLevel("Alerted");
+		
+		m_fDamageToCrawl = ReadParamValue("damageToCrawl",0.01);
+		m_fCrawlProbability = ReadParamValue("crawlProbability",0.01);
+		
+		Print("zombie data parse config end");
+	}
+};
+
+//NewNPC(model,behname,....)
+
+

+ 17 - 0
Scripts/3_game/ammocamparams.c

@@ -0,0 +1,17 @@
+class AmmoCamParams
+{
+	void Load(string ammoType)
+	{
+		string cfgPath = "CfgAmmo " + ammoType + " Effects" + " CameraShake ";
+		
+		m_Radius				= GetGame().ConfigGetFloat(cfgPath + "radius");
+		m_Strength				= GetGame().ConfigGetFloat(cfgPath + "strength");
+		m_ModifierClose			= GetGame().ConfigGetFloat(cfgPath + "modifierClose");
+		m_ModifierFar			= GetGame().ConfigGetFloat(cfgPath + "modifierFar");
+	}
+	
+	float m_Radius = 40;//the max distance at which the cam shake is triggered
+	float m_Strength = 4;//strength of the cam shake
+	float m_ModifierClose = 1;//shake 'strength' modifier when the player is at distance 0 from the source of explosion
+	float m_ModifierFar = 0;//shake 'strength' modifier when the player is at distance 'radius' from the source of explosion
+}

+ 137 - 0
Scripts/3_game/ammoeffects.c

@@ -0,0 +1,137 @@
+/**
+\brief Static data holder for certain ammo config values
+	\note Kept the names similar to what is in config, but it might be a little deceiving as this is mainly used for explosives
+*/
+class AmmoEffects
+{	
+	//! Key: Ammo class name; Data: ParticleList ID
+	static ref map<string, int> m_AmmoParticles;
+	
+	//! Key: Ammo class name; Data: ParticleList ID
+	static ref map<string, typename> m_AmmoEffects;
+	
+	
+	
+	/** \name Ammo particles
+ 		Methods regarding getting/playing ammo particle
+	*/
+	//@{
+	
+	//! Get the ParticleList ID for the particle for this ammoType
+	static int GetAmmoParticleID(string ammoType)
+	{
+		int particleID;
+		
+		// Search for it in the static map
+		if ( !m_AmmoParticles.Find(ammoType, particleID) )
+		{
+			// Load it in when we can't find it
+			string particleFileName;
+			GetGame().ConfigGetText(string.Format("cfgAmmo %1 particle", ammoType), particleFileName);
+			
+			// If we found a valid entry, try looking for it in ParticleList
+			if ( particleFileName != "" )
+			{
+				particleID = ParticleList.GetParticleIDByName(particleFileName);
+			}
+			
+			// Store it for next search
+			m_AmmoParticles.Insert(ammoType, particleID);
+		}
+		
+		return particleID;
+	}
+	
+	//! Attempt to play the ammo particle at pos if found, returns true on success
+	static bool PlayAmmoParticle(string ammoType, vector pos)
+	{
+		int particleID = GetAmmoParticleID(ammoType);
+		
+		if (ParticleList.IsValidId(particleID))
+		{
+			return ParticleManager.GetInstance().PlayInWorld(particleID, pos) != null;
+		}
+		
+		return false;
+	}
+	
+	//@}
+	
+	
+	
+	/** \name Ammo effects
+ 		Methods regarding getting/playing ammo effect
+	*/
+	//@{
+	
+	//! Get the typename for the effect for this ammoType
+	static typename GetAmmoEffectTypename(string ammoType)
+	{
+		typename typeName;
+		
+		// Search for it in the static map
+		if ( !m_AmmoEffects.Find(ammoType, typeName) )
+		{
+			// Load it in when we can't find it
+			string effectName;
+			GetGame().ConfigGetText(string.Format("cfgAmmo %1 effect", ammoType), effectName);
+			
+			// If we found a valid entry, try looking for it in ParticleList
+			if ( effectName != "" )
+			{
+				typeName = effectName.ToType();
+			}
+			
+			// Store it for next search
+			m_AmmoEffects.Insert(ammoType, typeName);
+		}
+		
+		return typeName;
+	}
+	
+	//! Attempt to play the ammo effect at pos if found, returns true on success
+	static bool PlayAmmoEffect(string ammoType, vector pos)
+	{
+		typename typeName = GetAmmoEffectTypename(ammoType);
+		
+		if ( typeName )
+		{
+			Effect eff = Effect.Cast(typeName.Spawn());
+			
+			if ( eff )
+			{
+				eff.SetAutodestroy(true);
+				return SEffectManager.PlayInWorld( eff, pos );
+			}
+		}
+		
+		return false;
+	}
+	
+	//@}
+	
+	
+	
+	/** \name Lifetime
+ 		Creation and cleanup
+	*/
+	//@{
+	
+	//! Initialize the containers: this is done this way, to have these not exist on server
+	static void Init()
+	{
+		m_AmmoParticles = new map<string, int>();
+		m_AmmoEffects = new map<string, typename>();
+	}
+	
+	//! Clean up the data
+	static void Cleanup()
+	{
+		/* These ain't containing no refs, so whatever
+		m_AmmoParticles.Clear();
+		m_AmmoEffects.Clear();
+		*/
+	}
+	
+	//@}
+}

+ 180 - 0
Scripts/3_game/analytics/analyticsmanagerclient.c

@@ -0,0 +1,180 @@
+class AnalyticsManagerClient
+{
+	static const int GEAR_COUNT = 3; 
+	static string m_FullGear[GEAR_COUNT] = {"Shoulder","Melee","Back"};
+	
+	void RegisterEvents()
+	{
+		ClientData.SyncEvent_OnEntityKilled.Insert(Event_OnEntityKilled);
+		ClientData.SyncEvent_OnPlayerIgnitedFireplace.Insert(Event_OnPlayerIgnitedFireplace);
+	}
+	
+	void UnregisterEvents()
+	{
+		ClientData.SyncEvent_OnEntityKilled.Remove(Event_OnEntityKilled);
+		ClientData.SyncEvent_OnPlayerIgnitedFireplace.Remove(Event_OnPlayerIgnitedFireplace);
+	}
+	
+	//===================================
+	// OnActionEat
+	//===================================
+	void OnActionEat()
+	{
+		Achievements.OnActionEat();
+	}
+	
+	//===================================
+	// OnActionDrink
+	//===================================
+	void OnActionDrink()
+	{
+		Achievements.OnActionDrink();
+	}
+	
+	//===================================
+	// OnActionCookedSteak - not implemented
+	//===================================
+	void OnActionCookedSteak()
+	{
+		Achievements.OnCookedSteak();
+	}
+	
+	//===================================
+	// OnActionFinishedShaveSelf
+	//===================================
+	void OnActionFinishedShaveSelf()
+	{
+		Achievements.OnActionShave();
+	}
+	
+	//===================================
+	// OnActionFinishedGutDeer
+	//===================================
+	void OnActionFinishedGutDeer()
+	{
+		Achievements.OnActionGutDeer();
+	}
+	
+	//===================================
+	// OnActionRestrain
+	//===================================
+	void OnActionRestrain()
+	{		
+		Achievements.OnActionHandcuff();
+	}
+	
+	//===================================
+	// OnActionBandageTarget
+	//===================================
+	void OnActionBandageTarget()
+	{	
+		Achievements.OnActionMedsSurvivor();
+	}
+	
+	//===================================
+	// OnItemAttachedAtPlayer
+	//===================================
+	void OnItemAttachedAtPlayer(EntityAI item, string slot_name)
+	{
+		bool weapon_present;
+		bool melee_present;
+		bool backpack_present;
+		HumanInventory inventory;
+
+		if ( GetDayZGame().GetGameState() != DayZGameState.IN_GAME )
+		{
+			return;
+		}
+		
+		Man player = GetGame().GetPlayer();
+		if (!player)
+		{
+			return;
+		}
+		
+		inventory = player.GetHumanInventory();
+			
+		if ( player && inventory )
+		{
+			for ( int i = 0; i < GEAR_COUNT; ++i )
+			{
+				int slot_id = InventorySlots.GetSlotIdFromString(m_FullGear[i]);
+				EntityAI att_item = inventory.FindAttachment( slot_id ); // Boris V [27.2.2019]: Consider using player.GetItemOnSlot(m_FullGear[i]) instead.
+					
+				if ( !att_item )
+				{
+					//Print("index: "+ i +" slot_id: "+ slot_id +" = "+ att_item + " EMPTY");
+					continue;
+				}
+				
+				//checks for firearm
+				if (att_item.IsWeapon())
+					weapon_present = true;
+				//checks for melee weapon
+				else if (!att_item.IsWeapon() && att_item.GetInventory().HasInventorySlot(InventorySlots.GetSlotIdFromString("Melee")))
+					melee_present = true;
+				//checks for backpack
+				else if (!att_item.IsWeapon() && att_item.GetInventory().HasInventorySlot(InventorySlots.GetSlotIdFromString("Back")))
+					backpack_present = true;
+				//Print("index: "+ i +" slot_id: "+ slot_id +" = "+ att_item + " ATTACHED");
+			}
+				
+			//separate check for hand slot; TODO remove duplicates
+			att_item = inventory.GetEntityInHands();
+			if ( att_item )
+			{
+				//checks for firearm
+				if (att_item.IsWeapon())
+					weapon_present = true;
+				//checks for melee weapon
+				else if (!att_item.IsWeapon() && att_item.GetInventory().HasInventorySlot(InventorySlots.GetSlotIdFromString("Melee")) )
+					melee_present = true;
+				//checks for backpack
+				else if (!att_item.IsWeapon() && att_item.GetInventory().HasInventorySlot(InventorySlots.GetSlotIdFromString("Back")))
+					backpack_present = true;
+			}
+				
+			if (weapon_present && melee_present && backpack_present)
+			{
+				//Print("---EAchievementActionId.ACTION_EQUIP_GEAR");
+				Achievements.OnEquippedFullGear();
+			}
+		}
+	}
+	
+	//===================================
+	// Event_OnPlayerIgnitedFireplace
+	//===================================
+	void Event_OnPlayerIgnitedFireplace( EFireIgniteType ignite_type )
+	{
+		switch ( ignite_type )
+		{
+			case EFireIgniteType.Matchbox:
+			{
+				Achievements.OnActionIgniteMatchbox();
+				break;
+			}
+			case EFireIgniteType.Roadflare:
+			{
+				Achievements.OnActionIgniteRoadflare();
+				break;
+			}
+			case EFireIgniteType.HandDrill:
+			{
+				Achievements.OnActionIgniteDrill();
+				break;
+			}
+		}
+	}
+	
+	//===================================
+	// Event_OnEntityKilled
+	//===================================
+	void Event_OnEntityKilled(EntityAI victim, EntityAI killer, EntityAI source, bool is_headshot)
+	{
+		if ( killer != null && killer.IsPlayer() && killer.GetID() == GetGame().GetPlayer().GetID() )
+		{
+			Achievements.OnPlayerKilled(victim, killer, source, is_headshot);
+		}
+	}
+}

+ 73 - 0
Scripts/3_game/analytics/analyticsmanagerserver.c

@@ -0,0 +1,73 @@
+class AnalyticsManagerServer
+{
+	const string STAT_DISTANCE 				= "dist";
+	const string STAT_PLAYTIME 				= "playtime";
+	const string STAT_PLAYERS_KILLED 		= "players_killed";
+	const string STAT_INFECTED_KILLED 		= "infected_killed";
+	const string STAT_LONGEST_SURVIVOR_HIT 	= "longest_survivor_hit";
+	
+	void OnPlayerConnect(Man player)
+	{
+		player.StatRegister(STAT_DISTANCE);
+		player.StatRegister(STAT_PLAYTIME);
+		player.StatRegister(STAT_PLAYERS_KILLED);
+		player.StatRegister(STAT_INFECTED_KILLED);
+		player.StatRegister(STAT_LONGEST_SURVIVOR_HIT);
+	}
+		
+	void OnPlayerDisconnect(Man player)
+	{
+		player.StatUpdateByPosition(STAT_DISTANCE);
+		player.StatUpdateByTime(STAT_PLAYTIME);
+	}
+	
+	//Entity-Entity hit
+	void OnEntityHit(EntityAI source, Man target)
+	{
+		if (source)
+		{
+			Man survivor = source.GetHierarchyRootPlayer();
+			if (survivor && source.IsWeapon())
+				OnPlayerToPlayerHit(survivor, target);
+		}
+	}
+	
+	protected void OnPlayerToPlayerHit(Man shooter, Man target)
+	{
+		float longestHitDistance = shooter.StatGet(STAT_LONGEST_SURVIVOR_HIT);
+		float currentDistance = vector.Distance(shooter.GetPosition(), target.GetPosition());
+		float distanceUpdate;
+		
+		if (longestHitDistance < currentDistance)
+			distanceUpdate = currentDistance - longestHitDistance;
+		
+		shooter.StatUpdate(STAT_LONGEST_SURVIVOR_HIT, distanceUpdate);
+	}
+	
+	//Entity-Entity kill
+	void OnEntityKilled(Object killer, EntityAI target)
+	{
+		EntityAI killerEntity = EntityAI.Cast(killer);
+		if (killerEntity)
+		{
+			Man killerSurvivor = killerEntity.GetHierarchyRootPlayer();
+			if (killerSurvivor)
+			{
+				if (target.IsPlayer())
+					OnPlayerKilled(killerSurvivor, target);
+				else if (target.IsZombie())
+					OnInfectedKilled(killerSurvivor, target);
+			}
+		}
+	}
+	
+	protected void OnPlayerKilled(Man killer, EntityAI target)
+	{
+		killer.StatUpdate(STAT_PLAYERS_KILLED, 1);
+	}
+	
+	protected void OnInfectedKilled(Man killer, EntityAI target)
+	{
+		killer.StatUpdate(STAT_INFECTED_KILLED, 1);
+	}
+}

+ 176 - 0
Scripts/3_game/analytics/scriptanalytics.c

@@ -0,0 +1,176 @@
+// class binded to engine
+class StatsEventMeasuresData
+{
+	string m_CharacterId;		//!< character ID
+	int m_TimeInterval;			//!< amount of real time in seconds covered by this event
+	int m_DaytimeHour;			//!< current daytime in gameplay (hour in 24h format)
+	vector m_PositionStart;		//!< player world position at the start of interval
+	vector m_PositionEnd;		//!< player world position at the end of interval
+	float m_DistanceOnFoot;		//!< traveled distance on foot (meters) during interval
+	
+	float m_DistanceVehicle;	//!< traveled distance (meters) in vehicle during interval
+	float m_TimeVONIn;			//!< amount of time in seconds with inbound VON during interval
+	float m_TimeVONOut;			//!< amount of time in seconds with outbound VON during interval
+	int m_CntLootAny;			//!< count of any loot collected during interval
+	int m_CntLootFood;			//!< count of any food or consumables collected during interval
+	int m_CntLootCloth;			//!< count of cloth collected during interval
+	int m_CntLootFirearm;		//!< count of firearms collected during interval
+	int m_CntLootAmmo;			//!< count of ammo collected during interval
+	int m_CntKillInfected;		//!< count of infected kills during interval
+	int m_CntConsumedFood;		//!< count of consumed food during interval
+	int m_CntConsumedWater;		//!< count of consumed water during interval
+	int m_HealthRestored;		//!< number of health point restored during interval
+	int m_CntFiredAmmo;			//!< firearm rounds fired during interval
+	int m_CntCraftedItem;		//!< number of items crafted during interval
+	
+	// listStatus				// state metric of health, hunger, thirst, etc... when event is created/send
+	int m_HealthStatus;			//!< state of health (current state)
+	int m_BloodStatus;			//!< state of blood (current state)
+	int m_SicknessStatus;		//!< state of sickness (current state)
+	int m_TemperatureStatus;	//!< state of temperature (current state)
+	int m_FoodStatus;			//!< state of food (hunger) (current state)
+	int m_HydrationStatus;		//!< state of hydration (thirst) (current state)
+};
+
+// class binded to engine
+class StatsEventDeathData
+{
+	string		m_CharacterId;			//!< character ID
+	int			m_CharacterLifetime;	//!< lifetime of character in seconds
+	string		m_Cause;				//!< cause of death (hunger, sickness, player-killed, zombie-killed...)
+	string		m_WeaponName;			//!< name of weapon which caused death
+	float		m_Distance;				//!< distance in meters (rounded) from spawn position to death position
+	vector		m_Position;				//!< position of player when died
+	
+	int			m_ListDamages[5];		//!< list of damages (5 values) during last n sec. For example: {20, 80, 0, 0, 0}
+};
+
+// class binded to engine
+class StatsEventScoredKillData
+{
+	string		m_CharacterId;		//!< character ID
+	string		m_WeaponName;		//!< name of weapon which killed player (victim)
+	int			m_KillDistance;		//!< distance in meters (rounded) between killer and victim
+	vector		m_PositionKiller;	//!< position of killer
+	vector		m_PositionVictim;	//!< position of victim
+};
+
+// class binded to engine
+class StatsEventDisconnectedData
+{
+	string		m_CharacterId;	//!< character ID
+	string		m_Reason;		//!< reason of disconnect (quit, kick, ban, sign-out...)
+};
+
+// class binded to engine
+class StatsEventSpawnedData
+{
+	string		m_CharacterId;	//!< character ID
+	int			m_Lifetime;		//!< lifetime of character in seconds
+	vector		m_Position;		//!< position of spawn
+	int			m_Population;	//!< population of current gameplay (server)
+	int			m_DaytimeHour;	//!< current time in hour (hour in 24h)
+};
+
+// class binded to engine
+class StatsEventData
+{
+	void StatsEventData(string eventName)
+	{
+		m_eventName = eventName;
+		m_valuesBool = new map<string, int>();
+		m_valuesInt = new map<string, int>();
+		m_valuesFloat = new map<string, float>();
+		m_valuesString = new map<string, string>();
+		m_valuesVector = new map<string, vector>();
+	}
+	
+	void AddBool(string key, bool value)
+	{
+		m_valuesBool.Insert(key, (int)value);
+	}
+	
+	void AddInt(string key, int value)
+	{
+		m_valuesInt.Insert(key, value);
+	}
+	
+	void AddFloat(string key, float value)
+	{
+		m_valuesFloat.Insert(key, value);
+	}
+	
+	void AddString(string key, string value)
+	{
+		m_valuesString.Insert(key, value);
+	}
+	
+	void AddVector(string key, vector value)
+	{
+		m_valuesVector.Insert(key, value);
+	}
+	
+	private string m_eventName;
+	private autoptr map<string, int> m_valuesBool;//TODO: use bool instead of int (problem with engine type binding)
+	private autoptr map<string, int> m_valuesInt;
+	private autoptr map<string, float> m_valuesFloat;
+	private autoptr map<string, string> m_valuesString;
+	private autoptr map<string, vector> m_valuesVector;
+}
+
+
+class ScriptAnalytics
+{
+	//! send event about death to statistic DB
+	static proto native void SendPlayerDeath(StatsEventDeathData data);
+	
+	//! send event about kill to statistic DB
+	static proto native void SendPlayerScoredKill(StatsEventScoredKillData data);
+	
+	//! send event to statistic DB
+	static proto native void SendPlayerDisconnected(StatsEventDisconnectedData data);
+	
+	//! send event about player status to statistic DB
+	static proto native void SendPlayerMeasures(StatsEventMeasuresData data);
+	
+	//! send event about spawning to statistic DB
+	static proto native void SendPlayerSpawned(StatsEventSpawnedData data);
+	
+	//! universal analytics event
+	static proto native void SendEvent(StatsEventData data);
+};
+
+
+
+class Analytics
+{
+	// send stats data with log
+	static void PlayerDeath(StatsEventDeathData data)
+	{
+		ScriptAnalytics.SendPlayerDeath(data);
+	}
+	
+	// send stats data with log
+	static void PlayerScoredKill(StatsEventScoredKillData data)
+	{
+		ScriptAnalytics.SendPlayerScoredKill(data);
+	}
+	
+	// send stats data with log
+	static void PlayerDisconnected(StatsEventDisconnectedData data)
+	{
+		ScriptAnalytics.SendPlayerDisconnected(data);
+	}
+	
+	// send stats data with log
+	static void PlayerMeasures(StatsEventMeasuresData data)
+	{
+		ScriptAnalytics.SendPlayerMeasures(data);
+	}
+	
+	// send stats data with log
+	static void PlayerSpawned(StatsEventSpawnedData data)
+	{
+		ScriptAnalytics.SendPlayerSpawned(data);
+	}
+}

+ 35 - 0
Scripts/3_game/anim/animcommand.c

@@ -0,0 +1,35 @@
+//! base class of all commands exposed to script to provide common functionality over animations
+class AnimCommandBase
+{
+	// These would be private if not for the scripted commands
+	// As other commands lifetime are handled internally
+	protected void AnimCommandBase() {}
+	protected void ~AnimCommandBase() {}
+	
+	//! returns entity that this command is bount to
+	proto native IEntity GetEntity();
+
+	//! called when command starts
+	void OnActivate() {}
+
+	//! called when command ends
+	void OnDeactivate() {}
+
+	//! called before any animation is processed
+	//! here change animation values, add animation commands
+	void PreAnimUpdate(float pDt) {}
+
+	//! after animation is processed, before physics is processed
+	//! here you can listen to various events
+	void PrePhysUpdate(float pDt) {}
+
+	//! functions usable only from OnActivate or PreAnimUpdate
+	proto native void PreAnim_CallCommand(int pCommand, int pParamInt, float pParamFloat);
+	proto native void PreAnim_SetFloat(int pVar, float pFlt);
+	proto native void PreAnim_SetInt(int pVar, int pInt);
+	proto native void PreAnim_SetBool(int pVar, bool pBool);
+
+	//! functions usable in PrePhysUpdate
+	proto native bool PrePhys_IsEvent(int pEvent);
+	proto native bool PrePhys_IsTag(int pTag);
+}

+ 134 - 0
Scripts/3_game/anim/animphysagent.c

@@ -0,0 +1,134 @@
+#ifdef FEATURE_NETWORK_RECONCILIATION
+
+/**
+ * The replay system only replays outputs from animation. It does not replay animations and does not replay actual inputs. 
+ * This means very often when a desync is detected, multiple corrections have to be sent before the simulation is stable. 
+ * This is why we only ever actually use this system for when a player is in HumanCommandMove and HumanCommandFall.
+ * 
+ * For some situations, such as swimming, it is not possible to ever correct as the water alignment heavily depends on re-simulaton of 
+ * animations, which is not happening. With this,  we use MINIMAL correction mode. This minimal correction mode is something similiar
+ * to how the old correction system used to work and could lead to situations such as being stuck behind doors. 
+ * This is not a problem for swimming.
+ */
+
+enum AnimPhysCorrectionType
+{
+	//! Additively apply the correction based on the delta and sends very minimal data, uses 'NetworkCompareResult.FORCE_CORRECT'
+	MINIMAL,
+	
+	//! No correction is performed
+	DROP,
+
+	//! Rewind the player physics and replay the moves
+	FULL
+};
+
+class AnimPhysOwnerState : PawnOwnerState
+{
+	proto native void	SetCorrectionType(int value);
+	proto native int	GetCorrectionType();
+
+	proto native void	SetPosition(vector value);
+	proto native void	GetPosition(out vector value);
+
+	proto native void	SetRotation(float value[4]);
+	proto native void	GetRotation(out float value[4]);
+
+	//! If parent entity doesn't exist for the owner then the correction is dropped
+	proto native void	SetParent(Object value);
+	proto native Object	GetParent();
+
+	//! If linked entity doesn't exist for the owner then the correction is dropped
+	proto native void	SetLinked(Object value);
+	proto native Object	GetLinked();
+
+	proto native bool	IsLinked();
+	proto native bool	IsParented();
+
+	proto native void	SetSpeed(vector value);
+	proto native void	GetSpeed(out vector value);
+
+	proto native void	SetCollisionLayer(int value);
+	proto native int	GetCollisionLayer();
+
+	proto native void	SetFlags(int value);
+	proto native int	GetFlags();
+
+	proto native void	SetCollisionOffset(vector value);
+	proto native int	GetCollisionOffset(out vector value);
+
+	proto native void	SetStance(int value);
+	proto native int	GetStance();
+
+#ifdef DIAG_DEVELOPER
+	override event void	GetTransform(inout vector transform[4])
+	{
+		float rotation[4];
+		GetRotation(rotation);
+		Math3D.QuatToMatrix(rotation, transform);
+
+		vector position;
+		GetPosition(position);
+		transform[3] = position;
+
+		Object parent = GetParent();
+		if (parent)
+		{
+			vector parentTransform[4];
+			parent.GetTransform(parentTransform);
+			Math3D.MatrixMultiply4(parentTransform, transform, transform);
+		}
+	}
+#endif
+
+};
+
+class AnimPhysMove : PawnMove
+{
+	proto native void	SetCorrectionType(int value);
+	proto native int	GetCorrectionType();
+
+	proto native void	SetPosition(vector value);
+	proto native void	GetPosition(out vector value);
+
+	proto native void	SetRotation(float value[4]);
+	proto native void	GetRotation(out float value[4]);
+
+	proto native void	SetParent(Object value);
+	proto native void	SetLinked(Object value);
+	
+	proto native Object	GetParentOrLinked();
+	proto native Object	GetParent();
+
+	proto native bool	HasParent();
+
+	proto native bool	IsParented();
+	proto native bool	IsLinked();
+
+	//! Parent (or linked) entity could've been deleted, store the necessary values so we have something to work with
+	proto native void	SetParentTransform(vector transform[4]);
+	proto native void	GetParentTransform(out vector transform[4]);
+
+#ifdef DIAG_DEVELOPER
+	override event void	GetTransform(inout vector transform[4])
+	{
+		float rotation[4];
+		GetRotation(rotation);
+		Math3D.QuatToMatrix(rotation, transform);
+
+		vector position;
+		GetPosition(position);
+		transform[3] = position;
+
+		if (HasParent())
+		{
+			vector parentTransform[4];
+			GetParentTransform(parentTransform);
+			Math3D.MatrixMultiply4(parentTransform, transform, transform);
+		}
+	}
+#endif
+
+};
+
+#endif

+ 120 - 0
Scripts/3_game/billboardset.c

@@ -0,0 +1,120 @@
+class BillboardSetHandler
+{
+	protected bool 							m_BillboardSetIndex 	= -1;
+	protected ref array<ref BillboardSet> 	m_BillboardSets;
+	protected static const string 			ROOT_CLASS = "BillboardPresets";
+	protected static int 					m_SetIndexCached = -1;//once we resolve the name into an index, we cache it(this disallows dynamic index swapping during mission's runtime)
+	
+	string GetTextureByType(string type)
+	{
+		if (m_BillboardSetIndex == -1)
+			return "";
+		BillboardSet bbset = m_BillboardSets.Get(m_BillboardSetIndex);
+		return bbset.GetTextureByType(type);
+	}
+
+	void OnRPCIndex(int index)
+	{
+		if (!m_BillboardSets)
+			LoadBillboardConfigs();
+						
+		if (m_BillboardSets && m_BillboardSets.IsValidIndex(index))
+		{
+			m_BillboardSetIndex = index;
+		}
+	}
+	
+	protected bool LoadBillboardConfigs()
+	{
+		m_BillboardSets = new array<ref BillboardSet>();
+		
+		int setCount = g_Game.ConfigGetChildrenCount(ROOT_CLASS);
+
+		for (int setIndex = 0; setIndex < setCount; setIndex++)
+		{
+			string setName;
+			GetGame().ConfigGetChildName(ROOT_CLASS, setIndex, setName);
+			string path = ROOT_CLASS + " " + setName;
+			m_BillboardSets.Insert(new BillboardSet(path));
+		}
+		
+		return true; 
+	}
+	
+	static bool ActivateBillboardSet(string setClassName, PlayerIdentity identity)
+	{
+		if (!g_Game)
+			return false;
+		
+		if (m_SetIndexCached == -1)
+		{
+			int setCount = g_Game.ConfigGetChildrenCount(ROOT_CLASS);
+			for (int setIndex = 0; setIndex < setCount; setIndex++)
+			{
+				string setName;
+				GetGame().ConfigGetChildName(ROOT_CLASS, setIndex, setName);
+				
+				if (setName == setClassName)
+				{
+					m_SetIndexCached = setIndex;
+					break
+				}
+			}
+		}
+		
+		if (m_SetIndexCached != -1)
+		{
+			auto param = new Param1<int>(m_SetIndexCached);
+			GetGame().RPCSingleParam( identity.GetPlayer(), ERPCs.RPC_SET_BILLBOARDS, param, true, identity );
+			return true;
+		}
+		return false;
+	}
+}
+
+
+class BillboardSet
+{
+	protected ref map<string, string> m_TypeTextureMapping = new map<string, string>();
+	
+	void BillboardSet(string path)
+	{
+		LoadConfig(path);
+	}
+	
+	string GetTextureByType(string type)
+	{
+		return m_TypeTextureMapping.Get(type);
+	}
+
+	protected void LoadConfig(string path)
+	{
+		int count = g_Game.ConfigGetChildrenCount(path);
+		for ( int i = 0; i < count; i++ )
+		{
+			string itemName;
+			GetGame().ConfigGetChildName(path, i, itemName);
+			
+			string typesPath = path + " " + itemName + " types";
+			string texturePath = path + " " + itemName + " texture";
+			
+			if (GetGame().ConfigIsExisting(typesPath) && GetGame().ConfigIsExisting(texturePath))
+			{
+				TStringArray types = new TStringArray();
+				string texture;
+				GetGame().ConfigGetText(texturePath, texture);
+				GetGame().ConfigGetTextArray(typesPath, types);
+				
+				foreach (string s: types)
+				{
+					m_TypeTextureMapping.Insert(s,texture);
+				}
+			}
+			else
+			{
+				ErrorEx("Billboard set incorrect configuration, type or texture param missing: " + path);
+			}
+			
+		}
+	}
+}

+ 131 - 0
Scripts/3_game/bleedchancedata.c

@@ -0,0 +1,131 @@
+typedef map<int,float> BleedChanceMaxMap; //<bloodDamageReceived,chanceMax>
+
+//! Static data of bleeding chance probabilities; currently used for melee only
+class BleedChanceData : Managed
+{
+	private static const float BLOOD_HITPOINTS_UNIVERSAL = 100.0;
+	
+	private static ref map<string, ref BleedChanceMaxMap> m_DamageTypeMap;
+	
+	static void InitBleedChanceData()
+	{
+		m_DamageTypeMap = new map<string,ref BleedChanceMaxMap>();
+		
+		InitMeleeChanceMap();
+		InitInfectedChanceMap();
+	}
+	
+	static void InitMeleeChanceMap()
+	{
+		if (m_DamageTypeMap.Contains("Melee"))
+			ErrorEx("'Melee' damage type bleed chances already initialized!");
+		
+		BleedChanceMaxMap bleedChanceMaxMap = new BleedChanceMaxMap();
+		
+		//keys have to be integers, recalculated later
+		bleedChanceMaxMap.Set(0,0.0);
+		bleedChanceMaxMap.Set(10,5.0);
+		bleedChanceMaxMap.Set(20,15.0);
+		bleedChanceMaxMap.Set(30,23.4);
+		bleedChanceMaxMap.Set(40,31.2);
+		bleedChanceMaxMap.Set(50,39.0);
+		bleedChanceMaxMap.Set(60,46.8);
+		bleedChanceMaxMap.Set(70,54.6);
+		bleedChanceMaxMap.Set(80,62.4);
+		bleedChanceMaxMap.Set(90,70.2);
+		bleedChanceMaxMap.Set(BLOOD_HITPOINTS_UNIVERSAL,100.0);
+		
+		m_DamageTypeMap.Set("Melee",bleedChanceMaxMap);
+	}
+	
+	static void InitInfectedChanceMap()
+	{
+		if (m_DamageTypeMap.Contains("Infected"))
+			ErrorEx("'Infected' damage type bleed chances already initialized!");
+		
+		BleedChanceMaxMap bleedChanceMaxMap = new BleedChanceMaxMap();
+		
+		//keys have to be integers, recalculated later
+		bleedChanceMaxMap.Set(0,0.0);
+		bleedChanceMaxMap.Set(10,5.0);
+		bleedChanceMaxMap.Set(20,15.0);
+		bleedChanceMaxMap.Set(30,27.5);
+		bleedChanceMaxMap.Set(40,40.0);
+		bleedChanceMaxMap.Set(50,55.0);
+		bleedChanceMaxMap.Set(60,60.0);
+		bleedChanceMaxMap.Set(70,70.0);
+		bleedChanceMaxMap.Set(80,75.0);
+		bleedChanceMaxMap.Set(90,85.0);
+		bleedChanceMaxMap.Set(BLOOD_HITPOINTS_UNIVERSAL,100.0);
+		
+		m_DamageTypeMap.Set("Infected",bleedChanceMaxMap);
+	}
+	
+	static void Cleanup()
+	{
+		delete m_DamageTypeMap;
+	}
+	
+	//! returns 'false' when damageType is unhandled
+	static bool CalculateBleedChance(string damageType, float bloodDamage, float bleedThreshold, out float bleedChance)
+	{
+		map<int,float> bleedChanceMap = m_DamageTypeMap.Get(damageType);
+		if (!bleedChanceMap)
+			return false;
+		
+		float armor = bloodDamage / BLOOD_HITPOINTS_UNIVERSAL;
+		float valueHigher = Math.Max(bleedThreshold,armor) * BLOOD_HITPOINTS_UNIVERSAL;
+		float valueLower = Math.Min(bleedThreshold,armor) * BLOOD_HITPOINTS_UNIVERSAL;
+		
+		#ifdef ENABLE_LOGGING
+		if (LogManager.IsBleedingChancesLogEnable())
+		{	
+			Debug.BleedingChancesLog(armor.ToString(), "BleedChanceData" , "n/a", "armor:");
+			Debug.BleedingChancesLog(bleedThreshold.ToString(), "BleedChanceData" , "n/a", "bleedThreshold:");
+		}
+		#endif
+		
+		//unexpected values, unhandled
+		if (valueLower > BLOOD_HITPOINTS_UNIVERSAL)
+		{
+			bleedChance = 1.0;
+			
+			#ifdef ENABLE_LOGGING
+			if (LogManager.IsBleedingChancesLogEnable())
+			{	
+				Debug.BleedingChancesLog(bleedChance.ToString(), "BleedChanceData" , "n/a", "Unhandleed values, default bleeding chance used:");
+			}
+			#endif
+			
+			return true;
+		}
+		
+		if (bleedChanceMap.Contains(valueLower))
+		{
+			bleedChance = bleedChanceMap.Get(valueLower) * valueHigher / 10000;
+		}
+		else
+		{
+			float chanceMaxActual;
+			
+			float floor = Math.Floor(valueLower / 10) * 10;
+			float ceil = Math.Ceil(valueLower / 10) * 10;
+			float pos = Math.InverseLerp(floor,ceil,valueLower);
+			
+			float chanceMin = bleedChanceMap.Get(floor);
+			float chanceMax = bleedChanceMap.Get(ceil);
+			
+			chanceMaxActual = Math.Lerp(chanceMin,chanceMax,pos);
+			bleedChance = valueHigher * chanceMaxActual / 10000;
+		}
+		
+		#ifdef ENABLE_LOGGING
+		if (LogManager.IsBleedingChancesLogEnable())
+		{	
+			Debug.BleedingChancesLog(bleedChance.ToString(), "BleedChanceData" , "n/a", "bleeding chance:");
+		}
+		#endif
+		
+		return true;
+	}
+}

+ 90 - 0
Scripts/3_game/canvas.c

@@ -0,0 +1,90 @@
+/*!
+Simple debug painting canvas with 0/1 pixel representation.
+Usage:
+	Canvas c = new Canvas(100,100);
+	for(int i = 0; i < 100;i++)
+	{
+		float val = i/100;
+		float y = Easing.EaseInOutExpo(val);
+		c.DrawPixel(i,y*100);
+	}
+	c.SaveToFile("output");
+*/
+
+typedef bool PIXEL;
+class Canvas
+{
+	int m_SizeX; int m_SizeY;
+	
+	ref array<ref array<PIXEL>> m_Pixels = new array<ref array<PIXEL>>;
+	
+	void Canvas(int size_x, int size_y)
+	{
+		m_SizeX = size_x;
+		m_SizeY = size_y;
+		for(int i = 0; i < size_y; i++)
+		{
+			array<PIXEL> x_line = new array<PIXEL>;
+			for(int z = 0; z < size_x;z++)
+			{
+				x_line.Insert(false);
+			}
+			m_Pixels.Insert(x_line);
+			
+		}
+	}
+	
+	void DrawPixel(int x, int y)
+	{
+		if((x > m_SizeX - 1) || (y > m_SizeY - 1))
+			return;
+		//Print("x:" +x+",y:"+y);
+		m_Pixels.Get(y).InsertAt(true, x);
+	}
+	
+	void PrintOut()
+	{
+		string line = "";
+		int y_lines = m_SizeY - 1;
+		for(int i = y_lines; i >= 0; i--)
+		{
+			line = "";
+			for(int z = 0; z < m_SizeX;z++)
+			{
+				if(m_Pixels.Get(i).Get(z))
+				{
+					line += "X";
+				}
+				else
+				{
+					line += " ";
+				}
+			}
+			Print(line);
+		}
+	}
+	
+	void SaveToFile(string filename)
+	{
+		FileHandle file = OpenFile("$profile:"+filename, FileMode.WRITE);
+		
+		string line = "";
+		int y_lines = m_SizeY - 1;
+		for(int i = y_lines; i >= 0; i--)
+		{
+			line = "";
+			for(int z = 0; z < m_SizeX;z++)
+			{
+				if(m_Pixels.Get(i).Get(z))
+				{
+					line += "X";
+				}
+				else
+				{
+					line += " ";
+				}
+			}
+			FPrintln(file, line);
+		}
+	}
+}

+ 768 - 0
Scripts/3_game/ce/centraleconomy.c

@@ -0,0 +1,768 @@
+
+/** @file */
+
+// -------------------------------------------------------------------------
+// object (SF) Spawn Flags (use to setup behavior and/ or trigger functionality)
+//
+const int ECE_NONE							= 0;
+	
+const int ECE_SETUP							= 2;	// process full entity setup (when creating NEW entity)
+const int ECE_TRACE							= 4;	// trace under entity when being placed (from the point of creation)
+const int ECE_CENTER						= 8;	// use center from shape (model) for placement
+
+const int ECE_UPDATEPATHGRAPH				= 32;	// update navmesh when object placed upon it
+
+const int ECE_ROTATIONFLAGS					= 512;	// enable rotation flags for object placement
+const int ECE_CREATEPHYSICS					= 1024;	// create collision envelope and related physics data (if object has them)
+const int ECE_INITAI						= 2048; // init ai
+const int ECE_AIRBORNE						= 4096;	// create flying unit in the air
+
+const int ECE_EQUIP_ATTACHMENTS				= 8192;		// equip with configured ATTACHMENTS
+const int ECE_EQUIP_CARGO					= 16384;	// equip with configured CARGO
+const int ECE_EQUIP							= 24576;	// equip with configured (ATTACHMENTS + CARGO)
+const int ECE_EQUIP_CONTAINER				= 2097152;	// populate DE/ group CONTAINER during spawn
+const int ECE_LOCAL							= 1073741824; // create object locally
+
+const int ECE_NOSURFACEALIGN				= 262144;	// do not align object on surface/ terrain
+const int ECE_KEEPHEIGHT					= 524288;	// keep height when creating object (do not use trace or placement on surface)
+
+const int ECE_NOLIFETIME					= 4194304;	// do not set lifetime when creating the object
+const int ECE_NOPERSISTENCY_WORLD			= 8388608;	// do not save this object in world
+const int ECE_NOPERSISTENCY_CHAR			= 16777216;	// do not save this object in character
+const int ECE_DYNAMIC_PERSISTENCY			= 33554432;	// spawns in without persistency, once player takes it, persistency will be enabled if available
+
+// note: use predefined combination when not solving something specific
+//
+const int ECE_IN_INVENTORY					= 787456;	// ECE_CREATEPHYSICS|ECE_KEEPHEIGHT|ECE_NOSURFACEALIGN
+const int ECE_PLACE_ON_SURFACE				= 1060;		// ECE_CREATEPHYSICS|ECE_UPDATEPATHGRAPH|ECE_TRACE
+const int ECE_OBJECT_SWAP					= 787488;	// ECE_CREATEPHYSICS|ECE_UPDATEPATHGRAPH|ECE_KEEPHEIGHT|ECE_NOSURFACEALIGN
+
+const int ECE_FULL							= 25126;	// ECE_SETUP|ECE_TRACE|ECE_ROTATIONFLAGS|ECE_UPDATEPATHGRAPH|ECE_EQUIP
+
+// -------------------------------------------------------------------------
+// object (RF) Rotation Flags (use to force and/ or invoke placement rotation)
+//
+const int	RF_NONE					= 0;
+
+const int	RF_FRONT				= 1;	// front side placement
+const int	RF_TOP					= 2;	// top side placement
+const int	RF_LEFT					= 4;	// left side placement
+const int	RF_RIGHT				= 8;	// right side placement
+const int	RF_BACK					= 16;	// back side placement
+const int	RF_BOTTOM				= 32;	// bottom side placement
+
+const int	RF_ALL					= 63;	// RF_FRONT|RF_TOP|RF_LEFT|RF_RIGHT|RF_BACK|RF_BOTTOM
+
+const int	RF_IGNORE				= 64;	// ignore placement RF flags - object will spawn as model was created
+
+const int	RF_TOPBOTTOM			= 34;	// RF_TOP|RF_BOTTOM
+const int	RF_LEFTRIGHT			= 12;	// RF_LEFT|RF_RIGHT
+const int	RF_FRONTBACK			= 17;	// RF_FRONT|RF_BACK
+
+const int	RF_RANDOMROT			= 64;	// allow random rotation around axis when placing
+const int	RF_ORIGINAL				= 128;	// use default placement setuped on object in config
+const int	RF_DECORRECTION			= 256;	// angle correction when spawning InventoryItem at Building angle
+const int	RF_DEFAULT				= 512;	// use default placement setuped on object in config
+
+// -------------------------------------------------------------------------
+//! Categories for CEApi.EconomyLog
+class EconomyLogCategories
+{
+	private void EconomyLogCategories();
+	private void ~EconomyLogCategories();
+	
+	const string Economy				= "economy";
+	const string EconomyRespawn			= "economy_respawn";
+	const string RespawnQueue			= "respawn_queue";
+	const string Container				= "container";
+	const string Matrix					= "matrix";
+	const string UniqueLoot				= "uniqueloot";
+	const string Bind					= "bind";
+	const string SetupFail				= "setupfail";
+	const string Storage				= "storage";
+	const string Classes				= "class";
+	const string Category				= "category";
+	const string Tag					= "tag";
+	const string SCategory				= "s_category";
+	const string STag					= "s_tag";
+	const string SAreaflags				= "s_areaflags";
+	const string SCrafted				= "s_crafted";
+	const string MapGroup				= "map_group";
+	const string MapComplete			= "map_complete";
+	const string InfectedZone			= "infected_zone";
+}
+
+// -------------------------------------------------------------------------
+//! Special strings for CEApi.EconomyMap
+class EconomyMapStrings
+{
+	private void EconomyMapStrings();
+	private void ~EconomyMapStrings();
+	
+	/**
+	\brief Generates string that will make CEApi.EconomyMap use all items with this category
+	\note This is refering to the CE categories of loot defined in cfglimitsdefinition.xml
+	\warning This is persistent per session, when you set it, it will persist until it is set to something else
+		\param category \p string The desired loot category
+		\return \p string The string to pass into CEApi.EconomyMap
+	@code
+		GetCEApi().EconomyMap(EconomyMapStrings.Category("food"));
+	@endcode
+	*/
+	static string Category(string category)
+	{
+		return string.Format("category:%1", category);
+	}
+	
+	/**
+	\brief Generates string that will make CEApi.EconomyMap use all items with this tag
+	\note This is refering to the CE tags of loot defined in cfglimitsdefinition.xml
+	\warning This is persistent per session, when you set it, it will persist until it is set to something else
+		\param category \p string The desired loot tag
+		\return \p string The string to pass into CEApi.EconomyMap
+	@code
+		GetCEApi().EconomyMap(EconomyMapStrings.Tag("floor"));
+	@endcode
+	*/
+	static string Tag(string tag)
+	{
+		return string.Format("tag:%1", tag);
+	}
+
+	
+	
+	//! Everything
+	const string ALL_ALL = "all:all";
+	//! All loot
+	const string ALL_LOOT = "all:loot";
+	//! All vehicles
+	const string ALL_VEHICLE = "all:vehicle";
+	//! All infected
+	const string ALL_INFECTED = "all:infected";
+	//! All animals
+	const string ALL_ANIMAL = "all:animal";
+	//! All players
+	const string ALL_PLAYER = "all:player";
+	//! All proxies
+	const string ALL_PROXY = "all:proxy";
+	//! All static loot spawns
+	const string ALL_PROXY_STATIC = "all:proxystatic";
+	//! All dynamic loot spawns
+	const string ALL_PROXY_DYNAMIC = "all:proxydynamic";
+	//! All abandoned loot spawns
+	const string ALL_PROXY_ABANDONED = "all:proxyabandoned";
+}
+
+// -------------------------------------------------------------------------
+//! Special strings for CEApi.EconomyOutput
+class EconomyOutputStrings
+{
+	private void EconomyOutputStrings();
+	private void ~EconomyOutputStrings();
+	
+	/**
+	\brief Lists stats regarding which loot spawn) that are linked together and how many there are
+		\note In logs: "[linked_groups]"
+	*/
+	const string LINKS = "links";
+	/**
+	\brief Lists loot spawns that have more loot than their maximum + 4
+		\note In logs: "[autotest:ListSuspiciousGroups]"
+	*/
+	const string SUSPICIOUS = "suspicious";
+	/**
+	\brief Lists DE spawns that have positions that are within supplied range (< fRange, not equal)
+		\note In logs: "[ClosePosition]"
+	*/
+	const string DE_CLOSE_POINT = "declosepoint";
+	/**
+	\brief Lists loot spawns that have been marked as abandoned
+		\note In logs: "[autotest:ListAbandonedGroups]"
+	*/ 
+	const string ABANDONED = "abandoned";
+	/**
+	\brief Lists loot spawns that are not abandoned but have no loot
+		\note In logs: "[autotest:ListEmptyGroups]"
+	*/  
+	const string EMPTY = "empty";
+	/**
+	\brief Lists loot spawns that are not abandoned and within the supplied range  (< fRange, not equal)
+		\note In logs: "[autotest:ListCloseGroups]"
+		\note Is the same as CEApi.ListCloseProxy
+	*/
+	const string CLOSE = "close";
+	/**
+	\brief Lists the number of objects inside of categories
+		\note In logs: "[autotest:ProcessDebugLog]"
+	*/
+	const string WORLD = "world";
+	/**
+	\brief Lists overall CE stats
+		\note In logs: "[autotest:OverallStatus]"
+	*/
+	const string STATUS = "status";
+	/**
+	\brief Lists the maxlootsize of all CE items
+		\note In logs: "[autotest:ListLootSize]"
+	*/
+	const string LOOT_SIZE = "lootsize";
+}
+
+// -------------------------------------------------------------------------
+enum ESpawnVolumeVis
+{
+	OFF = 0,
+	ADAPTIVE,
+	VOLUME,
+	OCCUPIED,
+}
+
+// -------------------------------------------------------------------------
+/**
+	\brief API to interact with Central Economy
+	\note Accessible through GetCEApi, make sure to read the documentation for that as well
+	\note Any mention of 'storage/' means the '$mission:storage_#' folder
+*/
+class CEApi
+{
+	private void CEApi() {}
+	private void ~CEApi() {}
+	
+	/**
+	\brief Regenerates "storage/spawnpoints.bin" if necessary
+	\note Already happens automatically when server starts before it is loaded in
+	@code
+		GetCEApi().ExportSpawnData();
+	@endcode
+	*/
+	proto native void ExportSpawnData();
+	/**
+	\brief Generates "storage/export/mapgrouppos.xml"
+		\param vCenter \p vector Center of area to generate from
+			\note When using a zero vector, this will automatically get the world center
+		\param fRadius \p float Radius in meters of area to generate from
+			\note When 0, this will automatically get a radius covering the map
+	@code
+		// Export for whole map
+		GetCEApi().ExportProxyData();
+	@endcode
+	*/
+	proto native void ExportProxyData( vector vCenter = vector.Zero, float fRadius = 0 );
+	/**
+	\brief Generates "storage/export/mapgroupcluster.xml"
+	@code
+		GetCEApi().ExportClusterData();
+	@endcode
+	*/
+	proto native void ExportClusterData();
+	/**
+	\brief Generates "storage/export/mapgroupproto.xml"
+	@code
+		GetCEApi().ExportProxyProto();
+	@endcode
+	*/
+	proto native void ExportProxyProto();
+	/**
+	\brief Invalidates loot spawn points which are closer than the radius supplied
+		\note Will output a message indicating how many points were invalidated
+		\param fRadius \p float The minimum desired distance in meters between loot spawn points
+			\note When 0 it will use a radius of 0.5
+		\param bAllSelections \p bool When false, will only check the points within a container against each other, when true will against all points
+	@code
+		// Example: I want there to be a minimum distance of 0.3m between any loot spawn point
+		GetCEApi().MarkCloseProxy(0.3, true);
+	@endcode
+	*/
+	proto native void MarkCloseProxy( float fRadius, bool bAllSelections );
+	/**
+	\brief Removes all invalid points
+		\note Is best paired with a MarkCloseProxy call first to invalidate unwanted points
+		\note Will output a message indicating the amount of deleted points
+	@code
+		GetCEApi().RemoveCloseProxy();
+	@endcode
+	*/
+	proto native void RemoveCloseProxy();
+	/**
+	\brief Outputs a list of all loot points closer than specified radius
+	\note This will automatically be checking all points against all points
+	\note This is a better way of handling it than the above two methods, as it can be then be removed manually from the xmls
+	\note Is the same as CEApi.EconomyOutput(EconomyOutputStrings.CLOSE, fRadius)
+		\param fRadius \p float The minimum desired distance in meters between loot spawn points
+	@code
+		GetCEApi().ListCloseProxy(0.3);
+	@endcode
+	*/
+	proto native void ListCloseProxy( float fRadius );
+
+	/**
+	\brief Will emulate the spawning of the item which is being looked at and generate images (.tga) in storage/lmap and output logs
+	\note DEVELOPER/DIAG ONLY
+	\note This will only work if the loot spawner is active
+		\param sClassName \p string The class name of the desired item to analyze
+			\note When using "*" as class name, instead of generating images, it will generate a .csv in storage/log containing the output of all spawnable items
+		\return \p bool Whether the operation was successful, it might fail in certain scenarios if the CE doesn't update in time
+	@code
+		GetCEApi().SpawnAnalyze("FlatCap_Grey");
+	@endcode
+	*/
+	proto native bool SpawnAnalyze( string sClassName );
+
+	/**
+	\brief Subtracts the supplied value from the current lifetime of all items in the world
+	\note Uses RadiusLifetimeDecrease under the hood and then calculates the parameters to fit the world
+	\note Will automatically clamp result between min and max lifetime  [3, 316224000] (3 seconds to 10 years)
+		\param fShift \p float The value in seconds which will be subtracted from the current lifetimes
+	@code
+		// Shortens the lifetimes of all items in the world by 3 seconds
+		GetCEApi().TimeShift(3);
+	@endcode
+	*/
+	proto native void TimeShift( float fShift );
+	/**
+	\brief Fills in the Debug Lifetime, which will be used for any new DE spawned
+		\param fLifeTime \p float The lifetime for any DE spawned after this call
+			\note When this is set back to 0, it will stop using the Debug Lifetime
+	@code
+		// Any DE spawned after this call will have a lifetime of 300 seconds
+		GetCEApi().OverrideLifeTime(300);
+	@endcode
+	*/
+	proto native void OverrideLifeTime( float fLifeTime );
+
+	/**
+	\brief Force spawn specific prototype group + loot at position
+	\note DEVELOPER/DIAG ONLY
+	\note This can also spawn in other CE & DE related objects, but is best used exclusively for testing prototype groups
+		\param sGroupName \p string The group name to spawn
+		\param vPos \p vector The position to spawn the Entity at
+		\param fAngle \p float Angle to spawn the Entity with in degrees [0, 360]
+			\note When a negative value, will pick a random one
+		\return \p Entity The spawned Entity or null if unsuccessful
+	@code
+		GetCEApi().SpawnGroup("Land_Shed_M1", Vector(5, 10, 5));
+	@endcode
+	*/
+	proto native Entity SpawnGroup( string sGroupName, vector vPos, float fAngle = -1 );
+	/**
+	\brief Force spawn specific dynamic event
+	\note DEVELOPER/DIAG ONLY
+	\note Versatile, can be used for Animal, Infected, Static, Item and Vehicle
+	\note Is the only one capable of spawning DE's that have DE Groups
+	\note Is the same as the next one, but has ECE_FULL flags and a hidden flag which overrides herd limit
+	\note This is also FORCE spawn, so it will bypass any limit and avoidance checks
+		\param sEvName \p string The DE to spawn
+		\param vPos \p vector The position to spawn the Entity at
+		\param fAngle \p float Angle to spawn the Entity with in degrees [0, 360]
+			\note When a negative value, will pick a random one
+		\return \p bool Whether the spawn was successful
+	@code
+		GetCEApi().SpawnDE("StaticHeliCrash", Vector(5, 10, 5));
+	@endcode
+	*/
+	proto native void SpawnDE( string sEvName, vector vPos, float fAngle = -1 );
+	/**
+	\brief Force spawn specific dynamic event
+	\note DEVELOPER/DIAG ONLY
+	\note Is the same one as above but with the possibility of custom flags
+		\param sEvName \p string The DE to spawn
+		\param vPos \p vector The position to spawn the Entity at
+		\param fAngle \p float Angle to spawn the Entity with in degrees [0, 360]
+			\note When a negative value, will pick a random one
+		\param uFlags \p int ECE flags to apply while spawning the DE
+		\return \p bool Whether the spawn was successful
+	@code
+		GetCEApi().SpawnDEEx("StaticHeliCrash", Vector(5, 10, 5), ECE_FULL);
+	@endcode
+	*/
+	proto native void SpawnDEEx( string sEvName, vector vPos, float fAngle, int uFlags );
+	/**
+	\brief Spawn an item through CE
+	\note DEVELOPER/DIAG ONLY
+		\param sEvName \p string The DE to spawn
+		\param vPos \p vector The position to spawn the Entity at
+		\param fAngle \p float Angle to spawn the Entity with in degrees [0, 360]
+			\note When a negative value, will pick a random one
+		\param iCount \p int The amount of items
+		\param fRange \p float Circle radius
+			\note When iCount is larger than 1, changing this will make it so that they are spawned in a circle around vPos
+	@code
+		GetCEApi().SpawnLoot("Deagle", Vector(5, 10, 5), 0, 9, 1);
+	@endcode
+	*/
+	proto native void SpawnLoot( string sEvName, vector vPos, float fAngle, int iCount = 1, float fRange = 1 );
+
+	/**
+	\brief Spawn all entities with dynamic category through CE
+	\note DEVELOPER/DIAG ONLY
+	\note Will print additional logs to RPT
+		\param vPos \p vector The position to spawn the Entities at
+			\note This will be the starting position, the items will be split into segments by CE BBox size (smallest to largest)
+		\param bShowCylinders \p bool Whether to draw the CE BBox with debug shapes
+			\note Red: Invalid BBox; Yellow: Not in DB; Green: All ok
+		\param fDefaultDistance \p float The default distance to use when the entity does not have a CE BBox
+			\note This means that all the ones with invalid CE BBoxes will be piled up at the starting position when this is 0
+	@code
+		GetCEApi().SpawnDynamic(Vector(5, 10, 5), true);
+	@endcode
+	*/
+	proto native void SpawnDynamic( vector vPos, bool bShowCylinders = true, float fDefaultDistance = 0 );
+	/**
+	\brief Spawn all entities with vehicles category through CE
+	\note DEVELOPER/DIAG ONLY
+	\note Will print additional logs to RPT
+		\param vPos \p vector The position to spawn the Entities at
+			\note This will be the starting position, vehicles spawn with 20m spacing
+			\note Make sure you do it on a surface as flat and open as possible, they need a lot of space
+		\param bShowCylinders \p bool Does nothing for Vehicles, left for backwards compat
+		\param fDefaultDistance \p float The default distance to use when the entity does not have a CE BBox
+			\note This means that all the ones with invalid CE BBoxes will be piled up at the starting position when this is 0
+	@code
+		GetCEApi().SpawnVehicles(Vector(5, 10, 5));
+	@endcode
+	*/
+	proto native void SpawnVehicles( vector vPos, bool bShowCylinders = false, float fDefaultDistance = 20 );
+	/**
+	\brief Spawn all entities with building category through CE
+	\note DEVELOPER/DIAG ONLY
+	\note Will print additional logs to RPT
+		\param vPos \p vector The position to spawn the Entities at
+			\note This will be the starting position, the items will be split into segments by CE BBox size (smallest to largest)
+		\param bShowCylinders \p bool Whether to draw the CE BBox with debug shapes
+			\note Red: Invalid BBox; Yellow: Not in DB; Green: All ok
+			\note These will most likely just always be red
+		\param fDefaultDistance \p float The default distance to use when the entity does not have a CE BBox
+			\note This means that all the ones with invalid CE BBoxes will be piled up at the starting position when this is 0
+	@code
+		GetCEApi().SpawnBuilding(Vector(5, 10, 5), true);
+	@endcode
+	*/
+	proto native void SpawnBuilding( vector vPos, bool bShowCylinders = false, float fDefaultDistance = 20 );
+
+	/**
+	\brief Spawn an entity through CE
+	\note DEVELOPER/DIAG ONLY
+	\note Is similar to SpawnLoot, but works better on Animal/Infected/Vehicle
+		\param sClassName \p string The entity to spawn
+		\param vPos \p vector The position to spawn the Entity at
+		\param fRange \p float Circle radius
+			\note When iCount is larger than 1, changing this will make it so that they are spawned in a circle around vPos
+		\param iCount \p int The amount of items
+	@code
+		GetCEApi().SpawnEntity("Deagle", Vector(5, 10, 5), 1, 9);
+	@endcode
+	*/
+	proto native void SpawnEntity( string sClassName, vector vPos, float fRange, int iCount );
+	/**
+	\brief Spawn an entity through CE
+	\note DEVELOPER/DIAG ONLY
+	\note Is the same as SpawnEntity, but spawns only one and returns the spawned Object
+		\param sClassName \p string The entity to spawn
+		\param vPos \p vector The position to spawn the Entity at
+		\return \p Object The spawned Object
+	@code
+		GetCEApi().SpawnSingleEntity("Deagle", Vector(5, 10, 5));
+	@endcode
+	*/
+	proto native Object SpawnSingleEntity( string sClassName, vector vPos );
+	/**
+	\brief Spawn an entity through CE
+	\note DEVELOPER/DIAG ONLY
+	\note Is the same as SpawnEntity, under the hood it just defaults to RF_ORIGINAL
+		\param sClassName \p string The entity to spawn
+		\param vPos \p vector The position to spawn the Entity at
+		\param fRange \p float Circle radius
+			\note When iCount is larger than 1, changing this will make it so that they are spawned in a circle around vPos
+		\param iCount \p int The amount of items
+		\param iFlags \p int The rotation flags to apply
+	@code
+		GetCEApi().SpawnRotation("Deagle", Vector(5, 10, 5), 1, 9, RF_ALL);
+	@endcode
+	*/
+	proto native void SpawnRotation( string sClassName, vector vPos, float fRange, int iCount, int iFlags );
+	/**
+	\brief Spawn an entity through CE, x amount of times in a grid
+	\note DEVELOPER/DIAG ONLY
+	\note The name may imply it does something else, but a profiler is needed to actually benchmark it
+	\note The position starts at 0 0 0
+		\param sClassName \p string The entity to spawn
+		\param iCount \p int The amount of items
+	@code
+		GetCEApi().SpawnPerfTest("Deagle", 30);
+	@endcode
+	*/
+	proto native void SpawnPerfTest( string sClassName, int iCount );
+	
+	/**
+	\brief Queue up the depleting of lifetime of everything in the world
+	\note DEVELOPER/DIAG ONLY
+	@code
+		GetCEApi().CleanMap();
+	@endcode
+	*/
+	proto native void CleanMap();
+
+	/**
+	\brief Outputs debug file to storage/log/*.csv
+	\note DEVELOPER/DIAG ONLY
+		\param sLogType \p string The type of log (EconomyLogCategories)
+	@code
+		GetCEApi().EconomyLog(EconomyLogCategories.Economy);
+	@endcode
+	*/
+	proto native void EconomyLog( string sLogType );
+	
+	/**
+	\brief Outputs debug file to storage/lmap/*.tga showing the current places this is spawned
+	\note DEVELOPER/DIAG ONLY
+	\note This works best when you have an image of the map to overlay the tga with afterwards
+		\param sMapType \p string The type of lmap, can be just a class name or a special string
+			\note There are several prefixes and sets of strings that can be passed in here, see EconomyMapStrings
+	@code
+		// To check only a specific item
+		GetCEApi().EconomyMap("Deagle");
+	@endcode
+	*/
+	proto native void EconomyMap( string sMapType );
+	/**
+	\brief Outputs debug logs into server log or rpt
+	\note DEVELOPER/DIAG ONLY
+		\param sOutputType \p string One of the strings specified in EconomyOutputStrings
+		\param fRange \p float Range parameter used for some of the options
+	@code
+		GetCEApi().EconomyOutput(EconomyOutputStrings.CLOSE, 3);
+	@endcode
+	*/
+	proto native void EconomyOutput( string sOutputType, float fRange );
+
+	/**
+	\brief Process lifetime increase within radius by value (sec)
+	\note Will automatically clamp result between min and max lifetime  [3, 316224000] (3 seconds to 10 years)
+		\param vCenter \p vector The center point
+		\param fRadius \p float The radius around the center point
+		\param fValue \p float The value to increase the lifetime by
+			\note When 0, this will reset it to default instead (but it's better to use RadiusLifetimeReset still)
+	@code
+		GetCEApi().RadiusLifetimeIncrease(Vector(500, 0, 500), 3, 500);
+	@endcode
+	*/
+	proto native void RadiusLifetimeIncrease( vector vCenter, float fRadius, float fValue );
+	/**
+	\brief Process lifetime decrease within radius by value (sec)
+	\note Will automatically clamp result between min and max lifetime  [3, 316224000] (3 seconds to 10 years)
+		\param vCenter \p vector The center point
+		\param fRadius \p float The radius around the center point
+		\param fValue \p float The value to decrease the lifetime by
+	@code
+		GetCEApi().RadiusLifetimeDecrease(Vector(500, 0, 500), 3, 500);
+	@endcode
+	*/
+	proto native void RadiusLifetimeDecrease( vector vCenter, float fRadius, float fValue );
+	/**
+	\brief Process lifetime reset to default value from DB within radius
+		\param vCenter \p vector The center point
+		\param fRadius \p float The radius around the center point
+	@code
+		GetCEApi().RadiusLifetimeReset(Vector(500, 0, 500), 3);
+	@endcode
+	*/
+	proto native void RadiusLifetimeReset( vector vCenter, float fRadius );
+	
+	
+	
+	/** \name Globals API
+		Get values from globals.xml
+	*/
+	//@{
+	
+	/**
+	\brief Get int from globals.xml
+	\note type="0"
+		\param varName \p string The name of the entry
+		\return \p int The value or int.MIN if not found/not an int
+	*/
+	proto native int GetCEGlobalInt(string varName);
+	/**
+	\brief Get float from globals.xml
+	\note type="1"
+		\param varName \p string The name of the entry
+		\return \p float The value or float.MIN if not found/not a float
+	*/
+	proto native float GetCEGlobalFloat(string varName);
+	/**
+	\brief Get string from globals.xml
+	\note type="2"
+		\param varName \p string The name of the entry
+		\return \p string The value or empty string if not found/not a string
+	*/
+	proto native string GetCEGlobalString(string varName);
+	
+	//@}
+	
+	
+	
+	/** \name Avoidance API
+		Optimized internal methods that the CE uses to avoid spawning DE within certain distances
+	*/
+	//@{
+	
+	/**
+	\brief Check if there is a player within a radius
+		\param vPos \p vector The center point
+		\param fDistance \p float The radius around the center point
+		\return \p bool Returns false when there is a player inside supplied area, true when it successfully avoided players
+	@code
+		GetCEApi().AvoidPlayer(Vector(500, 0, 500), 20);
+	@endcode
+	*/
+	proto native bool AvoidPlayer(vector vPos, float fDistance); // return false when there is a player
+	/**
+	\brief Check if there is a vehicle within a radius
+		\param vPos \p vector The center point
+		\param fDistance \p float The radius around the center point
+		\param sDEName \p string A specific DE to avoid, if left empty, will avoid all vehicles
+		\return \p bool Returns false when there is a vehicle inside supplied area, true when it successfully avoided vehicles
+	@code
+		GetCEApi().AvoidVehicle(Vector(500, 0, 500), 500, "VehicleCivilianSedan");
+	@endcode
+	*/
+	proto native bool AvoidVehicle(vector vPos, float fDistance, string sDEName = "");
+	/**
+	\brief Check if there is a vehicle within a radius
+		\param vPos \p vector The center point
+		\param fRange \p float The radius around the center point
+		\return \p int The amoutn of players inside supplied area
+	@code
+		GetCEApi().CountPlayersWithinRange(Vector(500, 0, 500), 500);
+	@endcode
+	*/
+	proto native int CountPlayersWithinRange(vector vPos, float fRange);
+	
+	//@}
+	
+	
+	
+	/** \name CE Debug menu Script API
+		DIAG ONLY: These options are available from the in-game debug menu on Diag exe (Game > Central Economy), documentation can be found on wiki
+	*/
+	//@{
+	
+	// "Loot Spawn Edit"
+	//{	
+		//! "Spawn Volume Vis"
+		proto native void LootSetSpawnVolumeVisualisation(ESpawnVolumeVis mode);
+		//! "Setup Vis"
+		proto native void LootToggleSpawnSetup(bool mode);
+		//! "Edit Volume"
+		proto native void LootToggleVolumeEditing(bool mode);
+		//! "Re-Trace Group Points"
+		proto native void LootRetraceGroupPoints();
+		//! "Export Group >>"
+		proto native void LootExportGroup();
+		//! "Export All Groups >>>>" / GetCEApi.ExportProxyProto();
+		proto native void LootExportAllGroups();
+		//! "<<< Export Map" / GetCEApi.ExportProxyData(vector.Zero, 0);
+		proto native void LootExportMap();
+		//! "<<< Export Clusters" / GetCEApi().ExportClusterData()
+		proto native void LootExportClusters();
+	//}
+
+	// "Loot Tool"
+	//{
+		//! "Deplete Lifetime"
+		proto native void LootDepleteLifetime();
+		//! "Set Damage = 1.0"
+		proto native void LootSetDamageToOne();
+		//! "Damage + Deplete"
+		proto native void LootDepleteAndDamage();
+	//}
+
+	// "Infected"
+	//{
+		//! "Infected Vis"
+		proto native void InfectedToggleVisualisation(bool mode);
+		//! "Infected Zone Info"
+		proto native void InfectedToggleZoneInfo(bool mode);
+		//! "Infected Spawn"
+		proto native void InfectedSpawn();
+		//! "Reset Cleanup"
+		proto native void InfectedResetCleanup();
+	//}
+
+	// "Animal"
+	//{
+		//! "Animal Vis"
+		proto native void AnimalToggleVisualisation(bool mode);
+		//! "Animal Spawn"
+		proto native void AnimalSpawn();
+		//! "Ambient Spawn"
+		proto native void AnimalAmbientSpawn();
+	//}
+
+	//! "Vehicle&Wreck Vis"
+	proto native void ToggleVehicleAndWreckVisualisation(bool mode);
+	//! "Loot Vis"
+	proto native void ToggleLootVisualisation(bool mode);
+	//! "Cluster Vis"
+	proto native void ToggleClusterVisualisation(bool mode);
+
+	//! "Dynamic Events Status"
+	proto native void ToggleDynamicEventStatus(bool mode);
+	//! "Dynamic Events Vis"
+	proto native void ToggleDynamicEventVisualisation(bool mode);
+	//! "Dynamic Events Spawn"
+	proto native void DynamicEventSpawn();
+	//! "Export Dyn Event >>"
+	proto native void DynamicEventExport();
+	
+	//! "Overall Stats"
+	proto native void ToggleOverallStats(bool mode);
+	
+	//@}
+	
+	
+	
+	/** \name DEPRECATED/LEGACY
+		These don't do anything anymore but are left for backwards compatibility
+	*/
+	//@{
+
+	proto native void PlatformStatTest();
+	
+	proto native void LootToggleProxyEditing(bool mode);
+	
+	proto native void OnUpdate();
+	
+	//@}
+};
+
+/**
+	\brief Get the CE API
+	\warning Only exists when the game has CE enabled
+	\note This means that this will work on anything which is running a mission with an initialized Hive
+	\note Client does not have Hive when connected to a server, only the server does if it was set up in the init.c
+*/
+proto native CEApi GetCEApi();
+
+// -------------------------------------------------------------------------
+class CEItemProfile
+{
+	private void CEItemProfile() {}
+	private void ~CEItemProfile() {}
+	
+	proto native int GetNominal(); // nominal - how many items should be aproximately in map
+	proto native int GetMin(); // min - minimal count should be available in map
+
+	proto native float GetQuantityMin(); // min quantity (0.0 - 1.0) (like ammobox - this determine how many bullets are there, or water bottle)
+	proto native float GetQuantityMax(); // max quantity (0.0 - 1.0) (like ammobox - this determine how many bullets are there, or water bottle)
+
+	proto native float GetQuantity(); // random quantity (0.0 - 1.0)
+
+	proto native float GetLifetime(); // maximum lifetime in (seconds) - what is the idle before item abandoned at ground gets deleted
+	proto native float GetRestock(); // restock is oposite of lifetime - idle before item is allowed to respawn when required
+
+	proto native int GetCost(); // cost of item determines its 'value' for players (this serve as priority during respawn and cleanup operation)
+
+	proto native int GetUsageFlags(); // area usage flags (each bit has assigned group - which as part of map overlay effectively affects spawning)
+	proto native int GetValueFlags(); // area value flags (each bit has assigned group - which as part of map overlay effectively affects spawning)
+};

+ 354 - 0
Scripts/3_game/cfggameplaydatajson.c

@@ -0,0 +1,354 @@
+//!contents of this class will be transfered to client upon connecting, with the variables in either initial state as set through the 'InitServer..()' call, or replaced with contents of the json configuration file if such file is both present and reading is enabled in server.cfg
+class CfgGameplayJson
+{
+	int version = -1;
+	
+	//! Obsolete, 'InitServer' on individual json items is now called centrally
+	void InitServer()
+	{
+	}
+	
+	//-------------------------------------------------------------------------------------------------
+	
+	
+	//!!! all member variables must correspond with the cfggameplay.json file contents !!!!
+	ref ITEM_GeneralData GeneralData			= new ITEM_GeneralData;
+	ref ITEM_PlayerData PlayerData 				= new ITEM_PlayerData;
+	ref ITEM_WorldData WorldsData 				= new ITEM_WorldData;
+	ref ITEM_BaseBuildingData BaseBuildingData 	= new ITEM_BaseBuildingData;
+	ref ITEM_UIData UIData 						= new ITEM_UIData;
+	ref ITEM_MapData MapData 					= new ITEM_MapData;
+	
+};
+
+class ITEM_DataBase
+{
+	void ITEM_DataBase()
+	{
+		#ifdef SERVER
+		CfgGameplayHandler.RegisterItem(this);
+		#endif
+	}
+	
+	bool ValidateServer()
+	{
+		return true;
+	}
+	
+	void InitServer();
+}
+
+class ITEM_GeneralData : ITEM_DataBase
+{
+	override void InitServer()
+	{
+		disableBaseDamage = GetGame().ServerConfigGetInt( "disableBaseDamage" );
+		disableContainerDamage = GetGame().ServerConfigGetInt( "disableContainerDamage" );
+		disableRespawnDialog = GetGame().ServerConfigGetInt("disableRespawnDialog");
+	}
+	
+	override bool ValidateServer()
+	{
+		return true;
+	}
+	//-------------------------------------------------------------------------------------------------
+	//!!! all member variables must correspond with the cfggameplay.json file contents !!!!
+	bool disableBaseDamage;
+	bool disableContainerDamage;
+	bool disableRespawnDialog;
+	bool disableRespawnInUnconsciousness;
+
+};
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------
+
+class ITEM_PlayerData : ITEM_DataBase
+{
+	ref ITEM_StaminaData StaminaData			 	= new ITEM_StaminaData;
+	ref ITEM_ShockHandlingData ShockHandlingData 	= new ITEM_ShockHandlingData;
+	ref ITEM_MovementData MovementData 				= new ITEM_MovementData;
+	ref ITEM_DrowningData DrowningData 				= new ITEM_DrowningData;
+	
+	override void InitServer()
+	{
+		disablePersonalLight = GetGame().ServerConfigGetInt( "disablePersonalLight" );
+	}
+	
+	override bool ValidateServer()
+	{
+		return true;
+	}
+	
+	//-------------------------------------------------------------------------------------------------
+	//!!! all member variables must correspond with the cfggameplay.json file contents !!!!
+	bool disablePersonalLight;
+	bool disable2dMap;
+	ref TStringArray spawnGearPresetFiles;
+
+};
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------
+
+class ITEM_ShockHandlingData : ITEM_DataBase
+{
+	override void InitServer()
+	{
+	}
+	
+	override bool ValidateServer()
+	{
+		return true;
+	}
+	
+	//-------------------------------------------------------------------------------------------------
+	//!!! all member variables must correspond with the cfggameplay.json file contents !!!!
+	float shockRefillSpeedConscious = PlayerConstants.SHOCK_REFILL_CONSCIOUS_SPEED;
+	float shockRefillSpeedUnconscious = PlayerConstants.SHOCK_REFILl_UNCONSCIOUS_SPEED;
+	bool allowRefillSpeedModifier = true;
+};
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------
+
+class ITEM_StaminaData : ITEM_DataBase
+{
+	override void InitServer()
+	{
+	}
+	
+	override bool ValidateServer()
+	{
+		return true;
+	}
+	
+	//-------------------------------------------------------------------------------------------------
+	//!!! all member variables must correspond with the cfggameplay.json file contents !!!!
+	float staminaWeightLimitThreshold = GameConstants.STAMINA_WEIGHT_LIMIT_THRESHOLD;
+	float staminaMax = GameConstants.STAMINA_MAX;
+	float staminaKgToStaminaPercentPenalty = GameConstants.STAMINA_KG_TO_STAMINAPERCENT_PENALTY;
+	float staminaMinCap = GameConstants.STAMINA_MIN_CAP;
+	float sprintStaminaModifierErc = 1;//consumption of stamina during standing sprint modification
+	float sprintStaminaModifierCro = 1;//consumption of stamina during crouched sprint modification
+	float sprintSwimmingStaminaModifier = 1;//consumption of stamina during swimming sprint modification
+	float sprintLadderStaminaModifier = 1;//consumption of stamina during climbing sprint modification
+	float meleeStaminaModifier = 1;//consumption of stamina during melee attacks and evasion modification
+	float obstacleTraversalStaminaModifier = 1;// vaulting and climbing stamina consumption modification
+	float holdBreathStaminaModifier = 1;// hold breath  stamina consumption modification
+};
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------
+
+class ITEM_MovementData : ITEM_DataBase
+{
+	override void InitServer()
+	{
+	}
+	
+	override bool ValidateServer()
+	{
+		return true;
+	}
+	
+	//-------------------------------------------------------------------------------------------------
+	//!!! all member variables must correspond with the cfggameplay.json file contents !!!!
+	float timeToStrafeJog  		= 0.1;
+	float rotationSpeedJog   	= 0.15;
+	float timeToSprint			= 0.45;
+	float timeToStrafeSprint 	= 0.3;
+	float rotationSpeedSprint	= 0.15;
+	bool allowStaminaAffectInertia = 1;
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------
+
+class ITEM_WorldData : ITEM_DataBase
+{
+	override void InitServer()
+	{
+		lightingConfig = GetGame().ServerConfigGetInt( "lightingConfig" );
+		wetnessWeightModifiers = {GameConstants.WEIGHT_DRY,GameConstants.WEIGHT_DAMP,GameConstants.WEIGHT_WET,GameConstants.WEIGHT_SOAKING_WET,GameConstants.WEIGHT_DRENCHED};
+	}
+	
+	override bool ValidateServer()
+	{
+		if (!wetnessWeightModifiers || wetnessWeightModifiers.Count() != 5)
+		{
+			return false;
+		}
+		
+		return true;
+	}
+	
+	//-------------------------------------------------------------------------------------------------
+	//!!! all member variables must correspond with the cfggameplay.json file contents !!!!
+	int lightingConfig;
+	
+	ref array<string> objectSpawnersArr;
+	ref array<float> environmentMinTemps;
+	ref array<float> environmentMaxTemps;
+	ref array<float> wetnessWeightModifiers = {GameConstants.WEIGHT_DRY,GameConstants.WEIGHT_DAMP,GameConstants.WEIGHT_WET,GameConstants.WEIGHT_SOAKING_WET,GameConstants.WEIGHT_DRENCHED};
+	ref TStringArray playerRestrictedAreaFiles;
+};
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------
+
+class ITEM_BaseBuildingData : ITEM_DataBase
+{
+	
+	override void InitServer()
+	{
+	}
+	
+	override bool ValidateServer()
+	{
+		return true;
+	}
+	
+	//-------------------------------------------------------------------------------------------------
+	//!!! all member variables must correspond with the cfggameplay.json file contents !!!!
+	ref ITEM_HologramData HologramData = new ITEM_HologramData;
+	ref ITEM_ConstructionData ConstructionData = new ITEM_ConstructionData;
+};
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------
+
+class ITEM_HologramData : ITEM_DataBase
+{
+	
+	override void InitServer()
+	{
+		disallowedTypesInUnderground = new TStringSet();
+		disallowedTypesInUnderground.Insert("FenceKit");
+		disallowedTypesInUnderground.Insert("TerritoryFlagKit");
+		disallowedTypesInUnderground.Insert("WatchtowerKit");
+	}
+	
+	override bool ValidateServer()
+	{
+		return true;
+	}
+	
+	//-------------------------------------------------------------------------------------------------
+	//!!! all member variables must correspond with the cfggameplay.json file contents !!!!
+	bool disableIsCollidingBBoxCheck;
+	bool disableIsCollidingPlayerCheck;
+	bool disableIsClippingRoofCheck;
+	bool disableIsBaseViableCheck;
+	bool disableIsCollidingGPlotCheck;
+	bool disableIsCollidingAngleCheck;
+	bool disableIsPlacementPermittedCheck;
+	bool disableHeightPlacementCheck;
+	bool disableIsUnderwaterCheck;
+	bool disableIsInTerrainCheck;
+	ref TStringSet disallowedTypesInUnderground;
+};
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------
+
+class ITEM_ConstructionData : ITEM_DataBase
+{
+	
+	override void InitServer()
+	{
+	}
+	
+	override bool ValidateServer()
+	{
+		return true;
+	}
+	
+	//-------------------------------------------------------------------------------------------------
+	//!!! all member variables must correspond with the cfggameplay.json file contents !!!!
+	bool disablePerformRoofCheck;
+	bool disableIsCollidingCheck;
+	bool disableDistanceCheck;
+};
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------
+
+//! data for UI, in-game HUD, and similar
+class ITEM_UIData : ITEM_DataBase
+{
+	override void InitServer()
+	{
+		HitIndicationData.InitServer();
+	}
+	
+	override bool ValidateServer()
+	{
+		return true;
+	}
+	
+	//-------------------------------------------------------------------------------------------------
+	//!!! all member variables must correspond with the cfggameplay.json file contents !!!!
+	ref ITEM_HitIndicationData HitIndicationData = new ITEM_HitIndicationData;
+	bool use3DMap = false;
+};
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------
+
+class ITEM_HitIndicationData : ITEM_DataBase
+{
+	override void InitServer()
+	{
+		hitDirectionOverrideEnabled = false;
+		hitIndicationPostProcessEnabled = false;
+	}
+	
+	override bool ValidateServer()
+	{
+		return true;
+	}
+	
+	//-------------------------------------------------------------------------------------------------
+	//!!! all member variables must correspond with the cfggameplay.json file contents !!!!
+	//!!! all member variables must be defined in the .json file, otherwise they are treated as '0' value (unless that's what you want..)
+	bool hitDirectionOverrideEnabled = false;
+	int hitDirectionBehaviour = HitDirectionModes.STATIC;
+	int hitDirectionStyle = HitIndicatorType.SPLASH;
+	string hitDirectionIndicatorColorStr;
+	float hitDirectionMaxDuration = HitDirectionConstants.DURATION_BASE;
+	float hitDirectionBreakPointRelative = HitDirectionConstants.BREAKPOINT_BASE;
+	float hitDirectionScatter = HitDirectionConstants.SCATTER;
+	bool hitIndicationPostProcessEnabled = false;
+};
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------
+
+class ITEM_MapData : ITEM_DataBase
+{
+	override void InitServer()
+	{
+	}
+	
+	override bool ValidateServer()
+	{
+		return true;
+	}
+	
+	//-------------------------------------------------------------------------------------------------
+	//!!! all member variables must correspond with the cfggameplay.json file contents !!!!
+	bool ignoreMapOwnership 		= false;
+	bool ignoreNavItemsOwnership  	= false;
+	bool displayPlayerPosition		= false;
+	bool displayNavInfo				= true;
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------------------------
+
+class ITEM_DrowningData : ITEM_DataBase
+{
+	override void InitServer()
+	{
+	}
+	
+	override bool ValidateServer()
+	{
+		return true;
+	}
+	
+	//-------------------------------------------------------------------------------------------------
+	//!!! all member variables must correspond with the cfggameplay.json file contents !!!!
+	float staminaDepletionSpeed = 10;
+	float healthDepletionSpeed = 10;
+	float shockDepletionSpeed = 10;
+}

+ 448 - 0
Scripts/3_game/cfggameplayhandler.c

@@ -0,0 +1,448 @@
+class CfgGameplayHandler
+{
+	private static string m_Path = "$mission:cfggameplay.json";
+	private static ref array<ref ITEM_DataBase> m_Items = new array<ref ITEM_DataBase>();
+	
+	static ref CfgGameplayJson m_Data = new CfgGameplayJson();
+	
+	//---------------------------------------------------------------------------------------
+	static void RegisterItem(ITEM_DataBase item)
+	{
+		m_Items.Insert(item);
+	}
+	//---------------------------------------------------------------------------------------
+	private static void ValidateItems()
+	{
+		foreach (ITEM_DataBase item : m_Items)
+		{
+			if (!item.ValidateServer())
+			{
+				string itemName = item.Type().ToString();
+				itemName.Replace("ITEM_", "");
+				PrintToRPT("Validation failed during loading of 'cfggameplay.json' for " + itemName);
+				item.InitServer();
+			}
+		}
+	}
+	
+	//---------------------------------------------------------------------------------------
+	private static void InitData()
+	{
+		foreach (ITEM_DataBase item:m_Items)
+		{
+			item.InitServer();
+		}
+	}
+	#ifdef DEVELOPER
+	//---------------------------------------------------------------------------------------
+	static void Output()
+	{
+		Print(m_Items.Count());
+	}
+	#endif
+	//---------------------------------------------------------------------------------------
+	static bool LoadData()
+	{
+		if (!FileExist(m_Path))
+		{
+			m_Path = "";
+			GetGame().GetWorldName(m_Path);
+			m_Path = string.Format("dz/worlds/%1/ce/cfggameplay.json", m_Path);
+		}
+
+		bool cfgGameplayFileEnabled = GetGame().ServerConfigGetInt( "enableCfgGameplayFile" );
+
+		#ifdef DIAG_DEVELOPER
+		if (!GetGame().IsDedicatedServer())
+		{
+			cfgGameplayFileEnabled = true;
+		}
+		#endif
+		
+		if (!cfgGameplayFileEnabled || !FileExist(m_Path))
+		{
+			m_Data.InitServer();//legacy call
+			InitData();
+			OnLoaded();
+			return false;
+		}
+		
+		string errorMessage;
+		if (!JsonFileLoader<CfgGameplayJson>.LoadFile(m_Path, m_Data, errorMessage)) //! we are allowed to read the file, so we replace the default data with data from json
+			ErrorEx(errorMessage);
+
+		ValidateItems();
+		OnLoaded();
+		
+		return true;
+	}
+	
+	//---------------------------------------------------------------------------------------
+	static void OnLoaded()
+	{
+		GetGame().GetMission().OnGameplayDataHandlerLoad();
+		DayZGame.Cast(GetGame()).OnGameplayDataHandlerLoad();
+	}
+	
+	//---------------------------------------------------------------------------------------
+	static void SyncDataSend(notnull Man player)
+	{
+		GetGame().RPCSingleParam(player, ERPCs.RPC_CFG_GAMEPLAY_SYNC, new Param1<CfgGameplayJson>(m_Data), true, player.GetIdentity());
+	}
+	
+	//---------------------------------------------------------------------------------------
+	static void SyncDataSendEx(notnull PlayerIdentity identity)
+	{
+		//Debug.Log("SyncDataSendEx");
+		GetGame().RPCSingleParam(null, ERPCs.RPC_CFG_GAMEPLAY_SYNC, new Param1<CfgGameplayJson>(m_Data), true, identity);
+	}
+	
+	//---------------------------------------------------------------------------------------
+	
+	static void OnRPC(Man player, ParamsReadContext ctx)
+	{
+		Param1<CfgGameplayJson> data = new Param1<CfgGameplayJson>(null);
+		
+		if ( ctx.Read(data) )
+		{
+			m_Data = data.param1;
+		}
+		else
+		{
+			ErrorEx("CfgGameplayHandler - client failed to read incoming data");
+		}
+	}
+
+	
+	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+	//!! =====================================================================================
+	//!!! the naming convention for static functions in this file is Get+MemberVariableName !!
+	//!! =====================================================================================
+	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!	
+	
+	//========================
+	// !!! ONLY GETTERS BELLOW
+	//========================
+		
+	
+	//----------------------------------------------------------------------------------
+	static bool GetDisablePersonalLight()
+	{
+		return m_Data.PlayerData.disablePersonalLight;
+	}
+	//----------------------------------------------------------------------------------
+
+	//-------------------------------   WorldsData   -----------------------------------
+	static int GetLightingConfig()
+	{
+		return m_Data.WorldsData.lightingConfig;
+	}
+
+	static TStringArray GetObjectSpawnersArr()
+	{
+		return m_Data.WorldsData.objectSpawnersArr;
+	}
+
+	static array<float> GetEnvironmentMinTemps()
+	{
+		return m_Data.WorldsData.environmentMinTemps;
+	}
+
+	static array<float> GetEnvironmentMaxTemps()
+	{
+		return m_Data.WorldsData.environmentMaxTemps;
+	}
+	static array<float> GetWetnessWeightModifiers()
+	{
+		return m_Data.WorldsData.wetnessWeightModifiers;
+	}
+	//----------------------------------------------------------------------------------
+
+	
+	static bool GetDisableBaseDamage()
+	{
+		return m_Data.GeneralData.disableBaseDamage;
+	}
+	//----------------------------------------------------------------------------------
+	
+	static bool GetDisableContainerDamage()
+	{
+		return m_Data.GeneralData.disableContainerDamage;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisableRespawnDialog()
+	{
+		return m_Data.GeneralData.disableRespawnDialog;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisableRespawnInUnconsciousness()
+	{
+		return m_Data.GeneralData.disableRespawnInUnconsciousness;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetSprintStaminaModifierErc()
+	{
+		return m_Data.PlayerData.StaminaData.sprintStaminaModifierErc;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetSprintStaminaModifierCro()
+	{
+		return m_Data.PlayerData.StaminaData.sprintStaminaModifierCro;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetSprintSwimmingStaminaModifier()
+	{
+		return m_Data.PlayerData.StaminaData.sprintSwimmingStaminaModifier;
+	}//----------------------------------------------------------------------------------
+	static float GetSprintLadderStaminaModifier()
+	{
+		return m_Data.PlayerData.StaminaData.sprintLadderStaminaModifier;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetStaminaWeightLimitThreshold()
+	{
+		return m_Data.PlayerData.StaminaData.staminaWeightLimitThreshold;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetStaminaMax()
+	{
+		return m_Data.PlayerData.StaminaData.staminaMax;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetStaminaKgToStaminaPercentPenalty()
+	{
+		return m_Data.PlayerData.StaminaData.staminaKgToStaminaPercentPenalty;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetStaminaMinCap()
+	{
+		return m_Data.PlayerData.StaminaData.staminaMinCap;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetMeleeStaminaModifier()
+	{
+		return m_Data.PlayerData.StaminaData.meleeStaminaModifier;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetObstacleTraversalStaminaModifier()
+	{
+		return m_Data.PlayerData.StaminaData.obstacleTraversalStaminaModifier;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetHoldBreathStaminaModifier()
+	{
+		return m_Data.PlayerData.StaminaData.holdBreathStaminaModifier;
+	}
+	//----------------------------------------------------------------------------------	
+	static float GetMovementTimeToStrafeJog()
+	{
+		return Math.Max(0.01, m_Data.PlayerData.MovementData.timeToStrafeJog);
+	}
+	//----------------------------------------------------------------------------------
+	static float GetMovementTimeToSprint()
+	{
+		return Math.Max(0.01, m_Data.PlayerData.MovementData.timeToSprint);
+	}
+	//----------------------------------------------------------------------------------
+	static float GetMovementTimeToStrafeSprint()
+	{
+		return Math.Max(0.01, m_Data.PlayerData.MovementData.timeToStrafeSprint);
+	}
+	//----------------------------------------------------------------------------------
+	static float GetMovementRotationSpeedJog()
+	{
+		return Math.Max(0.01, m_Data.PlayerData.MovementData.rotationSpeedJog);
+	}
+	//----------------------------------------------------------------------------------
+	static float GetMovementRotationSpeedSprint()
+	{
+		return Math.Max(0.01, m_Data.PlayerData.MovementData.rotationSpeedSprint);
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisable2dMap()
+	{
+		return m_Data.PlayerData.disable2dMap;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisableIsCollidingBBoxCheck()
+	{
+		return m_Data.BaseBuildingData.HologramData.disableIsCollidingBBoxCheck;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisableIsCollidingPlayerCheck()
+	{
+		return m_Data.BaseBuildingData.HologramData.disableIsCollidingPlayerCheck;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisableIsClippingRoofCheck()
+	{
+		return m_Data.BaseBuildingData.HologramData.disableIsClippingRoofCheck;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisableIsBaseViableCheck()
+	{
+		return m_Data.BaseBuildingData.HologramData.disableIsBaseViableCheck;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisableIsInTerrainCheck()
+	{
+		return m_Data.BaseBuildingData.HologramData.disableIsInTerrainCheck;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisableIsUnderwaterCheck()
+	{
+		return m_Data.BaseBuildingData.HologramData.disableIsUnderwaterCheck;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisableHeightPlacementCheck()
+	{
+		return m_Data.BaseBuildingData.HologramData.disableHeightPlacementCheck;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisableIsPlacementPermittedCheck()
+	{
+		return m_Data.BaseBuildingData.HologramData.disableIsPlacementPermittedCheck;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisableIsCollidingAngleCheck()
+	{
+		return m_Data.BaseBuildingData.HologramData.disableIsCollidingAngleCheck;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisableIsCollidingGPlotCheck()
+	{
+		return m_Data.BaseBuildingData.HologramData.disableIsCollidingGPlotCheck;
+	}
+	//----------------------------------------------------------------------------------	
+	static bool GetDisableIsCollidingCheck()
+	{
+		return m_Data.BaseBuildingData.ConstructionData.disableIsCollidingCheck;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisablePerformRoofCheck()
+	{
+		return m_Data.BaseBuildingData.ConstructionData.disablePerformRoofCheck;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetDisableDistanceCheck()
+	{
+		return m_Data.BaseBuildingData.ConstructionData.disableDistanceCheck;
+	}
+	//----------------------------------------------------------------------------------
+	static TStringSet GetDisallowedTypesInUnderground()
+	{
+		return m_Data.BaseBuildingData.HologramData.disallowedTypesInUnderground;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetHitIndicationOverrideEnabled() //TODO - ?
+	{
+		return m_Data.UIData.HitIndicationData.hitDirectionOverrideEnabled;
+	}
+	//----------------------------------------------------------------------------------
+	static int GetHitIndicationMode()
+	{
+		return m_Data.UIData.HitIndicationData.hitDirectionBehaviour;
+	}
+	//----------------------------------------------------------------------------------
+	static int GetHitIndicationTypeID()
+	{
+		return m_Data.UIData.HitIndicationData.hitDirectionStyle;
+	}
+	//----------------------------------------------------------------------------------
+	static int GetHitIndicationIndicatorColor()
+	{
+		return m_Data.UIData.HitIndicationData.hitDirectionIndicatorColorStr.HexToInt();
+	}
+	//----------------------------------------------------------------------------------
+	static float GetHitIndicationMaxDuration()
+	{
+		return m_Data.UIData.HitIndicationData.hitDirectionMaxDuration;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetHitIndicationBreakPoint()
+	{
+		return m_Data.UIData.HitIndicationData.hitDirectionBreakPointRelative;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetHitIndicationScatter()
+	{
+		return m_Data.UIData.HitIndicationData.hitDirectionScatter;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetHitIndicationPPEEnabled()
+	{
+		return m_Data.UIData.HitIndicationData.hitIndicationPostProcessEnabled;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetUse3DMap()
+	{
+		return m_Data.UIData.use3DMap;
+	}
+	//----------------------------------------------------------------------------------	
+	static float GetShockRefillSpeedConscious()
+	{
+		return m_Data.PlayerData.ShockHandlingData.shockRefillSpeedConscious;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetShockRefillSpeedUnconscious()
+	{
+		return m_Data.PlayerData.ShockHandlingData.shockRefillSpeedUnconscious;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetAllowRefillSpeedModifier()
+	{
+		return m_Data.PlayerData.ShockHandlingData.allowRefillSpeedModifier;
+	}
+
+	//--- MapData ----------------------------------------------------------------------
+	static bool GetMapIgnoreMapOwnership()
+	{
+		return m_Data.MapData.ignoreMapOwnership;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetMapIgnoreNavItemsOwnership()
+	{
+		return m_Data.MapData.ignoreNavItemsOwnership;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetMapDisplayPlayerPosition()
+	{
+		return m_Data.MapData.displayPlayerPosition;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetMapDisplayNavigationInfo()
+	{
+		return m_Data.MapData.displayNavInfo;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetStaminaDepletionSpeed()
+	{
+		return m_Data.PlayerData.DrowningData.staminaDepletionSpeed;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetHealthDepletionSpeed()
+	{
+		return m_Data.PlayerData.DrowningData.healthDepletionSpeed;
+	}
+	//----------------------------------------------------------------------------------
+	static float GetShockDepletionSpeed()
+	{
+		return m_Data.PlayerData.DrowningData.shockDepletionSpeed;
+	}
+	//----------------------------------------------------------------------------------
+	static bool GetAllowStaminaAffectInertia()
+	{
+		return m_Data.PlayerData.MovementData.allowStaminaAffectInertia;
+	}
+	//----------------------------------------------------------------------------------
+	static TStringArray GetPlayerSpawnGearPresetFiles()
+	{
+		return m_Data.PlayerData.spawnGearPresetFiles;
+	}
+	//----------------------------------------------------------------------------------
+	static TStringArray GetPlayerRestrictedAreaFiles()
+	{
+		return m_Data.WorldsData.playerRestrictedAreaFiles;
+	}
+	//----------------------------------------------------------------------------------
+}

+ 266 - 0
Scripts/3_game/cfgplayerrestrictedareahandler.c

@@ -0,0 +1,266 @@
+class CfgPlayerRestrictedAreaHandler
+{
+	private static bool m_Initialized;
+	
+	static ref TStringArray m_PRAFiles = new TStringArray();
+	static ref CfgPlayerRestrictedAreaJsonData m_Data = new CfgPlayerRestrictedAreaJsonData();
+	
+	//----------------------------------------------------------
+	//load, inits, validation
+	
+	static bool LoadData()
+	{
+		if (m_Initialized)
+			return true;
+		
+		m_Initialized = false;
+		
+		if (GetGame().ServerConfigGetInt( "enableCfgGameplayFile" )) //only reach into the CfgGameplayHandler if properly loaded!
+			m_PRAFiles = CfgGameplayHandler.GetPlayerRestrictedAreaFiles();
+		else
+			m_PRAFiles = g_Game.GetMission().GetWorldData().GetDefaultPRAPaths();
+		
+		if (!m_PRAFiles)
+			return true;
+
+		string worldName;
+		GetGame().GetWorldName(worldName);
+	
+		foreach (string filename : m_PRAFiles)
+		{
+			PlayerRestrictedAreaInstance area = new PlayerRestrictedAreaInstance();
+			
+			string errorMessage, path;
+
+			path = string.Format("$mission:%1", filename);
+			if (!JsonFileLoader<PlayerRestrictedAreaInstance>.LoadFile(path, area, errorMessage))
+			{
+				if (!FileExist(filename))
+					path = string.Format("dz/worlds/%1/ce/%2", worldName, filename);
+				
+				if (!JsonFileLoader<PlayerRestrictedAreaInstance>.LoadFile(path, area, errorMessage))
+				{
+					ErrorEx(errorMessage);
+					continue;
+				}
+			}
+			
+			if (area != null)
+				m_Data.m_Areas.Insert(area);
+		}
+		
+		m_Initialized = m_Data.InitializeAreas();
+		
+		return true;
+	}
+	
+	static bool IsInitialized()
+	{
+		return m_Initialized;
+	}
+	
+	//----------------------------------------------------------
+	//synchronization
+	
+	static void SyncDataSend(notnull PlayerIdentity identity)
+	{
+		GetGame().RPCSingleParam(null, ERPCs.RPC_PLAYERRESTRICTEDAREAS_SYNC, new Param1<CfgPlayerRestrictedAreaJsonData>(m_Data), true, identity);
+	}
+	
+	static void OnRPC(ParamsReadContext ctx)
+	{
+		Param1<CfgPlayerRestrictedAreaJsonData> data = new Param1<CfgPlayerRestrictedAreaJsonData>(null);
+		
+		if (ctx.Read(data))
+		{
+			m_Data = data.param1;
+			m_Initialized = m_Data.m_ValidatedAreas.Count() > 0;
+		}
+		else
+		{
+			ErrorEx("CfgPlayerRestrictedAreaHandler - client failed to read incoming data");
+		}
+	}
+	
+	//----------------------------------------------------------
+	//main area checking methods
+	
+	static bool IsPointInPlayerRestrictedAreaClosest(vector point, out PlayerRestrictedAreaInstance hitArea)
+	{
+		if (!IsInitialized())
+			return false;
+		
+		PlayerRestrictedAreaInstance area = GetClosestArea(point);
+		if (area && IsCylinderInAreaBox(area,point) || IsPointInAreaPolygon(area,point))
+		{
+			hitArea = area;
+			return true;
+		}
+		return false;
+	}
+	
+	static bool IsPointInPlayerRestrictedArea(vector point, out PlayerRestrictedAreaInstance hitArea)
+	{
+		if (!IsInitialized())
+			return false;
+		
+		foreach (PlayerRestrictedAreaInstance area : m_Data.m_ValidatedAreas)
+		{
+			if (IsCylinderInAreaBox(area,point) || IsPointInAreaPolygon(area,point))
+			{
+				hitArea = area;
+				return true;
+			}
+		}
+		
+		return false;
+	}
+	
+	//----------------------------------------------------------
+	//support methods
+	
+	private static PlayerRestrictedAreaInstance GetClosestArea(vector point)
+	{
+		PlayerRestrictedAreaInstance ret;
+		float closestDist = float.MAX;
+		float currentDist;
+		
+		foreach (PlayerRestrictedAreaInstance area : m_Data.m_ValidatedAreas)
+		{
+			currentDist = vector.DistanceSq(point,area.GetCenterPos2D());
+			if (currentDist < closestDist)
+			{
+				ret = area;
+				closestDist = currentDist;
+			}
+		}
+		
+		return ret;
+	}
+	
+	//! default cylinder values sufficient for player detection
+	private static bool IsCylinderInAreaBox(notnull PlayerRestrictedAreaInstance area, vector point, float cylinderRadius = 0.25, float cylinderHeight = 1)
+	{
+		foreach (PRAShapeBoxData boxData : area.m_PRABoxDataTranslated)
+		{
+			vector matPlayer4[4];
+			Math3D.MatrixIdentity4(matPlayer4);
+			matPlayer4[3] = point;
+			if (Math3D.IntersectCylinderOBB(boxData.m_Mins,boxData.m_Maxs,boxData.m_Mat4,matPlayer4,cylinderRadius,cylinderHeight))
+				return true;
+		}
+		
+		return false;
+	}
+	
+	private static bool IsPointInAreaPolygon(notnull PlayerRestrictedAreaInstance area, vector point)
+	{
+		array<float> translatedDta = new array<float>;
+		foreach (array<ref array<float>> polygonData : area.PRAPolygons)
+		{
+			translatedDta.Clear();
+			
+			foreach (array<float> vertexPos : polygonData)
+			{
+				translatedDta.Insert(vertexPos[0]);
+				translatedDta.Insert(vertexPos[1]);
+			}
+			
+			if (Math2D.IsPointInPolygon(translatedDta,point[0],point[2]))
+				return true;
+		}
+		
+		return false;
+	}
+	
+	//----------------------------------------------------------
+	//debugs
+	
+	static private ref array<Shape> m_DbgShapesBoxes;
+	static private ref array<Shape> m_DbgShapesPolygonLines;
+	
+	static void DrawBoxesDebug(bool draw)
+	{
+		if (!IsInitialized())
+			return;
+		
+		if (!m_DbgShapesBoxes)
+			m_DbgShapesBoxes = {};
+		
+		if (draw && m_DbgShapesBoxes.Count() == 0)
+		{
+			foreach (PlayerRestrictedAreaInstance area : m_Data.m_ValidatedAreas)
+			{
+				foreach (PRAShapeBoxData boxData : area.m_PRABoxDataTranslated)
+				{
+					Shape shp = Debug.DrawBox(boxData.m_Mins,boxData.m_Maxs);
+					shp.SetMatrix(boxData.m_Mat4);
+					m_DbgShapesBoxes.Insert(shp);
+				}
+			}
+		}
+		else if (!draw && m_DbgShapesBoxes.Count() > 0)
+		{
+			foreach (Shape box : m_DbgShapesBoxes)
+			{
+				box.Destroy();
+			}
+			
+			m_DbgShapesBoxes.Clear();
+		}
+	}
+	
+	static void DrawPolygonLinesDebug(bool draw)
+	{
+		if (!IsInitialized())
+			return;
+		
+		if (!m_DbgShapesPolygonLines)
+			m_DbgShapesPolygonLines = {};
+		
+		if (draw && m_DbgShapesPolygonLines.Count() == 0)
+		{
+			array<vector> polygonVectors = {};
+			foreach (PlayerRestrictedAreaInstance area : m_Data.m_ValidatedAreas)
+			{
+				foreach (array<ref array<float>> polygonData : area.PRAPolygons)
+				{
+					vector first;
+					vector current;
+					vector last;
+					
+					foreach (array<float> vertexPos : polygonData)
+					{
+						polygonVectors.Insert(Vector(vertexPos[0],GetGame().SurfaceY(vertexPos[0],vertexPos[1]) + 2,vertexPos[1]));
+					}
+					
+					int count = polygonVectors.Count();
+					for (int i = 0; i < count; ++i)
+					{
+						current = polygonVectors[i];
+						
+						if (i == 0)
+							first = polygonVectors[i];
+						else
+							Debug.DrawLine(last,current,COLOR_WHITE,ShapeFlags.TRANSP|ShapeFlags.NOZWRITE);
+						
+						last = current;
+					}
+					
+					m_DbgShapesPolygonLines.Insert(Debug.DrawLine(current,first,COLOR_RED,ShapeFlags.TRANSP|ShapeFlags.NOZWRITE));
+					
+					polygonVectors.Clear();
+				}
+			}
+		}
+		else if (!draw && m_DbgShapesPolygonLines.Count() > 0)
+		{
+			foreach (Shape item : m_DbgShapesPolygonLines)
+			{
+				item.Destroy();
+			}
+			
+			m_DbgShapesPolygonLines.Clear();
+		}
+	}
+}

+ 248 - 0
Scripts/3_game/cfgplayerrestrictedareajsondata.c

@@ -0,0 +1,248 @@
+class CfgPlayerRestrictedAreaJsonData
+{
+	ref array<ref PlayerRestrictedAreaInstance> m_ValidatedAreas = new array<ref PlayerRestrictedAreaInstance>();
+	ref array<ref PlayerRestrictedAreaInstance> m_Areas = new array<ref PlayerRestrictedAreaInstance>();
+	
+	bool InitializeAreas()
+	{
+		m_ValidatedAreas.Clear();
+		
+		foreach (PlayerRestrictedAreaInstance instance : m_Areas)
+		{
+			instance.Initialize();
+			if (instance.IsValid())
+				m_ValidatedAreas.Insert(instance);
+		}
+		
+		m_Areas.Clear();
+		
+		return m_ValidatedAreas.Count() > 0;
+	}
+};
+
+class PRAShapeDataBase
+{
+	void PRAShapeDataBase(array<ref array<float>> shapeDataArray)
+	{
+		InitPRAShapeData(shapeDataArray);
+	}
+	
+	void InitPRAShapeData(array<ref array<float>> shapeDataArray)
+	{
+	}
+}
+
+class PRAShapeBoxData : PRAShapeDataBase
+{
+	vector m_Mins;
+	vector m_Maxs;
+	vector m_Mat4[4];
+	
+	override void InitPRAShapeData(array<ref array<float>> shapeDataArray)
+	{
+		vector sizes = Vector(shapeDataArray[0][0],shapeDataArray[0][1],shapeDataArray[0][2]);
+		vector angle = Vector(shapeDataArray[1][0],shapeDataArray[1][1],shapeDataArray[1][2]);
+		vector targetPoint = Vector(shapeDataArray[2][0],shapeDataArray[2][1],shapeDataArray[2][2]);
+		
+		m_Mins = Vector(-sizes[0]/2,-sizes[1]/2,-sizes[2]/2);
+		m_Maxs = Vector(sizes[0]/2,sizes[1]/2,sizes[2]/2);
+		
+		vector mat3[3];
+		Math3D.YawPitchRollMatrix(angle,mat3);
+		
+		m_Mat4[0] = mat3[0];
+		m_Mat4[1] = mat3[1];
+		m_Mat4[2] = mat3[2];
+		m_Mat4[3] = targetPoint;
+	}
+}
+
+class PlayerRestrictedAreaInstance
+{
+	//private
+	private bool m_IsValid = false;
+	private int m_LastUsedSafePosIdx = -1;
+	private ref array<vector> m_TranslatedSafePositions3D;
+	private ref array<vector> m_RandomizedSafePositions3D;
+	//private ref map<vector,int> m_TimeIndexedSafePositions;
+	private vector m_CenterPos2D; //averaged center position, used for initial filtering
+	
+	//public
+	string areaName = ""; //optional
+	ref array<ref array<ref array<float>>> PRABoxes = new array<ref array<ref array<float>>>; //!3D, not used directly!
+	ref array<ref array<ref array<float>>> PRAPolygons = new array<ref array<ref array<float>>>; //2D
+	ref array<ref array<float>> safePositions2D = new array<ref array<float>>;
+	ref array<ref array<float>> safePositions3D = new array<ref array<float>>;
+	
+	ref array<ref PRAShapeBoxData> m_PRABoxDataTranslated = new array<ref PRAShapeBoxData>; //translated data
+	
+	void Initialize()
+	{
+		if (m_IsValid)
+			return;
+		
+		m_IsValid = false;
+		m_IsValid |= ValidatePlayerRestrictedAreaPositions();
+		m_IsValid |= TranslateSafePositions();
+	}
+	
+	private bool ValidatePlayerRestrictedAreaPositions()
+	{
+		if (PRABoxes.Count() == 0 && PRAPolygons.Count() == 0)
+		{
+			Debug.Log("No valid coordinates in 'PRABoxes' or 'PRAPolygons' for area: " + areaName,"n/a","n/a","","PlayerRestrictedAreaInstance");
+			return false;
+		}
+		
+		float xMin,zMin = float.MAX;
+		float xMax,zMax = float.MIN;
+		
+		foreach (array<ref array<float>> boxFloatsData : PRABoxes)
+		{
+			if (boxFloatsData.Count() != 3)
+			{
+				Debug.Log("Invalid box defined in " + areaName + ". Box needs to have sizes, rotation, and position defined!","n/a","n/a","","PlayerRestrictedAreaInstance");
+				return false;
+			}
+			
+			array<float> boxVectors;
+			//sizes
+			boxVectors = boxFloatsData[0];
+			if (boxVectors.Count() != 3)
+			{
+				Debug.Log("Invalid box defined in " + areaName + ". Box size needs to be in an XYZ format!","n/a","n/a","","PlayerRestrictedAreaInstance");
+				return false;
+			}
+			
+			//rotation
+			boxVectors = boxFloatsData[1];
+			if (boxVectors.Count() != 3)
+			{
+				Debug.Log("Invalid box defined in " + areaName + ". Box rotation needs to be in an XYZ format!","n/a","n/a","","PlayerRestrictedAreaInstance");
+				return false;
+			}
+			
+			//position
+			boxVectors = boxFloatsData[2];
+			if (boxVectors.Count() != 3)
+			{
+				Debug.Log("Invalid box defined in " + areaName + ". Box position needs to be in an XYZ format!","n/a","n/a","","PlayerRestrictedAreaInstance");
+				return false;
+			}
+			
+			//translate to data
+			PRAShapeBoxData dta = new PRAShapeBoxData(boxFloatsData);
+			if (dta)
+			{
+				m_PRABoxDataTranslated.Insert(dta);
+				
+				xMin = Math.Min(xMin,dta.m_Mins[0]);
+				zMin = Math.Min(zMin,dta.m_Mins[2]);
+				xMax = Math.Max(xMax,dta.m_Maxs[0]);
+				zMax = Math.Max(zMax,dta.m_Maxs[2]);
+			}
+		}
+		
+		foreach (array<ref array<float>> polygonData : PRAPolygons)
+		{
+			if (polygonData.Count() < 3)
+			{
+				Debug.Log("Invalid polygon defined in " + areaName + ". At least 3 points necessary!","n/a","n/a","","PlayerRestrictedAreaInstance");
+				return false;
+			}
+			
+			foreach (array<float> polygonCoords : polygonData)
+			{
+				if (polygonCoords.Count() != 2)
+				{
+					Debug.Log("Invalid polygon defined in " + areaName + ". Polygon coordinates need to be in a XZ format!","n/a","n/a","","PlayerRestrictedAreaInstance");
+					return false;
+				}
+				
+				xMin = Math.Min(xMin,polygonCoords[0]);
+				zMin = Math.Min(zMin,polygonCoords[1]);
+				xMax = Math.Max(xMax,polygonCoords[0]);
+				zMax = Math.Max(zMax,polygonCoords[1]);
+			}
+		}
+		
+		m_CenterPos2D = Vector(((xMin + xMax) / 2), 0, ((zMin + zMax) / 2));
+		
+		return true;
+	}
+	
+	private bool TranslateSafePositions()
+	{
+		if (safePositions2D.Count() == 0 && safePositions3D.Count() == 0)
+		{
+			Debug.Log("Undefined safe positions for area: " + areaName,"n/a","n/a","","PlayerRestrictedAreaInstance");
+			return false;
+		}
+		
+		m_TranslatedSafePositions3D = new array<vector>;
+		
+		foreach (array<float> arr2d : safePositions2D)
+		{
+			m_TranslatedSafePositions3D.Insert(Vector(arr2d[0],GetGame().SurfaceY(arr2d[0],arr2d[1]),arr2d[1]));
+		}
+		
+		foreach (array<float> arr3d : safePositions3D)
+		{
+			m_TranslatedSafePositions3D.Insert(Vector(arr3d[0],arr3d[1],arr3d[2]));
+		}
+		
+		return true;
+	}
+	
+	bool IsValid()
+	{
+		return m_IsValid;
+	}
+	
+	vector GetCenterPos2D()
+	{
+		return m_CenterPos2D;
+	}
+	
+	//----------------------------------------------------------
+	//getters
+	
+	vector GetClosestSafePos3D(vector targetPos)
+	{
+		vector closestPos = targetPos;
+		float smallestDist = float.MAX;
+		float dist;
+		
+		foreach (vector pos : m_TranslatedSafePositions3D)
+		{
+			dist = vector.DistanceSq(targetPos, pos);
+			if (dist < smallestDist)
+			{
+				smallestDist = dist;
+				closestPos = pos;
+			}
+		}
+		return closestPos;
+	}
+	
+	vector GetRandomSafePos3D(vector targetPos)
+	{
+		if (!m_RandomizedSafePositions3D || m_RandomizedSafePositions3D.Count() == 0)
+		{
+			m_RandomizedSafePositions3D = new array<vector>;
+			m_RandomizedSafePositions3D.Copy(m_TranslatedSafePositions3D);
+			m_LastUsedSafePosIdx = -1;
+		}
+		
+		int count = m_RandomizedSafePositions3D.Count();
+		m_LastUsedSafePosIdx++;
+		
+		if (m_LastUsedSafePosIdx == count)
+		{
+			m_RandomizedSafePositions3D.ShuffleArray();
+			m_LastUsedSafePosIdx = 0;
+		}
+		
+		return m_RandomizedSafePositions3D[m_LastUsedSafePosIdx];
+	}
+}

+ 131 - 0
Scripts/3_game/client/clientdata.c

@@ -0,0 +1,131 @@
+class ClientData
+{
+	static ref ScriptInvoker SyncEvent_OnPlayerListUpdate = new ScriptInvoker();
+	static ref ScriptInvoker SyncEvent_OnEntityKilled = new ScriptInvoker();
+	static ref ScriptInvoker SyncEvent_OnPlayerIgnitedFireplace = new ScriptInvoker();
+	
+	static ref array<Man>			m_PlayerBaseList = new array<Man>;
+	static ref SyncPlayerList		m_PlayerList;
+	static ref SyncPlayerList		m_LastNewPlayers;
+	
+	static ref OnlineServices		m_OnlineServices;
+	
+	static void ResetClientData()
+	{
+		if ( m_PlayerBaseList )
+			m_PlayerBaseList.Clear();
+		if ( m_PlayerList && m_PlayerList.m_PlayerList )
+			m_PlayerList.m_PlayerList.Clear();
+		if ( m_LastNewPlayers && m_LastNewPlayers.m_PlayerList )
+			m_LastNewPlayers.m_PlayerList.Clear();
+	}
+	
+	static void AddPlayerBase( Man player )
+	{
+		if ( m_PlayerBaseList && player != GetGame().GetPlayer() )
+			m_PlayerBaseList.Insert( player );
+	}
+	
+	static void RemovePlayerBase( Man player )
+	{
+		if ( m_PlayerBaseList )
+			m_PlayerBaseList.RemoveItem( player );
+	}
+	
+	static void SyncEvent_PreprocessPlayerList(SyncPlayerList player_list)
+	{
+		foreach (auto sync_player : player_list.m_PlayerList)
+		{
+			PlayerIdentity identity = sync_player.m_Identity;
+			if (!identity)
+			{
+				ErrorEx("PlayerIdentity not synchronized before SyncPlayer", ErrorExSeverity.WARNING);
+				continue;
+			}
+
+			sync_player.m_UID = identity.GetPlainId();
+			sync_player.m_PlayerName = identity.GetPlainName();
+		}
+	}
+
+	static void SyncEvent_OnRecievedPlayerList( SyncPlayerList player_list )
+	{
+		if (m_PlayerList && m_PlayerList.m_PlayerList)
+		{
+			//Print("SyncEvent_OnRecievedPlayerList | " + m_PlayerList.m_PlayerList.Count());
+		}
+		
+		SyncPlayerList new_players = SyncPlayerList.Compare(m_PlayerList, player_list);
+		
+		if ( !m_LastNewPlayers )
+		{
+			m_LastNewPlayers = player_list;
+		}
+		else
+		{
+			m_LastNewPlayers = SyncPlayerList.Compare( m_LastNewPlayers, new_players );
+		}
+		
+		m_PlayerList = SyncPlayerList.Compare(player_list, null);
+		
+		#ifdef PLATFORM_CONSOLE
+			#ifndef PLATFORM_WINDOWS // if app is not on Windows with -XBOX parameter
+				array<string> newPlayersSimple = GetSimplePlayerList( new_players );
+				OnlineServices.LoadPermissions( newPlayersSimple );
+				OnlineServices.m_ClientServices.GetSessionService().OnSessionPlayerListUpdate(newPlayersSimple);
+				
+				if ( new_players.m_PlayerList.Count() > 0 )
+				{
+					OnlineServices.LoadFriends();
+				}
+		
+				if ( g_Game.GetGameState() == DayZGameState.IN_GAME )
+				{
+					OnlineServices.SetMultiplayState(OnlineServices.GetMultiplayState());
+				}
+			#endif
+		#endif
+		
+		SyncEvent_OnPlayerListUpdate.Invoke( player_list );
+	}
+	
+	static array<string> GetSimplePlayerList()
+	{
+		array<string> ids = new array<string>;
+		if ( m_PlayerList && m_PlayerList.m_PlayerList )
+		{
+			for ( int i = 0; i < m_PlayerList.m_PlayerList.Count(); i++ )
+			{
+				SyncPlayer player = m_PlayerList.m_PlayerList.Get( i );
+				ids.Insert( player.m_UID );
+			}
+		}
+		
+		return ids;
+	}
+	
+	static array<string> GetSimplePlayerList( SyncPlayerList list )
+	{
+		array<string> ids = new array<string>;
+		if ( list )
+		{
+			for ( int i = 0; i < list.m_PlayerList.Count(); i++ )
+			{
+				SyncPlayer player = list.m_PlayerList.Get( i );
+				ids.Insert( player.m_UID );
+			}
+		}
+		
+		return ids;
+	}
+	
+	static void SyncEvent_OnEntityKilled( SyncEntityKillInfo entity_killed_data )
+	{
+		SyncEvent_OnEntityKilled.Invoke(entity_killed_data.m_EntityVictim, entity_killed_data.m_EntityKiller, entity_killed_data.m_EntitySource, entity_killed_data.m_IsHeadShot );
+	}
+	
+	static void SyncEvent_OnPlayerIgnitedFireplace( EFireIgniteType igante_type )
+	{
+		SyncEvent_OnPlayerIgnitedFireplace.Invoke(igante_type);
+	}
+}

+ 26 - 0
Scripts/3_game/client/mods/modloader.c

@@ -0,0 +1,26 @@
+class ModLoader
+{
+	protected static bool							m_Loaded;
+	protected static ref array<ref ModStructure>	m_Mods;
+	
+	static array<ref ModStructure> GetMods()
+	{
+		//if( !m_Loaded )
+			LoadMods();
+		return m_Mods;
+	}
+	
+	static void LoadMods()
+	{
+		m_Mods = new array<ref ModStructure>;
+		
+		int mod_count = GetGame().ConfigGetChildrenCount( "CfgMods" );
+		
+		for( int i = 2; i < mod_count; i++ )
+		{
+			string mod_name;
+			GetGame().ConfigGetChildName( "CfgMods", i, mod_name );
+			m_Mods.Insert( new ModStructure( i, "CfgMods " + mod_name ) );
+		}
+	}
+}

+ 68 - 0
Scripts/3_game/client/mods/modstructure.c

@@ -0,0 +1,68 @@
+class ModStructure
+{
+	protected int		m_ModIndex;
+	protected string	m_ModPath;
+	protected string	m_ModName;
+	protected string	m_ModLogo;
+	protected string	m_ModLogoSmall;
+	protected string	m_ModLogoOver;
+	protected string	m_ModActionURL;
+	protected string	m_ModTooltip;
+	protected string	m_ModOverview;
+	
+	void ModStructure( int index, string path )
+	{
+		m_ModIndex	= index;
+		m_ModPath	= path;
+		LoadData();
+	}
+	
+	void LoadData()
+	{
+		if( GetGame().ConfigIsExisting( m_ModPath ) )
+		{
+			GetGame().ConfigGetText( m_ModPath + " name", m_ModName );
+			GetGame().ConfigGetText( m_ModPath + " picture", m_ModLogo );
+			GetGame().ConfigGetText( m_ModPath + " logo", m_ModLogoSmall );
+			GetGame().ConfigGetText( m_ModPath + " logoSmall", m_ModLogoOver );
+			GetGame().ConfigGetText( m_ModPath + " logoOver", m_ModActionURL );
+			GetGame().ConfigGetText( m_ModPath + " tooltip", m_ModTooltip );
+			GetGame().ConfigGetText( m_ModPath + " overview", m_ModOverview );
+		}
+	}
+	
+	string GetModName()
+	{
+		return m_ModName;
+	}
+	
+	string GetModLogo()
+	{
+		return m_ModName;
+	}
+	
+	string GetModLogoSmall()
+	{
+		return m_ModName;
+	}
+	
+	string GetModLogoOver()
+	{
+		return m_ModName;
+	}
+	
+	string GetModActionURL()
+	{
+		return m_ModName;
+	}
+	
+	string GetModToltip()
+	{
+		return m_ModName;
+	}
+	
+	string GetModOverview()
+	{
+		return m_ModName;
+	}
+}

+ 14 - 0
Scripts/3_game/client/notifications/notificationdata.c

@@ -0,0 +1,14 @@
+class NotificationData
+{
+	string m_Icon;
+	string m_TitleText;
+	string m_DescriptionText;
+	
+	void NotificationData(string icon, string title_text, string desc_text = "")
+	{
+		m_Icon = icon;
+		m_TitleText = title_text;
+		if (desc_text != "")
+			m_DescriptionText = desc_text;
+	}
+}

+ 320 - 0
Scripts/3_game/client/notifications/notificationsystem.c

@@ -0,0 +1,320 @@
+const static float NOTIFICATION_FADE_TIME = 3.0; //! DEPRECATED (moved into NotificationSystem)
+
+enum NotificationType
+{
+	FRIEND_CONNECTED,
+	INVITE_FAIL_SAME_SERVER,
+	JOIN_FAIL_GET_SESSION,
+	CONNECT_FAIL_GENERIC,
+	DISCONNECTED,
+	GENERIC_ERROR,
+	//Please add types before this item
+	NOTIFICATIONS_END
+}
+
+class NotificationRuntimeData
+{
+	ref NotificationData	m_StaticData;
+	
+	float					m_NotificationTime;
+	float					m_TimeRemaining;
+	string					m_DetailText;
+	
+	void NotificationRuntimeData(float time, NotificationData data, string detail_text)
+	{
+		m_NotificationTime	= time;
+		m_TimeRemaining		= time;
+		m_StaticData		= data;
+
+		if (detail_text != "")
+			m_DetailText	= detail_text;
+		else
+			m_DetailText	= m_StaticData.m_DescriptionText;
+	}
+
+	float GetTime()
+	{
+		return m_NotificationTime;
+	}
+	
+	float GetRemainingTime()
+	{
+		return m_TimeRemaining;
+	}
+	
+	string GetIcon()
+	{
+		return m_StaticData.m_Icon;
+	}
+	
+	string GetTitleText()
+	{
+		return m_StaticData.m_TitleText;
+	}
+	
+	string GetDetailText()
+	{
+		return m_DetailText;
+	}
+	
+	void UpdateRemainingTime(float updateInterval)
+	{
+		m_TimeRemaining -= updateInterval;
+	}
+	
+	//! DEPRECATED
+	void SetTime(float time);
+}
+
+class NotificationSystem
+{
+	const int DEFAULT_TIME_DISPLAYED 	= 10;
+	const float NOTIFICATION_FADE_TIME 	= 3.0;
+
+	protected static const string JSON_FILE_PATH = "scripts/data/notifications.json";					
+	protected static const int MAX_NOTIFICATIONS = 5;
+
+	private static const float UPDATE_INTERVAL_THRESHOLD = 1.0;
+	
+	protected static ref NotificationSystem						m_Instance;
+	
+	protected ref array<ref NotificationRuntimeData>			m_TimeArray;
+	protected ref array<ref NotificationRuntimeData>			m_DeferredArray;
+	protected ref map<NotificationType, ref NotificationData>	m_DataArray;
+	
+	protected float m_TimeElapsed;
+	
+	ref ScriptInvoker m_OnNotificationAdded = new ScriptInvoker();
+	ref ScriptInvoker m_OnNotificationRemoved = new ScriptInvoker();
+	
+	static void InitInstance()
+	{
+		if (!m_Instance)
+		{
+			m_Instance = new NotificationSystem();
+			m_Instance.LoadNotificationData();
+		}
+	}
+	
+	static void CleanupInstance()
+	{
+		m_Instance = null;
+	}
+	
+	static NotificationSystem GetInstance()
+	{
+		return m_Instance;
+	}
+	
+	void NotificationSystem()
+	{
+		m_TimeElapsed 	= 0.0;
+
+		m_TimeArray 	= new array<ref NotificationRuntimeData>();
+		m_DeferredArray = new array<ref NotificationRuntimeData>();
+	}
+	
+	/**
+	\brief Send custom notification to player from server
+	@param player the target player to send notification to
+	@param show_time amount of time this notification is displayed
+	@param title_text the title text that is displayed in the notification
+	@param detail_text additional text that can be added to the notification under the title - will not display additional text if not set
+	@param icon the icon that is displayed in the notification - will use default icon if not set
+	*/
+	static void SendNotificationToPlayerExtended(Man player, float show_time, string title_text, string detail_text = "", string icon = "")
+	{
+		if (player)
+		{
+			SendNotificationToPlayerIdentityExtended(player.GetIdentity(), show_time, title_text, detail_text, icon);
+		}
+	}
+	
+	/**
+	\brief Send custom notification to player identity from server
+	@param player the target player to send notification to - if null, will send to all players
+	@param show_time amount of time this notification is displayed
+	@param title_text the title text that is displayed in the notification
+	@param detail_text additional text that can be added to the notification under the title - will not display additional text if not set
+	@param icon the icon that is displayed in the notification - will use default icon if not set
+	*/
+	static void SendNotificationToPlayerIdentityExtended(PlayerIdentity player, float show_time, string title_text, string detail_text = "", string icon = "")
+	{
+		ScriptRPC rpc = new ScriptRPC();
+		
+		rpc.Write(show_time);
+		rpc.Write(title_text);
+		rpc.Write(detail_text);
+		rpc.Write(icon);
+
+		rpc.Send(null, ERPCs.RPC_SEND_NOTIFICATION_EXTENDED, true, player);
+	}
+	
+	/**
+	\brief Send notification from default types to player from server
+	@param player the target player to send notification to
+	@param type the type of notification to send - these can be viewed in /Scripts/Data/Notifications.json
+	@param show_time amount of time this notification is displayed
+	@param detail_text additional text that can be added to the notification under the title - will not display additional text if not set
+	*/
+	static void SendNotificationToPlayer(Man player, NotificationType type, float show_time, string detail_text = "")
+	{
+		if (player)
+		{
+			SendNotificationToPlayerIdentity(player.GetIdentity(), type, show_time, detail_text);
+		}
+	}
+	
+	/**
+	\brief Send notification from default types to player identity from server
+	@param player the target player to send notification to - if null, will send to all players
+	@param type the type of notification to send - these can be viewed in /Scripts/Data/Notifications.json
+	@param show_time amount of time this notification is displayed
+	@param detail_text additional text that can be added to the notification under the title - will not display additional text if not set
+	*/
+	static void SendNotificationToPlayerIdentity( PlayerIdentity player, NotificationType type, float show_time, string detail_text = "" )
+	{
+		ScriptRPC rpc = new ScriptRPC();
+		
+		rpc.Write(type);
+		rpc.Write(show_time);
+		rpc.Write(detail_text);
+
+		rpc.Send(null, ERPCs.RPC_SEND_NOTIFICATION, true, player);
+	}
+	
+	/**
+	\brief Send notification from default types to local player
+	@param type the type of notification to send - these can be viewed in /Scripts/Data/Notifications.json
+	@param show_time amount of time this notification is displayed
+	@param detail_text additional text that can be added to the notification under the title - will not display additional text if not set
+	*/
+	static void AddNotification(NotificationType type, float show_time, string detail_text = "")
+	{
+		if (m_Instance.m_TimeArray.Count() < MAX_NOTIFICATIONS)
+		{
+			NotificationRuntimeData data = new NotificationRuntimeData(show_time, m_Instance.GetNotificationData(type), detail_text);
+			
+			m_Instance.m_TimeArray.Insert(data);
+			m_Instance.m_OnNotificationAdded.Invoke(data);
+		}
+		else
+		{
+			NotificationRuntimeData dataDeferred = new NotificationRuntimeData(show_time, m_Instance.GetNotificationData(type), detail_text);
+			m_Instance.m_DeferredArray.Insert(dataDeferred);
+		}
+	}
+	
+	/**
+	\brief Send custom notification from to local player
+	@param show_time amount of time this notification is displayed
+	@param title_text the title text that is displayed in the notification
+	@param detail_text additional text that can be added to the notification under the title - will not display additional text if not set
+	@param icon the icon that is displayed in the notification - will use default icon if not set
+	*/
+	static void AddNotificationExtended(float show_time, string title_text, string detail_text = "", string icon = "")
+	{
+		if (m_Instance.m_TimeArray.Count() < MAX_NOTIFICATIONS)
+		{
+			NotificationData tempData = new NotificationData(icon, title_text);
+			NotificationRuntimeData data = new NotificationRuntimeData(show_time, tempData, detail_text);
+			
+			m_Instance.m_TimeArray.Insert(data);
+			m_Instance.m_OnNotificationAdded.Invoke(data);
+		}
+		else
+		{
+			NotificationData tempDataDeferred = new NotificationData(icon, title_text);
+			NotificationRuntimeData dataDeferred = new NotificationRuntimeData(show_time, tempDataDeferred, detail_text);
+			m_Instance.m_DeferredArray.Insert(dataDeferred);
+		}
+	}
+	
+	static void Update(float timeslice)
+	{
+		if (m_Instance)
+		{
+			if (g_Game.GetGameState() != DayZGameState.IN_GAME && g_Game.GetGameState() != DayZGameState.MAIN_MENU)
+				return;
+	
+			m_Instance.m_TimeElapsed += timeslice;
+			if (m_Instance.m_TimeElapsed >= UPDATE_INTERVAL_THRESHOLD)
+			{
+				array<NotificationRuntimeData> expiredNotifications = new array<NotificationRuntimeData>();
+				foreach (NotificationRuntimeData visibleNotificationData : m_Instance.m_TimeArray)
+				{
+					if (visibleNotificationData.GetRemainingTime() <= 0.0)
+						expiredNotifications.Insert(visibleNotificationData);
+					else
+						visibleNotificationData.UpdateRemainingTime(UPDATE_INTERVAL_THRESHOLD);
+				}
+				
+				foreach (NotificationRuntimeData expiredNotificationData : expiredNotifications)
+				{
+					m_Instance.m_OnNotificationRemoved.Invoke(expiredNotificationData);
+					m_Instance.m_TimeArray.RemoveItem(expiredNotificationData);
+					
+					if (m_Instance.m_DeferredArray.Count() > 0)
+					{
+						int count = m_Instance.m_DeferredArray.Count();
+						NotificationRuntimeData deferredNotificationData = m_Instance.m_DeferredArray.Get(count - 1);
+						m_Instance.m_TimeArray.Insert(deferredNotificationData);
+						m_Instance.m_OnNotificationAdded.Invoke(deferredNotificationData);
+						m_Instance.m_DeferredArray.Remove(count - 1);
+					}
+				}
+	
+				m_Instance.m_TimeElapsed = 0;
+			}
+		}
+	}
+	
+	protected NotificationData GetNotificationData(NotificationType type)
+	{
+		if (m_DataArray.Contains(type))
+			return m_DataArray.Get(type);
+		
+		return null;
+	}
+	
+	static void LoadNotificationData()
+	{
+		map<NotificationType, NotificationData> dataArray;
+		m_Instance.m_DataArray = new map<NotificationType, ref NotificationData>();
+		string errorMessage;
+		if (!JsonFileLoader<map<NotificationType, NotificationData>>.LoadFile(JSON_FILE_PATH, dataArray, errorMessage))
+			ErrorEx(errorMessage);
+		
+		m_Instance.m_DataArray.Copy(dataArray);
+		
+		array<int> notificationTypes = new array<int>();
+		NotificationType notificationType = 0;
+		while (notificationType != NotificationType.NOTIFICATIONS_END)
+		{
+			notificationTypes.Insert(notificationType);
+			notificationType++;
+		}
+		
+		for (int i = 0; i < m_Instance.m_DataArray.Count(); ++i)
+		{
+			notificationTypes.RemoveItem(m_Instance.m_DataArray.GetKey(i));
+		}
+		
+		if (notificationTypes.Count() > 0)
+		{
+			foreach (NotificationType notificationType2 : notificationTypes)
+			{
+				NotificationData notificationData = new NotificationData(
+					"please_add_an_icon",
+					"please_add_a_title",
+					"optional_description",
+				);
+
+				m_Instance.m_DataArray.Insert(notificationType2, notificationData);
+			}
+
+			if (!JsonFileLoader<map<NotificationType, ref NotificationData>>.SaveFile(JSON_FILE_PATH, m_Instance.m_DataArray, errorMessage))
+				ErrorEx(errorMessage);
+		}
+	}
+}

+ 231 - 0
Scripts/3_game/client/notifications/notificationui.c

@@ -0,0 +1,231 @@
+class NotificationUI
+{
+	protected ref Widget	m_Root;
+	protected ref Widget	m_Spacer;
+	protected ref Widget	m_VoiceContent;
+	protected ref Widget	m_NotificationContent;
+	
+	protected ref map<NotificationRuntimeData, Widget>	m_Notifications;
+	protected ref map<string, Widget>					m_VoiceNotifications;
+	
+	protected float										m_Width;
+	protected float										m_CurrentHeight;
+	protected float										m_TargetHeight;
+	protected float										m_BackupPosX;
+	protected float										m_BackupPosY;
+	protected ref map<string, Widget>					m_WidgetTimers;
+	
+	protected bool										m_OffsetEnabled;;
+	
+	void NotificationUI()
+	{
+		m_Root					= GetGame().GetWorkspace().CreateWidgets("gui/layouts/new_ui/notifications/notifications.layout");
+		m_Spacer				= m_Root.FindAnyWidget( "NotificationSpacer" );
+		m_VoiceContent			= m_Root.FindAnyWidget( "VoiceContent" );
+		m_NotificationContent	= m_Root.FindAnyWidget( "NotificationContent" );
+		m_Notifications			= new map<NotificationRuntimeData, Widget>;
+		m_VoiceNotifications	= new map<string, Widget>;
+		m_WidgetTimers			= new map<string, Widget>;
+		
+		NotificationSystem ntfSys = NotificationSystem.GetInstance();
+		if (ntfSys)
+		{
+			ntfSys.m_OnNotificationAdded.Insert( AddNotification );
+			ntfSys.m_OnNotificationRemoved.Insert( RemoveNotification );
+		}
+	}
+	
+	void ~NotificationUI()
+	{
+		NotificationSystem ntfSys = NotificationSystem.GetInstance();
+		if (ntfSys)
+		{
+			ntfSys.m_OnNotificationAdded.Remove( AddNotification );
+			ntfSys.m_OnNotificationRemoved.Remove( RemoveNotification );
+		}
+	}
+	
+	void AddNotification( NotificationRuntimeData data )
+	{
+		Widget notification			= GetGame().GetWorkspace().CreateWidgets("gui/layouts/new_ui/notifications/notification_element.layout", m_NotificationContent);
+		
+		ImageWidget icon			= ImageWidget.Cast( notification.FindAnyWidget( "Image" ) );
+		RichTextWidget title		= RichTextWidget.Cast( notification.FindAnyWidget( "Title" ) );
+		
+		if ( data.GetIcon() != "" )
+			icon.LoadImageFile( 0, data.GetIcon() );
+		title.SetText( data.GetTitleText() );
+		
+		if ( data.GetDetailText() != "" )
+		{
+			Widget bottom_spacer	= notification.FindAnyWidget( "BottomSpacer" );
+			RichTextWidget detail	= RichTextWidget.Cast( notification.FindAnyWidget( "Detail" ) );
+			bottom_spacer.Show(true);
+			detail.SetText( data.GetDetailText() );
+			detail.Update();
+			bottom_spacer.Update();
+			notification.Update();
+		}
+		
+		m_Notifications.Insert( data, notification );
+		UpdateTargetHeight();
+	}
+	
+	void RemoveNotification( NotificationRuntimeData data )
+	{
+		if ( m_Notifications.Contains( data ) )
+		{
+			Widget notification = m_Notifications.Get( data );
+			m_WidgetTimers.Insert( m_WidgetTimers.Count().ToString() + data.GetTime().ToString(), notification );
+			m_Notifications.Remove( data );
+			UpdateTargetHeight();
+		}
+	}
+	
+	void AddVoiceNotification(string player, string name)
+	{
+		if (!m_VoiceNotifications.Contains(player))
+		{
+			Widget notification;
+			if (!m_WidgetTimers.Contains(player))
+			{
+				notification = GetGame().GetWorkspace().CreateWidgets("gui/layouts/new_ui/notifications/notification_voice_element.layout", m_VoiceContent);
+			}
+			else
+			{
+				notification = m_WidgetTimers.Get(player);
+				m_WidgetTimers.Remove(player);
+				notification.SetAlpha( 120 / 255 );
+				Widget w_c = notification.FindAnyWidget( "Name" );
+				if ( w_c )
+				{
+					w_c.SetAlpha( 1 );
+				}
+			}
+
+			RichTextWidget title = RichTextWidget.Cast(notification.FindAnyWidget("Name"));
+			m_VoiceNotifications.Insert(player, notification);
+			title.SetText(name);
+			UpdateTargetHeight();
+		}
+	}
+	
+	void RemoveVoiceNotification( string player )
+	{
+		if ( m_VoiceNotifications.Contains( player ) )
+		{
+			Widget notification = m_VoiceNotifications.Get( player );
+			m_WidgetTimers.Insert( player, notification );
+			m_VoiceNotifications.Remove( player );
+			UpdateTargetHeight();
+		}
+	}
+	
+	void ClearVoiceNotifications()
+	{
+		for ( int i = 0; i < m_VoiceNotifications.Count(); i++ )
+		{
+			Widget w = m_VoiceNotifications.GetElement( i );
+			delete w;
+		}
+		m_VoiceNotifications.Clear();
+		UpdateTargetHeight();
+	}
+	
+	void UpdateTargetHeight()
+	{
+		m_VoiceContent.Update();
+		m_NotificationContent.Update();
+		m_Spacer.Update();
+		
+		float x;
+		m_Spacer.GetScreenSize( x, m_TargetHeight );
+		m_Root.GetScreenSize( m_Width, m_CurrentHeight );
+		
+		UpdateOffset();
+	}
+	
+	void UpdateOffset()
+	{
+		UIScriptedMenu menu = UIScriptedMenu.Cast(GetGame().GetUIManager().GetMenu());
+		if (menu)
+		{
+			Widget expNotification = menu.GetLayoutRoot().FindAnyWidget("notification_root");
+			if (expNotification && expNotification.IsVisible())
+			{
+				if (!m_OffsetEnabled)
+				{
+					m_Root.GetPos(m_BackupPosX, m_BackupPosY);
+					
+					float x, y, w, h;
+					m_Root.GetScreenPos(x, y);
+					expNotification.GetScreenSize(w, h);
+					
+					m_Root.SetScreenPos(x, h);
+					m_OffsetEnabled = true;
+				}
+			}
+			else if (m_OffsetEnabled)
+			{
+				m_Root.SetPos(m_BackupPosX, m_BackupPosY);
+				m_OffsetEnabled = false;
+			}
+		}
+	}
+	
+	static float m_VelArr[1];
+	void Update( float timeslice )
+	{
+		UpdateOffset();
+		
+		float x;
+		m_Spacer.GetScreenSize( x, m_TargetHeight );
+		bool is_near = ( m_CurrentHeight + 0.01 < m_TargetHeight || m_CurrentHeight - 0.01 > m_TargetHeight );
+		if ( is_near )
+		{
+			m_CurrentHeight = Math.SmoothCD(m_CurrentHeight, m_TargetHeight, m_VelArr, 0.2, 10000, timeslice);
+			m_Root.SetSize( m_Width, m_CurrentHeight );
+		}
+		else if ( m_TargetHeight != m_CurrentHeight )
+		{
+			m_CurrentHeight = m_TargetHeight;
+			m_Root.SetSize( m_Width, m_CurrentHeight );
+			m_VelArr[0] = 0;
+		}
+		
+		for ( int i = 0; i < m_WidgetTimers.Count(); )
+		{
+			Widget w		= m_WidgetTimers.GetElement( i );
+			float new_alpha	= Math.Clamp( w.GetAlpha() - timeslice / NotificationSystem.NOTIFICATION_FADE_TIME, 0, 1 );
+			if ( new_alpha > 0 )
+			{
+				w.SetAlpha( new_alpha );
+				Widget w_c = w.FindAnyWidget( "TopSpacer" );
+				Widget w_c2 = w.FindAnyWidget( "BottomSpacer" );
+				Widget w_c3 = w.FindAnyWidget( "Title" );
+				Widget w_c4 = w.FindAnyWidget( "Detail" );
+				Widget w_c5 = w.FindAnyWidget( "Name" );
+				if ( w_c && w_c2 )
+				{
+					float new_alpha_cont	= Math.Clamp( w_c.GetAlpha() - timeslice / NotificationSystem.NOTIFICATION_FADE_TIME, 0, 1 );
+					w_c.SetAlpha( new_alpha_cont );
+					w_c2.SetAlpha( new_alpha_cont );
+					w_c3.SetAlpha( new_alpha_cont );
+					w_c4.SetAlpha( new_alpha_cont );
+				}
+				if ( w_c5 )
+				{
+					float new_alpha_voice	= Math.Clamp( w_c5.GetAlpha() - timeslice / NotificationSystem.NOTIFICATION_FADE_TIME, 0, 1 );
+					w_c5.SetAlpha(new_alpha_voice);
+				}
+				i++;
+			}
+			else
+			{
+				delete w;
+				m_WidgetTimers.RemoveElement( i );
+				UpdateTargetHeight();
+			}
+		}
+	}
+}

+ 747 - 0
Scripts/3_game/client/onlineservices.c

@@ -0,0 +1,747 @@
+class OnlineServices
+{
+	static ref ScriptInvoker												m_FriendsAsyncInvoker		= new ScriptInvoker();
+	static ref ScriptInvoker												m_PermissionsAsyncInvoker	= new ScriptInvoker();
+	static ref ScriptInvoker												m_ServersAsyncInvoker		= new ScriptInvoker();
+	static ref ScriptInvoker												m_ServerAsyncInvoker		= new ScriptInvoker();
+	static ref ScriptInvoker												m_MuteUpdateAsyncInvoker	= new ScriptInvoker(); // DEPRECATED
+	static ref ScriptInvoker												m_ServerModLoadAsyncInvoker	= new ScriptInvoker();
+	
+	static ref BiosClientServices											m_ClientServices;
+	static ref TrialService													m_TrialService;
+	
+	protected static string													m_InviteServerIP;
+	protected static int													m_InviteServerPort;
+	protected static string													m_CurrentServerIP;
+	protected static int													m_CurrentServerPort;
+	protected static ref GetServersResultRow								m_CurrentServerInfo;
+	
+	
+	protected static ref map<string, ref BiosFriendInfo>					m_FriendsList;
+	protected static ref map<string, bool>									m_MuteList;
+	protected static ref map<string, ref BiosPrivacyPermissionResultArray>	m_PermissionsList;
+	
+	protected static bool													m_FirstFriendsLoad			= true;
+	protected static bool													m_MultiplayState			= false;
+	protected static ref array<string>										m_PendingInvites;
+
+	protected static ref BiosUser											m_BiosUser;
+	
+	static void Init()
+	{
+		#ifdef PLATFORM_CONSOLE
+			#ifndef PLATFORM_WINDOWS // if app is not on Windows with -XBOX parameter
+			if ( !m_TrialService )
+				m_TrialService = new TrialService;
+			if ( !m_FriendsList )
+				m_FriendsList = new map<string, ref BiosFriendInfo>;
+			if ( !m_MuteList )
+				m_MuteList = new map<string, bool>;
+			if ( !m_PermissionsList )
+				m_PermissionsList = new map<string, ref BiosPrivacyPermissionResultArray>;
+			
+			m_FriendsList.Clear();
+			m_PermissionsList.Clear();
+			m_MuteList.Clear();
+			#endif
+		#endif
+		
+		GetClientServices();
+	}
+	
+	static bool IsInitialized()
+	{
+		return ( m_ClientServices != null );
+	}
+	
+	static void GetClientServices()
+	{
+		BiosUserManager user_manager = GetGame().GetUserManager();
+		if ( user_manager )
+		{
+			BiosUser selected_user = user_manager.GetSelectedUser();
+			if ( selected_user )
+			{
+				m_ClientServices = selected_user.GetClientServices();
+			}
+			#ifdef PLATFORM_WINDOWS
+				array<ref BiosUser> user_list = new array<ref BiosUser>;
+				user_manager.GetUserList( user_list );
+				if ( user_list.Count() > 0 )
+				{
+					m_ClientServices = user_list.Get( 0 ).GetClientServices();
+				}
+			#endif
+		}
+		else
+		{
+			Error( "BiosClientServices Error: Usermanager does not exist." );
+		}
+	}
+	
+	static bool ErrorCaught( EBiosError error )
+	{
+		switch ( error )
+		{
+			case EBiosError.OK:
+			{
+				return false;
+			}
+		}
+
+		DebugPrint.LogErrorAndTrace( string.Format("BiosClientServices Error: %1", ErrorModuleHandler.GetClientMessage(ErrorCategory.BIOSError, error)) );
+		return true;
+	}
+	
+	static void LoadServers( notnull GetServersInput inputValues )
+	{
+		GetClientServices();
+		if ( m_ClientServices )
+		{
+			m_ClientServices.GetLobbyService().GetServers( inputValues );
+		}
+		else
+		{
+			DebugPrint.LogErrorAndTrace( "BiosClientServices Error: Service reference does not exist." );
+		}
+	}
+
+	static void GetFavoriteServers(TStringArray favServers)
+	{
+		m_ClientServices.GetLobbyService().GetFavoriteServers(favServers);
+	}
+	
+	static void GetCachedFavServerInfo(array<ref CachedServerInfo> favServersInfoCache)
+	{
+		m_ClientServices.GetLobbyService().GetCachedFavoriteServerInfo(favServersInfoCache);
+	}
+	
+	static void SetServerFavorited(string ipAddress, int port, int steamQueryPort, bool is_favorited )
+	{
+		GetClientServices();
+		if ( m_ClientServices )
+		{
+			if ( is_favorited )
+			{
+				m_ClientServices.GetLobbyService().AddServerFavorite( ipAddress, port, steamQueryPort );
+			}
+			else
+			{
+				m_ClientServices.GetLobbyService().RemoveServerFavorite( ipAddress, port, steamQueryPort );
+			}
+		}
+		else
+		{
+			DebugPrint.LogErrorAndTrace( "BiosClientServices Error: Service reference does not exist." );
+		}
+	}
+	
+	static void GetCurrentServerInfo( string ip, int port )
+	{
+		GetClientServices();
+		
+		m_CurrentServerIP = ip;
+		m_CurrentServerPort = port;
+		
+		GetServersInput inputValues = new GetServersInput;
+		
+		inputValues.SetHostIp( ip );
+		inputValues.SetHostPort( port );
+		inputValues.m_Page = 0;
+		inputValues.m_RowsPerPage = 10;
+		inputValues.m_Platform = 1;
+
+		#ifdef PLATFORM_XBOX
+			inputValues.m_Platform = 2;
+		#endif
+		#ifdef PLATFORM_PS4
+			inputValues.m_Platform = 3;
+		#endif
+		
+		if ( m_ClientServices )
+		{
+			m_ClientServices.GetLobbyService().GetServers( inputValues );
+		}
+	}
+	
+	static GetServersResultRow GetCurrentServerInfo()
+	{
+		if (m_CurrentServerInfo)
+			return m_CurrentServerInfo;
+		else
+			return g_Game.GetHostData();
+	}
+	
+	static void ClearCurrentServerInfo()
+	{
+		m_CurrentServerInfo	= null;
+		m_CurrentServerIP	= "";
+		m_CurrentServerPort	= 0;
+	}
+	
+	static void SetInviteServerInfo( string ip, int port )
+	{
+		m_InviteServerIP = ip;
+		m_InviteServerPort = port;
+	}
+	
+	static void GetInviteServerInfo( out string ip, out int port )
+	{
+		ip = m_InviteServerIP;
+		port = m_InviteServerPort;
+	}
+	
+	static void OnLoadServersAsync( GetServersResult result_list, EBiosError error, string response )
+	{
+		if ( !ErrorCaught( error ) )
+		{
+			if ( m_CurrentServerIP != "" && m_CurrentServerPort > 0 )
+			{
+				foreach ( GetServersResultRow result : result_list.m_Results )
+				{
+					if ( result.m_HostIp == m_CurrentServerIP && result.m_HostPort == m_CurrentServerPort )
+					{
+						m_CurrentServerInfo	= result;
+						m_CurrentServerIP	= "";
+						m_CurrentServerPort	= 0;
+					}
+				}
+			}
+			
+			// todo: remove
+			//foreach( GetServersResultRow res : result_list.m_Results )
+			//{
+			//	Print("OnLoadServersAsync: result id: " + res.m_Id + "modded: " + res.m_Modded);
+			//}
+			
+			// just for example execute the retrieving of extended info for the first server entry in the list
+			//if (result_list.m_Results.Count() > 0)
+			//{
+				//GetServersResultRow re = result_list.m_Results[0];
+				//EBiosError er = m_ClientServices.GetLobbyService().GetServerModList(re.m_Id);
+				//Print("OnLoadServersAsync GetServerModList returns:" + er);
+			//}
+			
+			m_ServersAsyncInvoker.Invoke( result_list, error, response );
+		}
+		else
+		{
+			m_ServersAsyncInvoker.Invoke( null, error, "" );
+		}
+	}
+
+	
+	static void LoadFriends()
+	{
+		GetClientServices();
+		if ( m_ClientServices )
+		{
+			m_ClientServices.GetSocialService().GetFriendsAsync();
+		}
+		else
+		{
+			DebugPrint.LogErrorAndTrace( "BiosClientServices Error: Service reference does not exist." );
+		}
+	}
+	
+	static void ShowUserProfile( string uid )
+	{
+		GetClientServices();
+		if ( m_ClientServices )
+		{
+			m_ClientServices.GetSocialService().ShowUserProfileAsync( uid );
+		}
+		else
+		{
+			DebugPrint.LogErrorAndTrace( "BiosClientServices Error: Service reference does not exist." );
+		}
+	}
+	
+	static void OnUserProfileAsync(EBiosError error)
+	{
+		ErrorCaught( error );
+	}
+	
+	static void OnFriendsAsync( BiosFriendInfoArray friend_list, EBiosError error )
+	{
+		if ( !ErrorCaught( error ) )
+		{
+			m_FriendsAsyncInvoker.Invoke( friend_list );
+			
+			array<string> friends_simple = new array<string>;
+			for ( int i = 0; i < friend_list.Count(); ++i )
+			{
+				string uid = friend_list[i].m_Uid;
+				BiosFriendInfo storedBfi = m_FriendsList[uid];
+				BiosFriendInfo newBfi = friend_list[i];
+				
+				if (storedBfi)
+				{
+					if ( !BiosFriendInfo.Compare( storedBfi, newBfi ) )
+					{
+						friends_simple.Insert( newBfi.m_Uid );
+					}
+					m_FriendsList.Set( uid, newBfi );
+				}
+				else
+				{
+					m_FriendsList.Insert( uid, newBfi );
+					friends_simple.Insert( newBfi.m_Uid );
+				}
+			}
+			
+			if ( !m_FirstFriendsLoad )
+			{
+				if ( ClientData.m_LastNewPlayers && ClientData.m_LastNewPlayers.m_PlayerList.Count() > 0 )
+				{
+					foreach ( SyncPlayer player : ClientData.m_LastNewPlayers.m_PlayerList )
+					{
+						if ( m_FriendsList.Contains( player.m_UID ) )
+						{
+							NotificationSystem.AddNotification( NotificationType.FRIEND_CONNECTED, NotificationSystem.DEFAULT_TIME_DISPLAYED, player.m_PlayerName + " " + "#ps4_invite_has_joined_your_session" );
+						}
+					}
+					ClientData.m_LastNewPlayers.m_PlayerList.Clear();
+				}
+			}
+			m_FirstFriendsLoad = false;
+		}
+	}
+	
+	static void LoadPermissions( array<string> player_list )
+	{
+		GetClientServices();
+		if ( m_ClientServices )
+		{
+			array<EBiosPrivacyPermission> perms = new array<EBiosPrivacyPermission>;
+			perms.Insert( EBiosPrivacyPermission.COMMUNICATE_VOICE );
+			
+			ErrorCaught( m_ClientServices.GetPrivacyService().GetPermissionsAsync( player_list, perms ) );
+		}
+		else
+		{
+			DebugPrint.LogErrorAndTrace( "BiosClientServices Error: Service reference does not exist." );
+		}
+	}
+	
+	static void OnPermissionsAsync( BiosPrivacyUidResultArray result_list, EBiosError error )
+	{
+		if ( !ErrorCaught( error ) )
+		{
+			BiosPrivacyUidResultArray new_list = new BiosPrivacyUidResultArray;
+			
+			for ( int i = 0; i < result_list.Count(); i++ )
+			{
+				BiosPrivacyUidResult result = result_list.Get( i );
+				string uid = result.m_Uid;
+				BiosPrivacyPermissionResultArray result_array = m_PermissionsList.Get( uid );
+				BiosPrivacyPermissionResultArray result_array2 = result.m_Results;
+				if ( result_array && result_array2 )
+				{
+					if ( !BiosPrivacyPermissionResult.Compare( result_array.Get( 0 ), result_array2.Get( 0 ) ) )
+					{
+						new_list.Insert( result );
+						m_PermissionsList.Set( uid, result_array2 );
+					}
+				}
+				else
+				{
+					m_PermissionsList.Insert( uid, result_array2 );
+					new_list.Insert( result );
+				}
+			}
+			m_PermissionsAsyncInvoker.Invoke( new_list );
+		}
+	}
+	
+	static bool IsPlayerMuted( string id )
+	{
+		if ( m_MuteList.Contains( id ) )
+		{
+			return m_MuteList.Get( id );
+		}
+		return false;
+	}
+	
+	static bool MutePlayer( string id, bool mute )
+	{
+		if ( m_MuteList.Contains( id ) )
+		{
+			m_MuteList.Set( id, mute );
+		}
+		else
+		{
+			m_MuteList.Insert( id, mute );
+		}
+		
+		// notify server
+		ScriptInputUserData ctx = new ScriptInputUserData();
+		ctx.Write( INPUT_UDT_USER_MUTE_XBOX );
+		ctx.Write( id );
+		ctx.Write( mute );
+		ctx.Send();
+		
+		return true;
+	}
+	
+	static map<string, bool> GetMuteList()
+	{
+		return m_MuteList;
+	}
+	
+	static void ShowInviteScreen()
+	{
+		#ifdef PLATFORM_CONSOLE
+			GetClientServices();
+			if ( m_ClientServices )
+			{
+				string addr;
+				int port;
+				if ( GetGame().GetHostAddress( addr, port ) )
+				{
+					ErrorCaught( m_ClientServices.GetSessionService().ShowInviteToGameplaySessionAsync( addr, port ) );
+				}
+			}
+			else
+			{
+				DebugPrint.LogErrorAndTrace( "BiosClientServices Error: Service reference does not exist." );
+			}
+		#endif
+	}
+	
+	static void LoadMPPrivilege()
+	{
+		#ifdef PLATFORM_CONSOLE
+			GetClientServices();
+			if ( m_ClientServices )
+			{
+				ErrorCaught( m_ClientServices.GetPrivacyService().GetPrivilegeAsync( EBiosPrivacyPrivilege.MULTIPLAYER_GAMEPLAY, true ) );
+			}
+			else
+			{
+				DebugPrint.LogErrorAndTrace( "BiosClientServices Error: Service reference does not exist." );
+			}
+		#else
+			OnLoadMPPrivilege( EBiosError.OK );
+		#endif
+	}
+	
+	static void LoadVoicePrivilege()
+	{
+		GetClientServices();
+		if ( m_ClientServices )
+		{
+			ErrorCaught( m_ClientServices.GetPrivacyService().GetPrivilegeAsync( EBiosPrivacyPrivilege.COMMUNICATE_VOICE, true ) );
+		}
+		else
+		{
+			DebugPrint.LogErrorAndTrace( "BiosClientServices Error: Service reference does not exist." );
+		}
+	}
+	
+	static void OnLoadMPPrivilege( EBiosError err )
+	{
+		if ( !ErrorCaught( err ) )
+		{
+			g_Game.TryConnect();
+		}
+		else
+		{
+			if ( g_Game.GetGameState() != DayZGameState.MAIN_MENU )
+			{
+				g_Game.MainMenuLaunch();
+			}
+			else
+			{
+				g_Game.SetLoadState( DayZLoadState.MAIN_MENU_START );
+				g_Game.GamepadCheck();
+			}
+		}
+	}
+	
+	static void OnLoadVoicePrivilege( EBiosError err )
+	{
+		if ( g_Game.GetGameState() == DayZGameState.IN_GAME )
+		{
+			#ifdef PLATFORM_PS4
+			GetGame().GetWorld().DisableReceiveVoN( ErrorCaught( err ) );
+			#endif
+			GetGame().GetWorld().DisableTransmitVoN( ErrorCaught( err ) );
+		}
+	}
+	
+	static void SetSessionHandle( string handle )
+	{
+		GetClientServices();
+		if ( m_ClientServices )
+		{
+			m_ClientServices.GetSessionService().m_CurrentHandle = handle;
+		}
+	}
+	
+	static string GetSessionHandle()
+	{
+		GetClientServices();
+		if ( m_ClientServices )
+		{
+			return m_ClientServices.GetSessionService().m_CurrentHandle;
+		}
+		return "";
+	}
+	
+	static void GetSession()
+	{
+		GetClientServices();
+		if ( m_ClientServices )
+		{
+			m_ClientServices.GetSessionService().TryGetSession( GetSessionHandle() );
+		}
+	}
+
+	static BiosUser GetBiosUser()
+	{
+		return m_BiosUser;
+	}
+
+	static void SetBiosUser(BiosUser user)
+	{
+		m_BiosUser = user;
+	}
+
+	
+	static bool GetMultiplayState()
+	{
+		return m_MultiplayState;
+	}
+	
+	static void SetMultiplayState( bool state )
+	{
+		m_MultiplayState = state;
+		bool is_multiplay;
+		if ( ClientData.GetSimplePlayerList() )
+			is_multiplay = state && ( ClientData.GetSimplePlayerList().Count() > 1 );
+
+		if ( m_ClientServices )
+			m_ClientServices.GetSessionService().SetMultiplayState(is_multiplay);
+	}
+	
+	static void EnterGameplaySession()
+	{
+		string addr;
+		int port;
+		if ( GetGame().GetHostAddress( addr, port ) )
+		{
+			GetClientServices();
+			if ( m_ClientServices )
+			{
+				m_ClientServices.GetSessionService().EnterGameplaySessionAsync( addr, port );
+				SetMultiplayState(true);
+			}
+		}
+	}
+	
+	static void LeaveGameplaySession()
+	{
+		GetClientServices();
+		if ( m_ClientServices )
+		{
+			GetServersResultRow currentServerInfo = GetCurrentServerInfo();
+			
+			if ( currentServerInfo )
+				m_ClientServices.GetSessionService().LeaveGameplaySessionAsync(currentServerInfo.m_HostIp, currentServerInfo.m_HostPort);
+			else if ( m_CurrentServerIP != "" )
+				m_ClientServices.GetSessionService().LeaveGameplaySessionAsync(m_CurrentServerIP, m_CurrentServerPort);
+				
+			SetMultiplayState(false);
+			m_FirstFriendsLoad = true;
+			
+			if ( m_FriendsList )
+				m_FriendsList.Clear();
+		}
+	}
+	
+	static void SetGameplayActivity()
+	{
+		string addr;
+		int port;
+		if ( GetGame().GetHostAddress( addr, port ) )
+		{
+			GetClientServices();
+			if ( m_ClientServices )
+			{
+				m_ClientServices.GetSessionService().SetGameplayActivityAsync( addr, port );
+			}
+		}
+	}
+	
+	static void SetPendingInviteList( array<string> invitees )
+	{
+		string addr;
+		int port;
+		if ( GetGame().GetHostAddress( addr, port ) )
+		{
+			GetClientServices();
+			if ( m_ClientServices )
+			{
+				m_PendingInvites = invitees;
+				m_ClientServices.GetSessionService().InviteToGameplaySessionAsync( addr, port, GetPendingInviteList() );
+			}
+		}
+		else
+		{
+			m_PendingInvites = invitees;
+		}
+	}
+	
+	static array<string> GetPendingInviteList()
+	{
+		array<string> already_on_server = ClientData.GetSimplePlayerList();
+		if ( already_on_server && m_PendingInvites )
+		{
+			array<string> new_to_server = new array<string>;
+			foreach ( string invitee : m_PendingInvites )
+			{
+				if ( already_on_server.Find( invitee ) == -1 )
+				{
+					new_to_server.Insert( invitee );
+				}
+			}
+			return new_to_server;
+		}
+		else
+		{
+			return m_PendingInvites;
+		}
+	}
+	
+	static void ClearPendingInviteList( array<string> invitees )
+	{
+		delete m_PendingInvites;
+	}
+	
+	static int m_AutoConnectTries = 0;
+	static void AutoConnectToEmptyServer()
+	{
+		GetClientServices();
+		if ( m_ClientServices && m_AutoConnectTries == 0 )
+		{
+			m_AutoConnectTries = 1;
+			GetFirstServerWithEmptySlotInput input = new GetFirstServerWithEmptySlotInput;
+			input.SetOfficial( true );
+			m_ClientServices.GetLobbyService().GetFirstServerWithEmptySlot( input );
+		}
+	}
+	
+	static GetServersResultRow GetRandomFreeResult( GetFirstServerWithEmptySlotResult results )
+	{
+		GetServersResultRow result;
+		array<ref GetServersResultRow> results_free = new array<ref GetServersResultRow>;
+		
+		if ( results && results.m_Result && results.m_Result.m_Results && results.m_Result.m_Results.Count() > 0 )
+		{
+			foreach ( GetServersResultRow result_temp : results.m_Result.m_Results )
+			{
+				if ( result_temp.m_FreeSlots > 0 )
+				{
+					results_free.Insert( result_temp );
+				}
+			}
+		}
+		
+		return results_free.GetRandomElement();
+	}
+	
+	static void OnAutoConnectToEmptyServer( GetFirstServerWithEmptySlotResult result_list, EBiosError error )
+	{
+		if ( !ErrorCaught( error ) )
+		{
+			GetServersResultRow result = GetRandomFreeResult( result_list );
+			if ( result )
+			{
+				g_Game.ConnectFromServerBrowser( result.m_HostIp, result.m_HostPort );
+				m_AutoConnectTries = 0;
+				return;
+			}
+			else
+			{
+				GetGame().GetUIManager().ShowDialog( "#str_xbox_authentification_fail_title", "#str_xbox_authentification_fail", 232, DBT_OK, DBB_NONE, DMT_INFO, GetGame().GetUIManager().GetMenu() );
+			}
+		}
+		
+		if ( m_AutoConnectTries < 3 )
+		{
+			m_AutoConnectTries++;
+			GetFirstServerWithEmptySlotInput input = new GetFirstServerWithEmptySlotInput;
+			input.SetOfficial( true );
+			m_ClientServices.GetLobbyService().GetFirstServerWithEmptySlot( input );
+		}
+		else
+		{
+			GetGame().GetUIManager().ShowDialog( "#str_xbox_authentification_fail_title", "#xbox_authentification_fail", 232, DBT_OK, DBB_NONE, DMT_INFO, GetGame().GetUIManager().GetMenu() );
+		}
+	}
+	
+	static void GetServerModList( string server_id )
+	{
+		GetClientServices();
+		if ( m_ClientServices )
+		{
+			m_ClientServices.GetLobbyService().GetServerModList( server_id );
+		}
+	}
+	
+	static void OnGetServerModList( GetServerModListResult result_list, EBiosError error )
+	{
+		if ( !ErrorCaught( error ) )
+		{
+			m_ServerModLoadAsyncInvoker.Invoke( result_list );
+		}
+	}
+	
+	static bool IsGameTrial( bool sim )
+	{
+		#ifdef PLATFORM_XBOX
+		#ifndef PLATFORM_WINDOWS
+		if ( m_TrialService )
+			return m_TrialService.IsGameTrial( sim );
+		#endif
+		#endif
+		return false;
+	}
+	
+	static bool IsGameActive( bool sim )
+	{
+		#ifdef PLATFORM_XBOX
+		#ifndef PLATFORM_WINDOWS
+		if ( m_TrialService )
+			return m_TrialService.IsGameActive( sim );
+		#endif
+		#endif
+		return false;
+	}
+	
+	static bool CheckUpdate()
+	{
+		GetClientServices();
+		if ( m_ClientServices )
+		{
+			EBiosError error = m_ClientServices.GetPackageService().CheckUpdateAsync();
+			
+			if ( !error )
+			{
+				return true;
+			}
+		}
+		
+		return false;
+	}
+	
+	static void PromptUpdate()
+	{
+		GetClientServices();
+		if ( m_ClientServices )
+		{
+			m_ClientServices.GetPackageService().PromptUpdateAsync();
+		}
+	}
+}

+ 6 - 0
Scripts/3_game/client/syncdata.c

@@ -0,0 +1,6 @@
+class SyncData
+{
+	int m_SyncInt;
+	ref SyncPlayerList m_ServerPlayerList;
+	ref SyncEntityKillInfo m_EntityKill;
+}

+ 7 - 0
Scripts/3_game/client/syncentitykill.c

@@ -0,0 +1,7 @@
+class SyncEntityKillInfo
+{
+	EntityAI	m_EntityVictim;
+	EntityAI	m_EntityKiller;
+	EntityAI	m_EntitySource;
+	bool		m_IsHeadShot;
+}

+ 12 - 0
Scripts/3_game/client/syncplayer.c

@@ -0,0 +1,12 @@
+class SyncPlayer
+{
+	PlayerIdentity m_Identity;
+
+	//! Keeping for backwards compatability with mods. 
+
+	[NonSerialized()]
+	string m_UID;
+
+	[NonSerialized()]
+	string m_PlayerName;
+}

+ 69 - 0
Scripts/3_game/client/syncplayerlist.c

@@ -0,0 +1,69 @@
+class SyncPlayerList
+{
+	ref array<ref SyncPlayer> m_PlayerList;
+
+	void CreatePlayerList()
+	{
+		if (GetGame().IsServer())
+		{
+			m_PlayerList = new array<ref SyncPlayer>();
+			
+			array<PlayerIdentity> identities = new array<PlayerIdentity>();
+			GetGame().GetPlayerIndentities(identities);
+
+			foreach (auto identity : identities)
+			{
+				SyncPlayer sync_player = new SyncPlayer;
+				sync_player.m_Identity = identity;
+				sync_player.m_UID = identity.GetPlainId();
+				sync_player.m_PlayerName = identity.GetPlainName();
+				m_PlayerList.Insert(sync_player);
+			}
+		}
+	}
+
+	static SyncPlayerList Compare(SyncPlayerList a, SyncPlayerList b)
+	{
+		SyncPlayerList new_list = new SyncPlayerList;
+		new_list.m_PlayerList = new array<ref SyncPlayer>;
+
+		if (!a && b && b.m_PlayerList)
+		{
+			foreach (SyncPlayer player3 : b.m_PlayerList)
+			{
+				new_list.m_PlayerList.Insert(player3);
+			}
+		}
+		else if (a && a.m_PlayerList && !b)
+		{
+			foreach (SyncPlayer player4 : a.m_PlayerList)
+			{
+				new_list.m_PlayerList.Insert(player4);
+			}
+		}
+		else if (a && a.m_PlayerList && b && b.m_PlayerList)
+		{
+			array<ref SyncPlayer> array_a = a.m_PlayerList;
+			array<ref SyncPlayer> array_b = b.m_PlayerList;
+
+			foreach (SyncPlayer player : array_b)
+			{
+				bool found = false;
+				foreach (SyncPlayer player2 : array_a)
+				{
+					if (player.m_UID == player2.m_UID)
+					{
+						found = true;
+						break;
+					}
+				}
+
+				if (!found)
+				{
+					new_list.m_PlayerList.Insert(player);
+				}
+			}
+		}
+		return new_list;
+	}
+}

+ 76 - 0
Scripts/3_game/colors.c

@@ -0,0 +1,76 @@
+//color values and names taken from https://en.wikipedia.org/wiki/X11_color_names
+
+class Colors
+{
+	const int RED					= 0xFF0000;
+	const int CYAN					= 0x00FFFF;
+	const int GRAY					= 0xBEBEBE;
+	const int GREEN					= 0x00FF00;
+	const int PURPLE				= 0xA020F0;
+	const int YELLOW				= 0xFFFF00;
+	const int ORANGE				= 0xFFA500;
+	const int BLUE					= 0x0000FF;
+	const int BLACK					= 0x000000;
+	const int BROWN					= 0xA52A2A;
+	const int WHITE					= 0xFFFFFF;
+	const int WHITEGRAY				= 0xA0A1A1;
+	
+	const int COLOR_DEFAULT			= 0x64000000;
+
+	const int COLOR_RUINED			= 0x00FF0000;
+	const int COLOR_BADLY_DAMAGED	= 0x00FFBF00;
+	const int COLOR_DAMAGED			= 0x00FFFF00;
+	const int COLOR_WORN			= 0x00BFFF00;
+	const int COLOR_PRISTINE		= 0x0040FF00;
+
+	const int COLOR_DRENCHED		= 0x000000FF;
+	const int COLOR_SOAKING_WET 	= 0x003030FF;
+	const int COLOR_WET 			= 0x006060FF;
+	const int COLOR_DAMP 			= 0x009090FF;
+	
+	const int TEMPERATURE_HOT_LVL_FOUR			= 0x009D1A18;
+	const int TEMPERATURE_HOT_LVL_THREE  		= 0x00D92C28;
+	const int TEMPERATURE_HOT_LVL_TWO 			= 0x00DC3E40;
+	const int TEMPERATURE_HOT_LVL_ONE  			= 0x00EE8227;
+	const int TEMPERATURE_NEUTAL				= 0x00999999;
+	const int TEMPERATURE_COLD_LVL_ONE 			= 0x0098D9E9;
+	const int TEMPERATURE_COLD_LVL_TWO 			= 0x007095D3;
+	const int TEMPERATURE_COLD_LVL_THREE  		= 0x004851BD;
+	const int TEMPERATURE_COLD_LVL_FOUR 		= 0x00351BEA;
+
+	const int COLOR_LIQUID 			= 0x0000EEFF;
+	const int COLOR_FROZEN			= 0x006666FF;
+	
+	const int COLOR_RAW				= 0x00BF4242;
+	const int COLOR_BAKED			= 0x00A56D28;
+	const int COLOR_BOILED			= 0x00AF9442;
+	const int COLOR_DRIED			= 0x00FFEB48;
+	const int COLOR_BURNED			= 0x00888888;
+	const int COLOR_ROTTEN			= 0x00A93F15;
+	
+	const int COLOR_DAYZ_RED 				= 0xffd70d11;
+	const int COLOR_DAYZ_DARK_BLUE 			= 0xff13151b;
+	const int COLOR_DAYZ_SMOKY_BLUE 		= 0xff262a33;
+	const int COLOR_DAYZ_WHITE_BLUE 		= 0xfff9fcfe;
+	const int COLOR_DAYZ_LIGHT_SHADE 		= 0xff7d7f85;
+	const int COLOR_DAYZ_WASHOUT 			= 0xffcfd2d6;
+	
+	const int COLOR_LIVONIA_EMERALD_GREEN 	= 0xff4a8765;
+	const int COLOR_LIVONIA_FOREST_GREEN 	= 0xff47533e;
+	const int COLOR_LIVONIA_DARK_GREEN 		= 0xff1c2118;
+	const int COLOR_LIVONIA_BLACK_GREEN 	= 0xff0b100a;
+	const int COLOR_LIVONIA_OLIVE 			= 0xff8e8045;
+	
+	const int COLOR_FROSTLINE_LIGHT_BLUE = 0xff90b2bf;
+	const int COLOR_FROSTLINE_MOUNTAIN_BLUE = 0xff365d6e;
+	const int COLOR_FROSTLINE_DARK_BLUE = 0xff0d1c21;
+}
+
+class FadeColors
+{
+	const int WHITE			= 0xFFFFFFFF;
+	const int LIGHT_GREY	= 0xFFD7D7D7;
+	const int BLACK 		= 0xFF000000;
+	const int RED 			= 0xFFFF0000;
+	const int DARK_RED 		= 0xFF3f0000;
+}

+ 1066 - 0
Scripts/3_game/constants.c

@@ -0,0 +1,1066 @@
+/**
+ * \defgroup CppEnums Internally defined enums
+ * \desc Various enums defined in C++
+ * @{
+ */
+enum ChatChannelType
+{
+	System, 				//!< CCSystem
+	Admin, 					//!< CCAdmin
+	Direct, 				//!< CCDirect
+	Megaphone, 				//!< CCMegaphone
+	Transmitter, 			//!< CCTransmitter
+	PublicAddressSystem, 	//!< CCPublicAddressSystem
+	BattlEye, 				//!< CCBattlEye
+}
+
+enum VoiceLevel
+{
+	Whisper, 	//!< VoiceLevelWhisper
+	Talk, 		//!< VoiceLevelTalk
+	Shout 		//!< VoiceLevelShout
+}
+
+enum VoiceEffectType
+{
+	Mumbling, 		//!< VoiceEffectMumbling
+	Extortion, 		//!< VoiceEffectExtortion
+	Obstruction 	//!< VoiceEffectObstruction
+}
+
+enum ObjIntersect
+{
+	Fire, 	//!< ObjIntersectFire: Fire Geometry
+	View, 	//!< ObjIntersectView: View Geometry
+	Geom,	//!< ObjIntersectGeom: Geometry
+	IFire, 	//!< ObjIntersectIFire: (Indirect) Fire Geometry
+	None 	//!< ObjIntersectNone: No Geometry
+}
+
+enum RoadSurfaceDetection
+{
+	//! Find nearest surface under given point
+	UNDER,
+	//! Find nearest surface above given point
+	ABOVE,
+	//! Find nearest surface to given point
+	CLOSEST,
+	//! Legacy version, UNDER but without proxy support
+	LEGACY,
+}
+
+//! UserID of a parent widget usually matches this value, unless overriden in the 'InitWidgetSet' method
+enum EffectWidgetsTypes
+{
+	ROOT = -2, //used when handling the m_Root widget directly
+	NONE = 0,
+	
+	MASK_OCCLUDER = 1,
+	MASK_BREATH = 2,
+	
+	HELMET_OCCLUDER = 10,
+	HELMET_BREATH = 11,
+	
+	MOTO_OCCLUDER = 20,
+	MOTO_BREATH = 21,
+	
+	COVER_FLASHBANG = 50,
+	NVG_OCCLUDER = 51,
+	PUMPKIN_OCCLUDER = 52,
+	EYEPATCH_OCCLUDER = 53,
+	HELMET2_OCCLUDER = 54,
+	
+	BLEEDING_LAYER = 60,
+}
+
+enum EffectWidgetHandles
+{
+	FLASHBANG,
+}
+
+enum EffectWidgetSuspends
+{
+	BURLAPSACK,
+	UNCON,
+}
+
+class HitDirectionConstants
+{
+	const int ROTATION_DEFAULT = 0; //0 == random
+	const float DURATION_BASE = 2.0;
+	const float BREAKPOINT_BASE = 0.2;
+	const float DISTANCE_ADJUST = 0.0;
+	const float SCATTER = 10.0;
+	const int COLOR_DEFAULT = 0xffbb0a1e;
+}
+
+enum HitDirectionModes
+{
+	DISABLED,
+	STATIC,
+	DYNAMIC
+}
+
+enum HitIndicatorType
+{
+	SPLASH,
+	SPIKE,
+	ARROW
+}
+
+enum EInputRestrictors
+{
+	INVENTORY,
+	MAP
+}
+
+enum EPollution // FLAG - 1,2,4,8...
+{
+	NONE 			= 0,
+	HEAVYMETAL		= 1,
+	//POLLUTION2	= 2,
+	//POLLUTION3	= 4,
+}
+
+/** @}*/
+
+//! how often virtual hud checks if there is a difference since last sync
+const int VIRTUAL_HUD_UPDATE_INTERVAL = 1000;
+
+/**
+ * \defgroup UI UI
+ * \desc constants User Interface
+ * @{
+ */
+const int IDC_OK					= 1;
+const int IDC_CANCEL				= 2;
+const int IDC_RESTART				= 5;
+
+const int IDC_MAIN_NEXT_CHARACTER	= 50;
+const int IDC_MAIN_PREV_CHARACTER	= 51;
+
+const int IDC_MAIN_OPTIONS      	= 102;
+const int IDC_MAIN_MULTIPLAYER  	= 105;
+const int IDC_MAIN_QUIT         	= 106;
+const int IDC_MAIN_CONTINUE			= 114;
+const int IDC_MAIN_PLAY         	= 142;
+const int IDC_MAIN_CHARACTER		= 143;
+const int IDC_MAIN_ONLINE			= 124;
+const int IDC_MULTI_REFRESH			= 123;
+const int IDC_MULTI_INVITE			= 126;
+
+const int IDC_BOOK_VIEWER_PREV  	= 102;
+const int IDC_BOOK_VIEWER_NEXT  	= 103;
+
+//! ingame menu
+const int IDC_INT_RETRY				= 105; //default respawn
+const int IDC_INT_RETRY_CUSTOM		= 106; //custom respawn
+const int IDC_INT_EXIT				= 107;
+//const int IDC_INT_RESPAWN			= 108; //respawn dialogue
+/** @}*/
+
+/**
+ * \defgroup MenuID MenuID
+ * \desc constants for menu pages
+ * @{
+ */
+
+const int MENU_ANY									= 1;
+const int MENU_NONE									= 2;
+const int MENU_LOC_ADD								= 3;
+const int MENU_UNKNOWN								= 4;
+const int MENU_CHARACTER							= 5;
+const int MENU_CHAT									= 6;
+const int MENU_EARLYACCESS							= 7;
+const int MENU_SCENE_EDITOR							= 8;
+const int MENU_INGAME								= 9;
+const int MENU_INSPECT								= 10;
+const int MENU_INVENTORY							= 11;
+const int MENU_LOADING								= 12;
+const int MENU_MAIN									= 13;
+const int MENU_OPTIONS								= 14;
+const int MENU_STARTUP								= 15;
+const int MENU_SCRIPTCONSOLE						= 16;
+const int MENU_CHAT_INPUT							= 17;
+const int MENU_SCRIPTCONSOLE_DIALOG_PRESET_NAME		= 18;
+const int MENU_SCRIPTCONSOLE_DIALOG_PRESET_RENAME 	= 19;
+const int MENU_CONTROLS_PRESET						= 20;
+const int MENU_NOTE									= 21;
+const int MENU_MAP									= 22;
+const int MENU_BOOK									= 23;
+const int MENU_HELP_SCREEN      					= 24;
+const int MENU_GESTURES		      					= 25;
+const int MENU_LOGOUT 								= 26;
+const int MENU_TITLE_SCREEN							= 27;
+const int MENU_XBOX_CONTROLS						= 28;
+const int MENU_RADIAL_QUICKBAR						= 29;
+const int MENU_LOGIN_QUEUE							= 30;
+const int MENU_SERVER_BROWSER						= 31;
+const int MENU_CAMERA_TOOLS							= 32;
+const int MENU_VIDEO								= 33;
+const int MENU_KEYBINDINGS							= 34;
+const int MENU_TUTORIAL								= 35;
+const int MENU_CREDITS								= 36;
+const int MENU_INVITE_TIMER							= 37;
+const int MENU_LOGIN_TIME							= 38;
+const int MENU_WARNING_ITEMDROP						= 39;
+const int MENU_RESPAWN_DIALOGUE						= 40;
+const int MENU_WARNING_TELEPORT						= 41;
+const int MENU_CONNECT_ERROR						= 42;
+const int MENU_WARNING_INPUTDEVICE_DISCONNECT		= 43;
+const int MENU_SCRIPTCONSOLE_UNIVERSAL_INFO_DIALOG	= 44;
+const int MENU_MISSION_LOADER						= 45;
+
+
+const int GUI_WINDOW_MISSION_LOADER = 1;
+
+const string CFG_VEHICLESPATH = "CfgVehicles";
+const string CFG_WEAPONSPATH = "CfgWeapons";
+const string CFG_MAGAZINESPATH = "CfgMagazines";
+const string CFG_AMMO = "CfgAmmo";
+const string CFG_WORLDS = "CfgWorlds";
+const string CFG_SURFACES = "CfgSurfaces";
+const string CFG_RECIPESPATH = "CfgRecipes";
+const string CFG_SOUND_SHADERS = "CfgSoundShaders";
+const string CFG_SOUND_SETS = "CfgSoundSets";
+const string CFG_NONAI_VEHICLES = "CfgNonAIVehicles";
+const string CFG_SOUND_TABLES = "CfgSoundTables";
+
+/** @}*/
+
+/**
+ * \defgroup CFGConstants Local data saving to files
+ * \desc constants for saving local datas
+ * @{
+ */
+const int		CFG_ARRAY_ITEMS_MAX		= 64;
+const string	CFG_FILE_FIXED_PROFILE	= "Scripts/profile_fixed.cfg";
+const string	CFG_FILE_USER_PROFILE	= "$profile:profile.cfg";
+const string	CFG_FILE_DEBUG_PROFILE	= "debugProfile.cfg";
+const string	CFG_FILE_EMOTES_PROFILE	= "$profile:emotesProfile.cfg";
+const string	CFG_FILE_SEARCH_HISTORY	= "$profile:search_history.history";
+const string	CFG_FILE_ENS_HISTORY	= "script_enscript.history";
+const string	CFG_FILE_ENS_HISTORY_SERVER	= "script_enscriptServer.history";
+const string	CFG_FILE_SCRIPT_LOG		= "$profile:script.log";
+const string	CFG_FILE_SCRIPT_LOG_EXT	= "$profile:scriptExt.log";
+const string 	CFG_FILE_DEBUG_DIR =	"$profile:ScriptConsole/";
+const string 	CFG_FILE_MISSION_LIST =	"$profile:missionlist.json";
+/** @}*/
+
+/**
+ * \defgroup RPC RPC commands
+ * \desc Constants for sending RPC commands on server
+ * @{
+ */
+/*
+const int RPC_SYNC_ITEM_VAR                     = 1;
+const int RPC_SYNC_STAT                         = 2;
+const int RPC_WRITE_NOTE                        = 3;
+const int RPC_SYNC_DISPLAY_STATUS               = 4;
+const int RPC_RECIPE_SEND    					= 7;
+const int RPC_ON_SET_CAPTIVE					= 8;
+const int RPC_SYNC_SCENE_OBJECT					= 9;
+const int RPC_READ_A_BOOK               		= 10;	
+const int RPC_USER_ACTION_PROMPT_SYNCH			= 11;
+const int RPC_USER_ACTION_MESSAGE 				= 12;
+const int RPC_ITEM_DIAG							= 13;
+const int RPC_ITEM_DIAG_CLOSE					= 14;
+const int RPC_SET_OBJECT_POSITION 				= 15;
+const int RPC_USER_ACTION_MESSAGES 				= 16;
+const int RPC_ITEM_SPLIT						= 17;
+const int RPC_ITEM_COMBINE						= 18;
+const int RPC_PLAYER_STATES_ON					= 19;
+const int RPC_PLAYER_STATES_OFF					= 20;
+const int RPC_PLACING_DEBUG						= 21;
+const int RPC_PLACING_START						= 22;
+const int RPC_PLACING_STOP						= 23;
+const int RPC_STAMINA							= 25;
+const int RPC_DAMAGE_VALUE_SYNC					= 26;
+const int RPC_USER_ACTION_PROMPT_PROGRESS		= 27;
+const int RPC_PLACING_UPDATE					= 28;
+const int RPC_USER_ACTION_PROMPT_CLEAN			= 29;
+const int RPC_DISABLE_MODIFIERS					= 30;
+const int RPC_KILL_PLAYER						= 31;
+const int RPC_ENABLE_INVINCIBILITY				= 32;
+const int RPC_ITEM_DEBUG_ACTIONS				= 33;
+const int RPC_LOG_PLAYER_STATS					= 34;
+const int RPC_EM_IS_PLUGGED						= 35;
+const int RPC_EM_IS_UNPLUGGED					= 36;
+*/
+/** @}*/
+
+
+/**
+ * \defgroup DeveloperRPC Developer RPC commands
+ * \desc Constants for sending developer RPC commands on server
+ * @{
+ */
+/*
+const int DEV_RPC_SPAWN_GROUND_ITEM             = 101;
+const int DEV_RPC_CLEAR_INV                     = 102;
+const int DEV_RPC_TELEPORT                      = 103;
+const int DEV_RPC_SET_PLAYER_DIRECTION          = 104;
+const int DEV_RPC_SEND_SERVER_LOG               = 105;
+const int DEV_RPC_STATS_DATA					= 107;
+const int DEV_RPC_MODS_DATA						= 108;
+const int DEV_RPC_AGENTS_DATA					= 109;
+const int DEV_RPC_CREATE_SCENE_OBJECT 			= 110;
+const int DEV_RPC_SCENE_LOAD 					= 111;
+const int DEV_RPC_SPAWN_INV_ITEM                = 112;
+const int DEV_RPC_SPAWN_ATTACHMENT_ITEM         = 113;
+const int DEV_RPC_SPAWN_ITEM_ON_CURSOR          = 114;
+*/
+/** @}*/
+
+/**
+ * \defgroup SyncCMD Sync update commands
+ * \desc Constants for synchronization update commands
+ * @{
+ */
+	/*
+const int DEV_STATS_UPDATE						= 1;
+const int DEV_MODS_UPDATE						= 2;
+const int DEV_AGENTS_UPDATE						= 3;
+	*/
+/** @}*/
+
+/**
+ * \defgroup MessageCMD Message commands
+ * \desc Messaging System - the numbers must be 0 or higher, and the highest number should not be bigger than NUM_OF_CHANNELS-1
+ * @{
+ */
+const int NUM_OF_CHANNELS 		= 100;
+const int MSG_TEST_CHANNEL		= 0;
+const int MSG_IMMUNE_REACTION	= 1;
+const int MSG_STATS_SYNCED		= 2;
+const int MSG_NOTIFIERS_TICK	= 3;
+/** @}*/
+	
+/**
+ * \defgroup Modifier pools minimum tick times in ms
+ * \desc Modifier pools minimum tick times
+ * @{
+ */
+const int MIN_TICK_MDFR_POOL_MAIN = 10000;//in ms
+const int MIN_TICK_MDFR_POOL_PLAYER = 3000;
+const int MIN_TICK_MDFR_POOL_ENVIRONMENT = 3000;
+const int MIN_TICK_MDFR_POOL_DISEASE = 30000;
+const int MIN_TICK_NOTIFIERS = 1000;
+/** @}*/
+
+/**
+ * \defgroup EmoteIDs Emote ids
+ * @{
+ */
+class EmoteConstants
+{
+	const int ID_EMOTE_GREETING			= 1;
+	const int ID_EMOTE_SOS				= 2; //FB
+	const int ID_EMOTE_HEART 			= 3;
+	const int ID_EMOTE_TAUNT	 		= 4;
+	const int ID_EMOTE_LYINGDOWN		= 5;
+	const int ID_EMOTE_TAUNTKISS		= 6;
+	const int ID_EMOTE_FACEPALM			= 7;
+	const int ID_EMOTE_TAUNTELBOW		= 8;
+	const int ID_EMOTE_THUMB			= 9;
+	const int ID_EMOTE_THROAT		 	= 10;
+	const int ID_EMOTE_SUICIDE			= 11; //FB
+	const int ID_EMOTE_DANCE 			= 12;
+	const int ID_EMOTE_CAMPFIRE 		= 13;
+	const int ID_EMOTE_SITA 			= 14;
+	const int ID_EMOTE_SITB 			= 15;
+	const int ID_EMOTE_THUMBDOWN 		= 16;
+	
+	const int ID_EMOTE_DABBING 		= 32;
+	const int ID_EMOTE_TIMEOUT 		= 35;
+	const int ID_EMOTE_CLAP 		= 39;
+	const int ID_EMOTE_POINT 		= 40;
+	const int ID_EMOTE_SILENT 		= 43;
+	const int ID_EMOTE_SALUTE 		= 44;
+	const int ID_EMOTE_RPS 			= 45;
+	const int ID_EMOTE_WATCHING 	= 46;
+	const int ID_EMOTE_HOLD 		= 47;
+	const int ID_EMOTE_LISTENING 	= 48;
+	const int ID_EMOTE_POINTSELF 	= 49;
+	const int ID_EMOTE_LOOKATME 	= 50;
+	const int ID_EMOTE_TAUNTTHINK 	= 51;
+	const int ID_EMOTE_MOVE 		= 52;
+	const int ID_EMOTE_DOWN 		= 53;
+	const int ID_EMOTE_COME 		= 54;
+	const int ID_EMOTE_RPS_R 		= 55;
+	const int ID_EMOTE_RPS_P 		= 56;
+	const int ID_EMOTE_RPS_S 		= 57;
+	const int ID_EMOTE_NOD 			= 58;
+	const int ID_EMOTE_SHAKE 		= 59;
+	const int ID_EMOTE_SHRUG 		= 60;
+	const int ID_EMOTE_SURRENDER 	= 61;
+	const int ID_EMOTE_VOMIT 		= 62;
+	const int ID_EMOTE_DEBUG 		= 1000;
+	
+	/**
+	 * \defgroup CustomEmoteIDs Custom animation events ID for emotes
+	 * \desc used mainly in suicide emotes
+	 * @{
+	 */
+	const int EMOTE_SUICIDE_DEATH 	= 1;
+	const int EMOTE_SUICIDE_BLEED 	= 2;
+	const int EMOTE_SUICIDE_SIMULATION_END = 3;
+	/** @}*/
+}
+
+/**
+ * \defgroup ItemGeneratorCfg Configurations for ItemsGenerator class
+ * \desc Configurations for ItemsGenerator class
+ * @{
+ */
+const float		ITEMSGEN_TICK = 10; //in seconds
+const float		ITEMSGEN_MIN_DISTANCE_TO_REPOSITION = 80; //in meters
+const float		ITEMSGEN_SPAWN_DISTANCE = 60; //in meters
+const float		ITEMSGEN_MAX_SPREAD = 15; //in meters
+const int		ITEMSGEN_ITEMS_AMOUNT = 5;
+/** @}*/
+
+
+/**
+ * \defgroup SATIDs Selectable action types ids
+ * \desc These ids helsp diferentiate types of selectable actions 
+ * @{
+ */
+const int SAT_INTERACT_ACTION	= 1;
+const int SAT_CRAFTING	 		= 2;
+const int SAT_DEBUG_ACTION		= 3;
+/** @}*/
+
+/**
+ * \defgroup UAIDs User action internal state machine states
+ * \desc User action internal state machine states
+ * @{
+ */
+const int 		UA_NONE = 0;
+const int 		UA_FAILED = 1;
+const int 		UA_PROCESSING = 2;
+const int 		UA_REPEAT = 3;
+const int 		UA_FINISHED = 4;
+const int		UA_CANCEL = 5;
+const int		UA_INTERRUPT = 6;
+const int       UA_START = 7;
+const int       UA_STARTT = 8;
+const int       UA_CANCELT = 9;
+const int       UA_FINISHEDT = 10;
+const int    	UA_ANIM_EVENT = 11;
+const int 		UA_INITIALIZE = 12;
+const int		UA_CHECK_CON = 13;
+const int		UA_AM_PENDING = 14;
+const int		UA_AM_ACCEPTED = 15;
+const int		UA_AM_REJECTED = 16;
+const int		UA_IN_START = 17;
+const int		UA_IN_END = 18;
+const int		UA_SPAWN_DUST_A = 19;
+const int		UA_SPAWN_DUST_B = 20;
+const int		UA_IN_CRAFTING = 21;
+	
+const int		UA_ERROR = 24;
+	
+const int		UA_SETEND_2 = 32;
+/** @}*/
+
+/**
+
+ * \defgroup AGTIDs Agent transmission system
+ * \desc Agent transmission system
+ * @{
+ */
+const int AGT_NONE				= 0;
+const int AGT_INV_IN	 		= 1;
+const int AGT_INV_OUT	 		= 2;
+const int AGT_UACTION_CONSUME	= 3;
+const int AGT_TRANSFER_COPY	= 4;
+const int AGT_UACTION_TOUCH		= 5;
+const int AGT_WATER_POND		= 6;
+const int AGT_AIRBOURNE_BIOLOGICAL	= 7;
+const int AGT_UACTION_TO_PLAYER	= 8;
+const int AGT_UACTION_TO_ITEM	= 9;
+const int AGT_ITEM_TO_FLESH		= 10;
+const int AGT_AIRBOURNE_CHEMICAL = 11;
+const int AGT_SNOW				= 12;
+const int AGT_WATER_FRESH		= 13;
+const int AGT_WATER_HOT_SPRING	= 14;
+
+const int DEF_BIOLOGICAL		= 1;
+const int DEF_CHEMICAL			= 2;
+/** @}*/
+			
+const int QUANTITY_HIDDEN = 0;
+const int QUANTITY_COUNT = 1;
+const int QUANTITY_PROGRESS = 2;
+
+
+			
+/**
+ * \defgroup LiquidTypes LiquidTypes
+ * \desc Constants for liquid types
+ * @{
+ */
+// BEWARE ALL INDIVIDUAL LIQUID TYPES ARE ALSO REPRESENTED CONFIG-SIDE AND MUST MATCH(all changes must be made on both sides)
+// NOTE ANY NUMBER HERE MUST BE A 0 OR ANY POWER OF TWO, THERE IS A MAXIMUM OF 32 INDIVIDUAL LIQUID TYPES POSSIBLE
+const int LIQUID_NONE		= 0;
+
+const int LIQUID_BLOOD_0_P	= 1;
+const int LIQUID_BLOOD_0_N	= 2;
+const int LIQUID_BLOOD_A_P	= 4;
+const int LIQUID_BLOOD_A_N	= 8;
+const int LIQUID_BLOOD_B_P	= 16;
+const int LIQUID_BLOOD_B_N	= 32;
+const int LIQUID_BLOOD_AB_P	= 64;
+const int LIQUID_BLOOD_AB_N = 128;
+const int LIQUID_SALINE 	= 256;
+
+const int LIQUID_WATER			= 512;		// base water liquid type, LIQUID_GROUP_DRINKWATER translates into this type within script
+const int LIQUID_RIVERWATER		= 1024;		// unused? river surfaces are using FRESHWATER
+const int LIQUID_VODKA 			= 2048;
+const int LIQUID_BEER 			= 4096;
+const int LIQUID_GASOLINE 		= 8192;
+const int LIQUID_DIESEL 		= 16384;
+const int LIQUID_DISINFECTANT 	= 32768;
+const int LIQUID_SOLUTION 		= 65536;
+const int LIQUID_SNOW 			= 131072;
+const int LIQUID_SALTWATER 		= 262144;
+const int LIQUID_FRESHWATER 	= 524288;	// used by river/pond surfaces
+const int LIQUID_STILLWATER 	= 1048576;	// used for unfishable surfaces
+const int LIQUID_HOTWATER	 	= 2097152;	// hot springs
+const int LIQUID_CLEANWATER		= 4194304;	// clean water from wells / rain
+
+const int LIQUID_GROUP_DRINKWATER 	= LIQUID_WATER | LIQUID_RIVERWATER | LIQUID_SNOW | LIQUID_FRESHWATER | LIQUID_STILLWATER | LIQUID_HOTWATER | LIQUID_CLEANWATER;
+const int LIQUID_GROUP_WATER 		= LIQUID_GROUP_DRINKWATER | LIQUID_SALTWATER;
+
+// these are groups which do not have to correspond with configs
+const int GROUP_LIQUID_BLOOD = 255;
+const int GROUP_LIQUID_ALL = -1;//-1 = all bits to 1
+/** @}*/
+
+/**
+ * \defgroup LiquidThroughputs LiquidThroughputs
+ * \desc Constants for liquid transfer speeds
+ * @{
+ */
+const float LIQUID_THROUGHPUT_TINY = 0.1;
+const float LIQUID_THROUGHPUT_DEFAULT = 1.0;
+const float LIQUID_THROUGHPUT_GASOLINECANISTER = 10.0;
+const float LIQUID_THROUGHPUT_CAR_DEFAULT = 1.0;
+const float LIQUID_THROUGHPUT_GENERATOR = 10.0;
+const float LIQUID_THROUGHPUT_FUELSTATION = 20.0;
+const float LIQUID_THROUGHPUT_WELL = 15.0;
+const float LIQUID_THROUGHPUT_BARREL = 100.0;
+
+/** @}*/
+	
+/**
+ * \defgroup ChatMessagesVisibility ChatMessagesVisibility
+ * \desc Constants for toggle chat messages type visibility
+ * @{
+ */
+const string SYSTEM_CHAT_MSG 	= "system_chat_msg";
+const string GLOBAL_CHAT_MSG 	= "global_chat_msg";
+const string DIRECT_CHAT_MSG	= "direct_chat_msg";
+const string VEHICLE_CHAT_MSG 	= "vehicle_chat_msg";
+const string RADIO_CHAT_MSG 	= "radio_chat_msg";	
+const string GAME_CHAT_MSG 		= "game_chat_msg";	
+const string ADMIN_CHAT_MSG 	= "admin_chat_msg";	
+const string PLAYER_CHAT_MSG 	= "player_chat_msg";	
+/** @}*/
+
+/**
+ * \defgroup HUDVisibility HUDVisibility
+ * \desc Constants for toggling of HUD visibility
+ * @{
+ */
+const string SHOW_QUICKBAR 		= "show_quickbar";
+const string SHOW_HUD 			= "show_hud";
+const string SHOW_HUD_VEHICLE 	= "show_hud_vehicle";
+const string HUD_BRIGHTNESS		= "hud_brightness";
+const string ENABLE_BLEEDINGINDICATION	= "enable_bleedingindication";
+const string SHOW_CONNECTIVITYINFO	= "show_connectivityinfo";
+//const string SHOW_HUD_AUTOHIDE 	= "hud_autohide";
+const string SHOW_CROSSHAIR 	= "show_crosshair";
+const string SHOW_SERVERINFO 	= "show_serverinfo";
+/** @}*/
+
+const string OPTIONS_SOUND_AMBIENT_SOUND_MODE = "ambient_sound_mode";
+
+/**
+ * \defgroup LockConstants Controls locks
+ * \desc Constants for toggling of alternate 
+ * @{
+ */
+const string LOCK_SPRINT 	= "lock_sprint";
+const string LOCK_FREELOOK 	= "lock_freelook";
+const string LOCK_ZOOM 		= "lock_zoom";
+/** @}*/
+
+/**
+ * \defgroup ItemVariables Item Variables
+ * \desc Constants for Item Variables
+ * @{
+ */
+const int VARIABLE_QUANTITY 	= 1;
+const int VARIABLE_ENERGY 		= 2;
+const int VARIABLE_TEMPERATURE 	= 4;
+const int VARIABLE_WET 			= 8;
+const int VARIABLE_LIQUIDTYPE	= 16;
+const int VARIABLE_ISLIT		= 32;
+const int VARIABLE_COLOR		= 64;
+const int VARIABLE_CLEANNESS	= 128;
+/** @}*/
+
+const float CRAFTING_TIME_UNIT_SIZE = 4.0;// time unit size for crafting, this value is multiplied by the length given by a recipe
+
+const float PROJECTED_CURSOR_DISTANCE = 5;//how long is the raycast from the weapon for projected cursor
+
+
+/**
+  * \ misc
+ */
+
+const float DEBUG_QUICK_UNRESTRAIN_TIME = 1.0;
+const float MELEE_ITEM_DAMAGE = 0.35;
+
+const int HAIR_SELECTION_COUNT = 45;
+/**
+* \ input exclude types; DEPRECATED (confusing)
+*/
+const int INPUT_EXCLUDE_ALL = 0;
+const int INPUT_EXCLUDE_INVENTORY = 1;
+const int INPUT_EXCLUDE_MOUSE_ALL = 2;
+const int INPUT_EXCLUDE_MOUSE_RADIAL = 3;
+const int INPUT_EXCLUDE_MAP = 4;
+
+class GameConstants
+{
+	/**
+	 * \defgroup StaminaHandlerCfg Configurations for StaminaHandler class
+	 * \desc Configurations for StaminaHandler class
+	 * @{
+	 */
+		// unit = currently percent (stamina max is 100)
+	const int 	STAMINA_DRAIN_STANDING_SPRINT_PER_SEC = 4; //in units (how much sprint depletes stamina)
+	const int 	STAMINA_DRAIN_CROUCHED_SPRINT_PER_SEC = 1; //in units (how much sprint in crouch depletes stamina)
+	const int 	STAMINA_DRAIN_PRONE_SPRINT_PER_SEC = 3; //in units (how much sprint in prone depletes stamina)
+	const int	STAMINA_DRAIN_SWIM_FAST_PER_SEC = 5; //in units (how much fast swimming depletes stamina)
+	const int	STAMINA_DRAIN_LADDER_FAST_PER_SEC = 8; //in units (how much fast ladder climb depletes stamina)
+	
+	const float	STAMINA_DRAIN_HOLD_BREATH_START = 0.2; //in units (how much holding breath depletes stamina at the start)
+	const float	STAMINA_DRAIN_HOLD_BREATH_END = 1.0; //in units (how much holding breath depletes stamina at the end)
+	const float	STAMINA_DRAIN_JUMP = 25;		// in units (how much jumping depletes stamina)
+	const float	STAMINA_DRAIN_VAULT = 20;		// in units (how much jumping depletes stamina)
+	const float	STAMINA_DRAIN_CLIMB = 42;		// in units (how much jumping depletes stamina)
+	const float	STAMINA_DRAIN_MELEE_LIGHT = 5; //in units (how much light melee punch depletes stamina)
+	const float	STAMINA_DRAIN_MELEE_HEAVY = 25; //in units (how much heavy melee punch depletes stamina)
+	const float	STAMINA_DRAIN_MELEE_EVADE = 8; // in units (how much evade depletes stamina)
+	const float	STAMINA_DRAIN_ROLL = 5; // in units (how much roll depletes stamina)
+	
+	const float STAMINA_DRAIN_HOLD_BREATH_DURATION = 5.0; //in seconds, time it takes to increase stamina drain from STAMINA_DRAIN_HOLD_BREATH_START to STAMINA_DRAIN_HOLD_BREATH_END
+	const float	STAMINA_DRAIN_HOLD_BREATH_EXPONENT = 3; //holding breath exponent
+	
+	const int 	STAMINA_GAIN_JOG_PER_SEC = 2; //in units (how much of stamina units is gained while jogging)
+	const int 	STAMINA_GAIN_WALK_PER_SEC = 4; //in units (how much of stamina units is gained while walking)
+	const int 	STAMINA_GAIN_IDLE_PER_SEC = 5; //in units (how much of stamina units is gained while iddling)
+	const int	STAMINA_GAIN_SWIM_PER_SEC = 1; //in units (how much of stamina units is gained while slowly swim)
+	const int	STAMINA_GAIN_LADDER_PER_SEC = 1; //in units (how much of stamina units is gained while slowly swim)
+	const int	STAMINA_GAIN_ROLL_PER_SEC = 0; //in units (how much of stamina units is gained while rolling)
+	const float STAMINA_GAIN_BONUS_CAP = 3.0; //in units (tells how much extra units can be added at best to stamina regain)
+	
+	const float STAMINA_KG_TO_STAMINAPERCENT_PENALTY = 1.75; //in units (by how many  units is max stamina bar reduced for each 1 kg of load weight)
+	const float STAMINA_MIN_CAP = 5; //in units (overload won't reduce max stamina bar under this value)
+	const float STAMINA_HOLD_BREATH_THRESHOLD_ACTIVATE = 10; // in units
+	const float STAMINA_HOLD_BREATH_THRESHOLD_DRAIN = 0; // in units
+	const float STAMINA_JUMP_THRESHOLD = 25; // in units
+	const float STAMINA_VAULT_THRESHOLD = 20; // in units
+	const float STAMINA_CLIMB_THRESHOLD = 42; // in units
+	const float STAMINA_ROLL_THRESHOLD = 5; // in units
+	
+	
+	const float STAMINA_MELEE_HEAVY_THRESHOLD = STAMINA_DRAIN_MELEE_HEAVY; // in units (how many units we need to make a heavy hit in melee)
+	const float STAMINA_MELEE_EVADE_THRESHOLD = 8; // in units
+	const float STAMINA_REGEN_COOLDOWN_DEPLETION = 0.45; // in secs (how much time we will spend in cooldown before the stamina will starts with regeneration)
+	const float STAMINA_REGEN_COOLDOWN_EXHAUSTION = 0.5;
+	const float STAMINA_WEIGHT_LIMIT_THRESHOLD = 6000; //! in grams (weight where the player is not penalized by stamina)
+	const float STAMINA_KG_TO_GRAMS = 1000; //for kg to g conversion
+	const float STAMINA_SYNC_RATE = 0.5; //in secs
+	const float STAMINA_MAX = 100;
+	/** @}*/
+	
+	/**
+	 * \defgroup EnvironmentCfg Configurations for Environment class
+	 * \desc Configurations for Environment class
+	 * @{
+	 */
+	const float ENVIRO_TICK_RATE 						= 3;		//! in secs. how often should enviro effet process
+	const float	ENVIRO_TICKS_TO_WETNESS_CALCULATION 	= 2;	  	//! each X (ticks) is processed wetness on items on player
+	const float ENVIRO_TICK_ROOF_RC_CHECK 				= 10;	  	//! in secs. how often we should check if player is under the roof (raycast)
+	const float ENVIRO_WET_INCREMENT 					= 0.01;	  	//! amount of wetness added to items wet value each tick if is raining
+	const float ENVIRO_DRY_INCREMENT 					= 0.00005; 	//! amount of wetness subtracted from items wet value each tick if is not raining due to player heat
+	const float ENVIRO_SUN_INCREMENT 					= 0.002;	//! (not used) amount of wetness subtracted from items wet value each tick if is not raining due to sun
+	const float ENVIRO_FIRE_INCREMENT					= 23.5;		//! how much is the generic temp effect increased when player is next to a fireplace
+	const float ENVIRO_CLOUD_DRY_EFFECT 				= 0.7;		//! how many % of ENVIRO_SUN_INCREMENT is reduced by cloudy sky
+	const float ENVIRO_FOG_DRY_EFFECT 					= 0.9;		//! how many % of ENVIRO_SUN_INCREMENT is reduced by fog
+	const float ENVIRO_FOG_TEMP_EFFECT 					= -2;		//! how strong the effect of fog is
+	const float ENVIRO_WET_PENALTY 						= 0.5;		//! at which state of item wetness (0-1) will heat isolation start having negative effect on heat comfort of item
+	const float ENVIRO_WET_PASSTHROUGH_COEF 			= 0.1;		//! how many times slower is wetting/drying items in backpacks
+	const float ENVIRO_DEFAULT_ENTITY_HEAT 				= 2.5;		//! heat entity generates if not moving
+	const float ENVIRO_TEMPERATURE_INSIDE_VEHICLE_COEF	= 0.051;	//! increases temp inside vehicles
+	const float ENVIRO_TEMPERATURE_UNDERROOF_COEF		= 0.75;		//! underroof wind multiplier
+	const float ENVIRO_TEMPERATURE_WIND_COEF			= 2.5;		//! windchill effect on base temperature
+	const float ENVIRO_WIND_EFFECT 						= 0.25;		//! amount of % wind affect drying/wetting
+	const float ENVIRO_HIGH_NOON 						= 12;		//! when is sun highest on sky
+	
+	const float ENVIRO_HEATCOMFORT_MAX_STEP_SIZE 		= 0.25;		//! max step of dynamic heatcomfort change (applies if diff between target and dynamic HC is bigger than this value)
+	
+	static const float ENVIRO_HEATCOMFORT_HEADGEAR_WEIGHT		= 0.05;		//! how much this body part affects final heatcomfort
+	static const float ENVIRO_HEATCOMFORT_MASK_WEIGHT			= 0.05;
+	static const float ENVIRO_HEATCOMFORT_VEST_WEIGHT			= 0.04;
+	static const float ENVIRO_HEATCOMFORT_BODY_WEIGHT			= 0.12;
+	static const float ENVIRO_HEATCOMFORT_BACK_WEIGHT			= 0.03;
+	static const float ENVIRO_HEATCOMFORT_GLOVES_WEIGHT			= 0.04;
+	static const float ENVIRO_HEATCOMFORT_LEGS_WEIGHT			= 0.12;
+	static const float ENVIRO_HEATCOMFORT_FEET_WEIGHT			= 0.06;
+	static const float ENVIRO_HEATCOMFORT_HIPS_WEIGHT			= 0.00;
+	//! don't forget to update the weights from above if you are adding/removing them
+	static const float ENVIRO_HEATCOMFORT_WEIGHT_SUMMARY 		= ENVIRO_HEATCOMFORT_HEADGEAR_WEIGHT + ENVIRO_HEATCOMFORT_MASK_WEIGHT +ENVIRO_HEATCOMFORT_VEST_WEIGHT + ENVIRO_HEATCOMFORT_BODY_WEIGHT + ENVIRO_HEATCOMFORT_BACK_WEIGHT + ENVIRO_HEATCOMFORT_GLOVES_WEIGHT + ENVIRO_HEATCOMFORT_LEGS_WEIGHT + ENVIRO_HEATCOMFORT_FEET_WEIGHT + ENVIRO_HEATCOMFORT_HIPS_WEIGHT;
+	
+	const float ENVIRO_STOMACH_WEIGHT					= 0.2;		//! how much stomach content affects final heatcomfort
+	const float ENVIRO_LOW_TEMP_LIMIT					= -20;		//! lowest temperature(deg Celsius) where the player gets lowest possible heat comfort (-1)
+	const float ENVIRO_HIGH_TEMP_LIMIT					= 70;		//! highest temperature(deg Celsius) where the player gets highest possible heat comfort (1)
+	const float ENVIRO_PLAYER_COMFORT_TEMP				= 24;		//! comfort temperature of environment for the player
+	const float ENVIRO_TEMP_EFFECT_ON_PLAYER			= 40;		//! impact of enviro temperature on player (lower value = higher, cannot be zero or below!)
+	const float ENVIRO_PLAYER_HEATBUFFER_WATEREFFECT	= 20;		//! impact of water contact on player's heatbuffer
+	const float ENVIRO_PLAYER_HEATBUFFER_DECREASE		= 0.03;		//! How much heat buffer decreases per one enviro tick
+	const float ENVIRO_PLAYER_HEATBUFFER_INCREASE		= 0.3;		//! How much heat buffer increases per one enviro tick
+	const float ENVIRO_PLAYER_HEATBUFFER_TEMP_AFFECT	= 0.50;		//! How much heat buffer change rates are affected by temperature
+	const float ENVIRO_PLAYER_HEATBUFFER_CAPACITY_MIN	= 0.3;		//! Minimal heatbuffer capacity of naked character
+
+	//! impact of item wetness to the heat isolation
+	const float ENVIRO_ISOLATION_WETFACTOR_DRY			= 1.0;
+	const float ENVIRO_ISOLATION_WETFACTOR_DAMP			= 0.9;
+	const float ENVIRO_ISOLATION_WETFACTOR_WET			= 0.5;
+	const float ENVIRO_ISOLATION_WETFACTOR_SOAKED		= 0.1;
+	const float ENVIRO_ISOLATION_WETFACTOR_DRENCHED 	= -0.15;
+	//! impact of item health (state) to the heat isolation
+	const float ENVIRO_ISOLATION_HEALTHFACTOR_PRISTINE  = 1.0;
+	const float ENVIRO_ISOLATION_HEALTHFACTOR_WORN		= 0.9;
+	const float ENVIRO_ISOLATION_HEALTHFACTOR_DAMAGED	= 0.8;
+	const float ENVIRO_ISOLATION_HEALTHFACTOR_B_DAMAGED = 0.5;
+	const float ENVIRO_ISOLATION_HEALTHFACTOR_RUINED  	= 0.0;
+	
+	const float ENVIRO_TEMP_SOURCES_LOOKUP_RADIUS		= 20.0;
+	
+	const float ENVIRO_NAKED_BODY_PENALTY_RAIN_MIN_VALUE 		= 0.2; //! how intensive a rain should be to enable rain penalty on naked body
+	const float ENVIRO_NAKED_BODY_PENALTY_SNOWFALL_MIN_VALUE 	= 0.4; //! how intensive a snowfall should be to enable snowfall penalty on naked body
+	
+	const float LIQUID_RAIN_AMOUNT_COEF_BASE = 10.0;
+	const float COLD_AREA_TEMPERATURE_THRESHOLD = 5;				//! (deg Celsius) temperature limit up to which player is allowed to dig garden plots
+	const float COLD_AREA_DIG_WORMS_MODIF = 1.5;					//! time modifier, how much longer it takes to dig up worms while in a cold area
+	
+	const float ENVIRO_WIND_EFFECT_SLOPE = -35.0;					//! Affects the slope of calculation
+	const float ENVIRO_WIND_CHILL_LIMIT = 30.0;						//! Above this value, the wind effect increases the modified temperature
+	
+	const float ENVIRO_SNOW_WET_COEF = 0.1;
+	
+	// --
+	//! various damage per second constants
+	const float FIRE_ATTACHMENT_DAMAGE_PER_SECOND 		= 0.07;		//! damage per second dealt to attachment by fire
+	
+	const float ITEM_TEMPERATURE_NEUTRAL_ZONE_LOWER_LIMIT	= 15.0;
+	const float ITEM_TEMPERATURE_NEUTRAL_ZONE_UPPER_LIMIT	= 35.0;
+	
+	const float ITEM_TEMPERATURE_QUANTITY_WEIGHT_MULTIPLIER = 0.04;
+	
+	static const float ITEM_TEMPERATURE_NEUTRAL_ZONE_MIDDLE = (GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_UPPER_LIMIT + GameConstants.ITEM_TEMPERATURE_NEUTRAL_ZONE_LOWER_LIMIT) * 0.5;
+	
+	/** @}*/
+	
+	/**
+	 * \defgroup CarFluidsConstants Cars Fluids 
+	 * \desc Constants for car fluids
+	 * @{
+	 */
+	const int CARS_FLUIDS_TICK 		= 1;
+	const int CARS_LEAK_TICK_MIN 	= 0.02;
+	const int CARS_LEAK_TICK_MAX 	= 0.05;
+	const int CARS_LEAK_THRESHOLD	= 0.5;
+	/** @}*/
+	
+	/**
+	 * \defgroup CarContactConstants Cars Contact 
+	 * \desc Constants for car contact event
+	 * @{
+	 */
+	const float CARS_CONTACT_DMG_THRESHOLD = 750.0;
+	const float CARS_CONTACT_DMG_MIN = 150.0;
+	const float CARS_CONTACT_DMG_KILLCREW = 1200.0;
+	/** @}*/
+	
+	/**
+	 * \defgroup ItemHealth Item Health States (ItemBase.GetHealthLevel)
+	 * \desc Constants for Item Health States
+	 * @{
+	 */
+	const int STATE_RUINED 		 	= 4;
+	const int STATE_BADLY_DAMAGED 	= 3;
+	const int STATE_DAMAGED 	  	= 2;
+	const int STATE_WORN 		  	= 1;
+	const int STATE_PRISTINE 	  	= 0;
+	/** @}*/
+	
+	/**
+	 * \defgroup ItemDamage Item Damage Relative Values (ItemBase.GetHealth01)
+	 * \desc Constants for relative Item Health handling
+	 * @{
+	 */
+	const float DAMAGE_PRISTINE_VALUE 		= 1.0;
+	const float DAMAGE_WORN_VALUE 			= 0.7;
+	const float DAMAGE_DAMAGED_VALUE 		= 0.5;
+	const float DAMAGE_BADLY_DAMAGED_VALUE 	= 0.3;
+	const float DAMAGE_RUINED_VALUE 		= 0.0;
+	/** @}*/
+	
+	/**
+	 * \defgroup ItemWetness Item Wetness States (ItemBase.GetWet)
+	 * \desc Constants for Item Wetness States
+	 * @{
+	 */
+	const float STATE_DRENCHED		= 0.8;
+	const float STATE_SOAKING_WET	= 0.5;
+	const float STATE_WET			= 0.25;
+	const float STATE_DAMP			= 0.05;
+	const float STATE_DRY			= 0;
+	/** @}*/
+	
+	/**
+	 * \defgroup ItemTemperature Item Temperature Levels (ItemBase.GetTemperature) (ObjectTemperatureState)
+	 * \desc Constants for Item Temperature Levels
+	 * @{
+	 */
+	const int STATE_HOT_LVL_FOUR 	= 600;
+	const int STATE_HOT_LVL_THREE  	= 250;
+	const int STATE_HOT_LVL_TWO 	= 70;
+	const int STATE_HOT_LVL_ONE  	= 35;
+	const int STATE_NEUTRAL_TEMP	= 15;
+	const int STATE_COLD_LVL_ONE  	= 3;
+	const int STATE_COLD_LVL_TWO  	= -10;
+	const int STATE_COLD_LVL_THREE  = -50;
+	const int STATE_COLD_LVL_FOUR	= -100;
+	/** @}*/
+	
+	/**
+	 * \defgroup ItemWetness Item Wetness Weight Modifiers
+	 * \desc Constants for Item Wetness States
+	 * @{
+	 */
+	const float WEIGHT_DRENCHED		= 2.0;
+	const float WEIGHT_SOAKING_WET	= 1.66;
+	const float WEIGHT_WET			= 1.33;
+	const float WEIGHT_DAMP			= 1.0;
+	const float WEIGHT_DRY			= 1.0;
+	/** @}*/
+	
+	const int OPTICS_STATE_DAY	 		= 0; //default state for most optics
+	const int OPTICS_STATE_NIGHTVISION 	= 1;
+	//const int OPTICS_STATE_OTHER	 	= 2;
+	
+	const float WETNESS_RATE_WETTING_INSIDE = 0.0020;
+	const float WETNESS_RATE_WETTING_LIQUID = 0.015;
+	const float WETNESS_RATE_DRYING_INSIDE  = -0.0016;
+	const float WETNESS_RATE_DRYING_GROUND  = -0.0008;
+	
+	/**
+	 * \defgroup EntityTemperature Entity Temperature constants
+	 * \desc Constants for generic Entity temperature simulation
+	 * @{
+	 */
+	
+	static const float TEMPERATURE_RATE_AVERAGE_ABS = 0.17; // °C/s
+	static const float TEMPERATURE_RATE_MAX_ABS = TEMPERATURE_RATE_AVERAGE_ABS * 6; // °C/s
+	//static const float TEMPERATURE_INTERPOLATION_EXPONENT_MAX = 3.0;
+	static const float TEMPERATURE_INTERPOLATION_THRESHOLD_MIN_ABS = 1.0; //difference in current - target temperatures
+	static const float TEMPERATURE_INTERPOLATION_THRESHOLD_MAX_ABS = 300.0; //difference in current - target temperatures
+	
+	static const float TEMPERATURE_FREEZETHAW_LEGACY_COEF = 0.2; //artificially lowers the freeze/thaw progression on reverse-calculated time values
+	
+	static const float TEMPERATURE_TIME_OVERHEAT_MIN = 180; //minimal time in seconds to overheat any overheatable entity
+	static const float TEMPERATURE_TIME_FREEZE_MIN = 120; //minimal time in seconds to freeze entity
+	static const float TEMPERATURE_TIME_THAW_MIN = 120; //minimal time in seconds to thaw entity
+	
+	static const float TEMPERATURE_FREEZE_TIME_COEF_DRIED = 0.25;
+	static const float TEMPERATURE_FREEZE_TIME_COEF_BURNED = 0.25;
+	static const float TEMPERATURE_THAW_TIME_COEF_BURNED = 0.25;
+	static const float TEMPERATURE_THAW_TIME_COEF_DRIED = 0.25;
+	
+	static const float TEMPERATURE_SENSITIVITY_THRESHOLD = 0.1; //changes lower than this will usually not be processed (absolute)
+	
+	const float TEMP_COEF_WORLD = 1; //entities on the ground
+	const float TEMP_COEF_INVENTORY = 1;
+	const float TEMP_COEF_FIREPLACE_COOLING = 2.0;
+	const float TEMP_COEF_FIREPLACE_HEATING = 2.0;
+	const float TEMP_COEF_GAS_STOVE = 1.0;
+	const float TEMP_COEF_UTS = 6.0; //universal temperature sources
+	const float TEMP_COEF_COOKING_CATCHUP = 3.0; //heating of child items that are below minimal cooking temperature (catching up)
+	const float TEMP_COEF_COOKING_DEFAULT = 3.0;
+	const float TEMP_COEF_COOLING_GLOBAL = 1.0; //one universal coef for item cooling
+	
+	const float HEATISO_THRESHOLD_BAD = 0.2;
+	const float HEATISO_THRESHOLD_LOW = 0.4;
+	const float HEATISO_THRESHOLD_MEDIUM = 0.6;
+	const float HEATISO_THRESHOLD_HIGH = 0.8;
+	/** @}*/
+	
+	/**
+	 * \defgroup Barrel Barrel related functions constants
+	 * \desc Barrel related functions constants
+	 * @{
+	 */
+	const int BAREL_LIME_PER_PELT = 100; //grams per pelt 
+	const int BAREL_BLEACH_PER_CLOTH = 50; //ml per item
+	const float BAREL_LIME_PER_PLANT = 50; //grams per gram
+	/** @}*/
+	
+	/**
+	 * \defgroup FOVSettings FOV settings
+	 * \desc Constats for setting of DayZPlayerCamera FOV
+	 */
+	
+	//! FOV (vertical angle/2) in radians. Take care to modify also in "basicDefines.hpp"
+	const float DZPLAYER_CAMERA_FOV_EYEZOOM			= 0.3926;	// 45deg
+	const float DZPLAYER_CAMERA_FOV_EYEZOOM_SHALLOW	= 0.610865;	// 70deg
+	const float DZPLAYER_CAMERA_FOV_IRONSIGHTS		= 0.5236;	// 60deg
+	
+	const string DEFAULT_CHARACTER_NAME = "#str_cfgvehicles_survivor0"; //experiment, used to be "Survivor"
+	
+	const int DEFAULT_CHARACTER_MENU_ID = -1;
+	
+	const float CLEAN_UNRESTRAIN_DAMAGE = 10;
+	
+	//! Camera shake
+	const int CAMERA_SHAKE_GRENADE_DISTANCE = 40;
+	const int CAMERA_SHAKE_ARTILLERY_DISTANCE = 200;
+	const int CAMERA_SHAKE_ARTILLERY_DISTANCE2 = 40000; // Square distance used for distance check
+	
+	//! Wood mining GameConstants, scaled by output. Should not be lower than ~1.5s!
+	const float MINING_WOOD_FAST = 2.0;
+	const float MINING_WOOD_MEDIUM = 2.0;
+	const float MINING_WOOD_SLOW = 3.0;
+	
+	//! Non-lethal projectile damage QuantityConversions
+	const float PROJECTILE_CONVERSION_ANIMALS 	= 0.1;
+	const float PROJECTILE_CONVERSION_INFECTED 	= 0.44;
+	const float PROJECTILE_CONVERSION_PLAYERS 	= 0.1;
+	
+	const float NL_DAMAGE_FIREARM_CONVERSION_ANIMALS 	= PROJECTILE_CONVERSION_ANIMALS;
+	const float NL_DAMAGE_FIREARM_CONVERSION_INFECTED 	= PROJECTILE_CONVERSION_INFECTED;
+	const float NL_DAMAGE_FIREARM_CONVERSION_PLAYERS  	= PROJECTILE_CONVERSION_PLAYERS;
+	
+	const float NL_DAMAGE_CLOSECOMBAT_CONVERSION_ANIMALS 	= 0.16;
+	const float NL_DAMAGE_CLOSECOMBAT_CONVERSION_INFECTED 	= 0.16;
+	const float NL_DAMAGE_CLOSECOMBAT_CONVERSION_PLAYERS  	= 0;
+	
+	const float ROOF_CHECK_RAYCAST_DIST = 20.0;
+	
+	//! misc
+	const float ITEM_TEMPERATURE_TO_EXPLODE_MIN = 100;
+	const float LOADING_SCREEN_HINT_INTERVAL = 14;//the time that elapses before a hint is switched during loading in screens that support hint switching
+	const float LOADING_SCREEN_HINT_INTERVAL_MIN = 8;//the minimum time that needs to remain on the count-down counter for a hint to still be changed based on the 'LOADING_SCREEN_HINT_INTERVAL'(prevents last moment hint update where the player has no time to read it)
+	
+	
+	/**
+	 * \defgroup LifetimeRefresherConstants Lifetime Refresher functionality constants
+	 * \desc Constats for lifetime refresher (radius, default lifetime, frequency...)
+	 */
+	const int REFRESHER_MAX_DURATION_DEFAULT		= 3600 * 24 * 40; 	//max duration of refresher in seconds - 40 days (+ 5 days final refresh )
+	const int REFRESHER_FREQUENCY_DEFAULT 			= 3600 * 24 * 5;	//frequency of lifetime refreshes/refresher time decreases - 5 days 
+	const float REFRESHER_RADIUS 					= 60; 				//meters
+	// lifetime of refresher itself is in db (3600 * 24 * 7 = 604800 )
+	
+	const float SALMONELLA_RETENTION_PREDATOR = 0.6; //60% chance cooked predator meat will retain salmonella
+	
+	/**
+	 * \defgroup FoodDecayConstants Food decay constants
+	 * \desc Constants for decay of various types of food.
+	 */
+	const float DECAY_FOOD_RAW_MEAT = 21600;
+	const float DECAY_FOOD_RAW_CORPSE = 32400;
+	const float DECAY_FOOD_RAW_FRVG = 43200;
+	const float DECAY_FOOD_BOILED_MEAT = 259200;
+	const float DECAY_FOOD_BOILED_FRVG = 172800;
+	const float DECAY_FOOD_BAKED_MEAT = 345600;
+	const float DECAY_FOOD_BAKED_FRVG = 259200;
+	const float DECAY_FOOD_DRIED_MEAT = 691200;
+	const float DECAY_FOOD_CAN_OPEN = 172800;
+	const int DECAY_FOOD_FRVG_DRIED_CHANCE = 43;
+	const int DECAY_TIMER_RANDOM_PERCENTAGE = 25;
+	const float DECAY_RATE_ON_PLAYER = 2.5;
+	
+	const int RESPAWN_MODE_CUSTOM = 0;
+	const int RESPAWN_MODE_RANDOM = 1;
+
+	/**
+	 * \defgroup InventoryConstants Inventory constants
+	 * \desc Constants for inventory
+	 */
+	const int INVENTORY_ENTITY_DROP_OVERLAP_DEPTH = 2; // How deep should it go looking for a free spot to drop an entity
+	/**
+	\brief Inventory visibility depth, also governs default direct access for most cases. Actual inventory depth CAN be higher than this, but direct access from player should not be possible in the context of player inventory.
+	\note ContainerWithCargoAndAttachments::AttachmentAddedEx creates 'Attachments' and 'CargoContainer' objects at depth 3 (nature of the architecture)
+	*/
+	const int INVENTORY_MAX_REACHABLE_DEPTH_ATT = 2;
+	
+	//----------------------------------------------------------
+	//							AI
+	//----------------------------------------------------------
+	
+	const float AI_ATTACKSPEED = 1.5;
+	const float AI_MAX_BLOCKABLE_ANGLE = 60; // The angle under which an infected must be relative to player to be blockable
+	const float AI_CONTAMINATION_DMG_PER_SEC = 3; // The amount of damage AI agents take per contaminated area damage event
+	
+	/*
+		Noise multiplier works with a 0-1 value which is then multiplied by noise levels. Noise reduction is a value in 0-1 range depending on phenomenon intensity.
+		noise = (NoiseMultiplier - NoiseReduction) * NOISE_LEVEL_MAX
+	
+		Reduction is substracted from multiplier before the noise conversion happens, meaning that if:
+		RAIN_NOISE_REDUCTION_WEIGHT == 1 && rain instensity == 1, any noise would be reduced to 0
+		RAIN_NOISE_REDUCTION_WEIGHT == 0.5, max possible reduction of noise would be by half
+	
+		In case of multiple phenomenons happening at the same time, the noise reduction does not stack and the stronger one is picked for calculation
+	*/
+	static float RAIN_NOISE_REDUCTION_WEIGHT = 0.5;
+	static float SNOWFALL_NOISE_REDUCTION_WEIGHT = 0.25;
+	
+	//----------------------------------------------------------
+	//						   MELEE
+	//----------------------------------------------------------
+	
+	const float PVP_MAX_BLOCKABLE_ANGLE = 60; // The angle under which a Player must be relative to player to be blockable
+	
+	//!
+	//! DEPRECATED
+	//!
+	const float ENVIRO_HEATCOMFORT_HEADPARTS_WEIGHT		= 0.3;		//! how much this head parts (clothing) affects final heatcomfort
+	const float ENVIRO_HEATCOMFORT_BODYPARTS_WEIGHT		= 0.8;		//! how much this body parts (clothing) affects final heatcomfort
+	const float ENVIRO_HEATCOMFORT_FEETPARTS_WEIGHT		= 0.4;		//! how much this feet parts (clothing) affects final heatcomfort
+	
+	const float ENVIRO_HEATISOLATION_BACK_WEIGHT		= 0.3;		//! weight of back for the sum of heat isolation
+	const float ENVIRO_HEATISOLATION_VEST_WEIGHT		= 0.5;		//! weight of vest for the sum of heat isolation
+
+	const float ENVIRO_ITEM_HEAT_TRANSFER_COEF 			= 0.01;		//! converts temperature of items to entities heatcomfort gain
+	const float ENVIRO_TEMPERATURE_HEIGHT_REDUCTION 	= 0.02;		//! amount of ?C reduced for each 100 meteres of height above water level
+	const float ENVIRO_CLOUDS_TEMP_EFFECT 				= 0.35;		//! how many % of environment temperature can be lowered by clouds
+	const float ENVIRO_TEMPERATURE_INSIDE_COEF 			= 0.085;	//! increases temp in interiors	
+	const float ENVIRO_WATER_TEMPERATURE_COEF 			= 1.5;		//! how many time is water colder than air
+
+	const float ENVIRO_PLAYER_HEATBUFFER_TICK			= 0.011;	//! Heat buffer static timer tick (set for 2s enviro tick, 180s to 1.0)
+
+	const float TEMPERATURE_RATE_COOLING_INSIDE = -0.17;
+	const float TEMPERATURE_RATE_COOLING_GROUND = -0.34;
+	const float TEMPERATURE_RATE_COOLING_PLAYER = -0.35;
+}
+
+//! DEPRECATED
+const string	CFG_FILE_ADDITIONAL_INFO= "$profile:serverInfo.cfg";

+ 8 - 0
Scripts/3_game/controlschememanager.c

@@ -0,0 +1,8 @@
+class ControlSchemeManager
+{
+	//! leaving it here in case that someone using it inside a mod
+	static void SetControlScheme( EControlSchemeState state )
+	{
+		return;
+	}
+}

+ 157 - 0
Scripts/3_game/damagesystem.c

@@ -0,0 +1,157 @@
+class TotalDamageResult: Managed
+{
+	proto native float GetDamage(string zoneName, string healthType);
+	proto native float GetHighestDamage(string healthType);
+};
+
+//-----------------------------------------------------------------------------
+
+//! exposed from C++ (do not change)
+enum DamageType
+{
+	CLOSE_COMBAT,	// 0
+	FIRE_ARM,		// 1
+	EXPLOSION,
+	STUN,
+	CUSTOM
+}
+
+//-----------------------------------------------------------------------------
+class DamageSystem
+{
+	static proto native void CloseCombatDamage(EntityAI source, Object targetObject, int targetComponentIndex, string ammoTypeName, vector worldPos, int directDamageFlags = ProcessDirectDamageFlags.ALL_TRANSFER);
+	static proto native void CloseCombatDamageName(EntityAI source, Object targetObject, string targetComponentName, string ammoTypeName, vector worldPos, int directDamageFlags = ProcessDirectDamageFlags.ALL_TRANSFER);
+
+	static proto native void ExplosionDamage(EntityAI source, Object directHitObject, string ammoTypeName, vector worldPos, int damageType);
+	
+	static bool GetDamageZoneMap(EntityAI entity, out DamageZoneMap zoneMap)
+	{
+		string path_base;
+		string path;
+		
+		if (entity.IsWeapon())
+		{
+			path_base = CFG_WEAPONSPATH;
+		}
+		else if (entity.IsMagazine())
+		{
+			path_base = CFG_MAGAZINESPATH;
+		}
+		else
+		{
+			path_base = CFG_VEHICLESPATH;
+		}
+		
+		path_base = string.Format("%1 %2 DamageSystem DamageZones", path_base, entity.GetType());
+		
+		if (!GetGame().ConfigIsExisting(path_base))
+		{
+			return false;
+		}
+		else
+		{
+			string zone;
+			array<string> zone_names = new array<string>;
+			array<string> component_names;
+			
+			entity.GetDamageZones(zone_names);
+			for (int i = 0; i < zone_names.Count(); i++)
+			{
+				component_names = new array<string>;
+				zone = zone_names.Get(i);
+				
+				path =  string.Format("%1 %2 componentNames ", path_base, zone);
+				if (GetGame().ConfigIsExisting(path))
+				{
+					GetGame().ConfigGetTextArray(path,component_names);
+				}
+				zoneMap.Insert(zone,component_names);
+			}
+			
+			return true;
+		}
+	}
+	
+	//! Returns damage zone to which the named component belongs
+	static bool  GetDamageZoneFromComponentName(notnull EntityAI entity, string component, out string damageZone)
+	{
+		DamageZoneMap zoneMap = entity.GetEntityDamageZoneMap();
+		array<array<string>> components;
+		components = zoneMap.GetValueArray();
+		for (int i = 0; i < components.Count(); i++)
+		{
+			array<string> inner = components.Get(i);
+			for (int j = 0; j < inner.Count(); j++)
+			{
+				string innerComponentName = inner.Get(j);
+				innerComponentName.ToLower();
+				
+				//We don't have a component name, no need to proceed
+				if ( innerComponentName == "" )
+					break;
+				
+				if (innerComponentName == component)
+				{
+					damageZone = zoneMap.GetKey(i);
+					return true;
+				}
+			}
+		}
+		damageZone = "";
+		return false;
+	}
+	
+	static bool GetComponentNamesFromDamageZone(notnull EntityAI entity, string damageZone, out array<string> componentNames)
+	{
+		string path;
+		
+		if (entity.IsWeapon())
+		{
+			path = CFG_WEAPONSPATH;
+		}
+		else if (entity.IsMagazine())
+		{
+			path = CFG_MAGAZINESPATH;
+		}
+		else
+		{
+			path = CFG_VEHICLESPATH;
+		}
+		
+		path = string.Format("%1 %2 DamageSystem DamageZones %3 componentNames", path, entity.GetType(), damageZone);
+		if (GetGame().ConfigIsExisting(path))
+		{
+			GetGame().ConfigGetTextArray(path,componentNames);
+			return true;
+		}
+		
+		return false;
+	}
+	
+	static string GetDamageDisplayName(EntityAI entity, string zone)
+	{
+		string component_name;
+		entity.GetEntityDamageDisplayNameMap().Find(zone.Hash(), component_name);
+		component_name = Widget.TranslateString(component_name);
+		return component_name;
+	}
+	
+	static void ResetAllZones(EntityAI entity)
+	{
+		DamageZoneMap zonesMap = new DamageZoneMap();
+		DamageSystem.GetDamageZoneMap(entity, zonesMap);
+		array<string> zones = zonesMap.GetKeyArray();
+		entity.SetHealth("", "Health", entity.GetMaxHealth("","Health"));
+		entity.SetHealth("", "Shock", entity.GetMaxHealth("","Shock"));
+		entity.SetHealth("", "Blood", entity.GetMaxHealth("","Blood"));
+		
+		foreach (string zone : zones)
+		{
+			entity.SetHealth(zone, "Health", entity.GetMaxHealth(zone,"Health"));
+			entity.SetHealth(zone, "Shock", entity.GetMaxHealth(zone,"Shock"));
+			entity.SetHealth(zone, "Blood", entity.GetMaxHealth(zone,"Blood"));
+		}	
+	}
+}
+
+typedef map<string,ref array<string>> DamageZoneMap; //<zone_name,<components>>

+ 238 - 0
Scripts/3_game/dayzanimeventmaps.c

@@ -0,0 +1,238 @@
+//individual sound table consisting of map of parameter hashes as keys and soundbuilder array as values
+class SoundLookupTable
+{
+	void SoundLookupTable()
+	{
+		m_soundBuilders = new map<int, ref array<SoundObjectBuilder>>();
+	}
+	
+	void InitTable(string tableCategoryName, string parameterName)
+	{
+		m_tableCategoryName = tableCategoryName;
+		m_parameterName = parameterName;
+	}
+	
+	void LoadTable(string soundLookupTableName)
+	{
+		string path = "CfgSoundTables " + m_tableCategoryName + " " + soundLookupTableName;
+		
+		//load all classes names
+		int soundCount = GetGame().ConfigGetChildrenCount(path);
+
+		for(int i = 0; i < soundCount; i++)
+		{
+			string soundClassName;
+			GetGame().ConfigGetChildName(path, i, soundClassName);
+			string soundClassPath = path + " " + soundClassName + " ";
+
+			string parameter;
+			GetGame().ConfigGetText(soundClassPath + m_parameterName, parameter);
+
+			array<string> soundSetNames = new array<string>;
+			GetGame().ConfigGetTextArray(soundClassPath + "soundSets", soundSetNames);
+
+			//TODO create SoundObject for every entry, save in Game?
+			array<SoundObjectBuilder> soundObjectBuilders = new array<SoundObjectBuilder>;
+			for(int j = 0; j < soundSetNames.Count(); j++)
+			{
+				AnimSoundObjectBuilderBank bank = AnimSoundObjectBuilderBank.GetInstance();
+				SoundObjectBuilder soundObjectBuilder = bank.GetBuilder(soundSetNames.Get(j));
+
+				if(soundObjectBuilder != NULL)
+					soundObjectBuilders.Insert(soundObjectBuilder);
+			}
+
+			if(soundObjectBuilders.Count() > 0)
+			{
+				//Print("SoundLookupTable::LoadTable: path: " + path + " param:" + parameter + " param#:" + parameter.Hash() + " objBuildersCount: " + soundObjectBuilders.Count());
+				m_soundBuilders.Insert(parameter.Hash(), soundObjectBuilders);
+			}
+		}
+	}
+	
+	SoundObjectBuilder GetSoundBuilder(int parameterHash)
+	{
+		array<SoundObjectBuilder> soundObjects = m_soundBuilders.Get(parameterHash);
+
+		if(soundObjects == NULL || soundObjects.Count() == 0)
+		{
+			return NULL;
+		}
+		else if (soundObjects.Count() == 1)
+		{
+			return soundObjects.Get(0);
+		}
+		else
+		{
+			int index = Math.RandomInt(0, soundObjects.Count());
+			return soundObjects.Get(index);
+		}
+	}
+	
+	
+	private string m_tableCategoryName;
+	private string m_parameterName;
+	private ref map<int, ref array<SoundObjectBuilder>> m_soundBuilders;
+}
+
+
+class StepSoundLookupTable extends SoundLookupTable
+{
+	void StepSoundLookupTable()
+	{
+		InitTable("CfgStepSoundTables", "surface");
+	}
+}
+
+class AttachmentSoundLookupTable extends SoundLookupTable
+{
+	void AttachmentSoundLookupTable()
+	{
+		InitTable("CfgAttachmentSoundTables", "category");
+	}
+}
+
+class PlayerVoiceLookupTable extends SoundLookupTable
+{
+	ref NoiseParams m_NoiseParams;
+	
+	void PlayerVoiceLookupTable()
+	{
+		InitTable("CfgVoiceSoundTables", "category");
+	}
+	
+	void SetNoiseParam(NoiseParams param)
+	{
+		m_NoiseParams = param;
+	}
+	
+	NoiseParams GetNoiseParam()
+	{
+		return m_NoiseParams;
+	}
+}
+
+
+class ImpactSoundLookupTable extends SoundLookupTable
+{
+	void ImpactSoundLookupTable()
+	{
+		InitTable("CfgImpactSoundTables", "surface");
+	}
+}
+
+class ActionSoundLookupTable extends SoundLookupTable
+{
+	void ActionSoundLookupTable()
+	{
+		InitTable("CfgActionsSoundTables", "category");
+	}
+}
+
+
+class AnimSoundObjectBuilderBank
+{
+	void AnimSoundObjectBuilderBank()
+	{
+		m_pBuilders = new map<int, ref SoundObjectBuilder>();
+	}
+
+
+	static AnimSoundObjectBuilderBank GetInstance()
+	{
+		if(m_instance == NULL)
+			m_instance = new AnimSoundObjectBuilderBank();
+
+		return m_instance;
+	}
+
+
+	SoundObjectBuilder GetBuilder(string soundSetName)
+	{
+		int soundSetNameHash = soundSetName.Hash();
+
+		SoundObjectBuilder builder = m_pBuilders.Get(soundSetNameHash);
+		if(builder == NULL)
+		{
+			SoundParams params = new SoundParams(soundSetName);
+			if(params.IsValid())
+			{
+				builder = new SoundObjectBuilder(params);
+				m_pBuilders.Insert(soundSetNameHash, builder);
+			}
+			else
+			{
+				Print("AnimSoundObjectBuilderBank: Invalid sound set \"" + soundSetName + "\".");
+				return NULL;
+			}
+		}
+		return builder;
+	}
+
+	private static ref AnimSoundObjectBuilderBank m_instance;
+	private autoptr map<int, ref SoundObjectBuilder> m_pBuilders;
+}
+
+
+class AnimSoundLookupTableBank
+{
+	void AnimSoundLookupTableBank()
+	{
+		m_pTables = new map<int, ref SoundLookupTable>();
+	}
+
+
+	static AnimSoundLookupTableBank GetInstance()
+	{
+		if(m_instance == NULL)
+			m_instance = new AnimSoundLookupTableBank();
+
+		return m_instance;
+	}
+
+
+	SoundLookupTable GetStepTable(string tableName)
+	{
+		int tableNameHash = tableName.Hash();
+
+		SoundLookupTable table = m_pTables.Get(tableNameHash);
+		if(table == NULL)
+		{
+			table = new StepSoundLookupTable();
+			table.LoadTable(tableName);
+			m_pTables.Insert(tableNameHash, table);
+		}
+		return table;
+	}
+	
+	SoundLookupTable GetImpactTable(string tableName)
+	{
+		int tableNameHash = tableName.Hash();
+
+		SoundLookupTable table = m_pTables.Get(tableNameHash);
+		if(table == NULL)
+		{
+			table = new ImpactSoundLookupTable();
+			table.LoadTable(tableName);
+			m_pTables.Insert(tableNameHash, table);
+		}
+		return table;
+	}
+	
+	SoundLookupTable GetActionTable(string tableName)
+	{
+		int tableNameHash = tableName.Hash();
+
+		SoundLookupTable table = m_pTables.Get(tableNameHash);
+		if(table == NULL)
+		{
+			table = new ActionSoundLookupTable();
+			table.LoadTable(tableName);
+			m_pTables.Insert(tableNameHash, table);
+		}
+		return table;
+	}
+
+	private static ref AnimSoundLookupTableBank m_instance;
+	private autoptr map<int, ref SoundLookupTable> m_pTables;
+}

+ 366 - 0
Scripts/3_game/dayzanimevents.c

@@ -0,0 +1,366 @@
+/*enum AnimSurfaces
+{
+	cp_concrete1,
+	cp_concrete2,
+
+	cp_dirt,
+
+	cp_broadleaf_dense1,
+	cp_broadleaf_dense2,
+	cp_broadleaf_sparse1,
+	cp_broadleaf_sparse2,
+
+	cp_conifer_common1,
+	cp_conifer_common2,
+	cp_conifer_moss1,
+	cp_conifer_moss2,
+
+	cp_grass,
+	cp_grass_tall,
+
+	cp_gravel,
+	cp_rock,
+
+	asphalt_ext,
+	asphalt_int,
+
+	asphalt_destroyed_ext,
+	asphalt_destroyed_int,
+
+	concrete_ext,
+	concrete_int,
+
+	stone_ext,
+	stone_int,
+
+	gravel_large_ext,
+	gravel_large_int,
+
+	gravel_small_ext,
+	gravel_small_int,
+
+	sand_ext,
+	sand_int,
+
+	dirt_ext,
+	dirt_int,
+
+	rubble_large_ext,
+	rubble_large_int,
+
+	rubble_small_ext,
+	rubble_small_int,
+
+	trash_ext,
+	trash_int,
+
+	grass_dry_ext,
+	grass_dry_int,
+
+	metal_thick_ext,
+	metal_thick_int,
+
+	metal_thin_ext,
+	metal_thin_int,
+
+	metal_thin_mesh_ext,
+	metal_thin_mesh_int,
+
+	asphalt_felt_ext,
+	asphalt_felt_int,
+
+	ceramic_tiles_ext,
+	ceramic_tiles_int,
+
+	lino_ext,
+	lino_int,
+
+	textile_carpet_ext,
+	textile_carpet_int,
+
+	wood_parquet_ext,
+	wood_parquet_int,
+
+	wood_planks_ext,
+	wood_planks_int,
+
+	concrete_stairs_ext,
+	concrete_stairs_int,
+
+	metal_stairs_ext,
+	metal_stairs_int,
+
+	wood_planks_stairs_ext,
+	wood_planks_stairs_int
+}*/
+
+enum AnimBootsType
+{
+	None,
+	Sneakers,
+	Boots
+}
+
+enum AnimUpperBodyType
+{
+	None 				= 4107064,//string hash, because we can't make compile time constant
+	NylonJacket			= 1228024514,
+	TShirt				= 1690896446,
+	WoolShirt			= 1060939383,
+	HeavyJacket			= 1544363355,
+	LeatherJacket		= 2008520095,
+	Coat				= 3549415,
+	ChemlonDress		= -1491825621,
+	Ghillie				= 602194810,
+	Chainmail			= -563873622,
+}
+
+enum AnimBackType
+{
+	None 				= -1,
+	Small 				= 161213437,
+	Military 			= 1935514591,
+	Outdoor				= 574855932,
+	Ghillie				= 602194810
+}
+
+enum AnimRangedWeaponType
+{
+	None 		= 5727960,
+	Rifle 		= 219116654,
+	Shotgun 	= 1836650908
+}
+
+class AnimSoundEvent
+{
+	int m_iID;
+	ref SoundObjectBuilder 			m_SoundObjectBuilder;
+	ref SoundParams 				m_SoundParams;
+	autoptr NoiseParams 			m_NoiseParams;
+	bool 							m_IsValid = false;
+	SoundLookupTable 				m_Table;
+	
+	
+	void AnimSoundEvent(string soundPath)
+	{
+		m_iID = GetGame().ConfigGetInt(soundPath + "id");
+
+		#ifndef SERVER
+
+		string soundSetName;
+		if (GetGame().ConfigGetText(soundPath + "soundSet", soundSetName))
+		{
+			m_SoundParams = new SoundParams(soundSetName);
+			if (m_SoundParams.IsValid())
+			{
+				m_SoundObjectBuilder = new SoundObjectBuilder(m_SoundParams);
+				m_IsValid = true;
+			}
+		}
+		
+		string tableName;
+		if (GetGame().ConfigGetText(soundPath + "soundLookupTable", tableName))
+		{
+			m_Table = AnimSoundLookupTableBank.GetInstance().GetActionTable(tableName);
+			if (m_Table)
+			{
+				m_IsValid = true;
+				//Print("Found lookup table '"+tableName +"' for anim event-----------------------------------------> " + m_iID);
+			}
+		}
+		#endif
+
+		
+		
+		
+		if ( GetGame().IsServer() )
+		{
+			string noiseName;
+			if (GetGame().ConfigGetText(soundPath + "noise", noiseName))
+			{
+				m_NoiseParams = new NoiseParams();
+				m_NoiseParams.Load(noiseName);
+				m_IsValid = true;
+			}
+			else
+			{
+				//Print("AnimSoundEvent: \"" + soundPath + "\" doesn't have defined \"noise\"");
+			}
+		}
+	}
+	
+	bool IsValid()
+	{
+		return m_IsValid;
+	}
+	
+	SoundObjectBuilder GetSoundBuilder()
+	{
+		return m_SoundObjectBuilder;
+	}
+	
+	SoundObjectBuilder GetSoundBuilderEx(int paramHash = 0)
+	{
+		if (m_Table && paramHash)
+		{
+			return m_Table.GetSoundBuilder(paramHash);
+		}
+		return m_SoundObjectBuilder;
+	}
+
+	SoundObject GetSoundObject(vector position)
+	{
+		GetSoundBuilderEx().AddEnvSoundVariables(position);
+		return GetSoundBuilderEx().BuildSoundObject();
+	}
+}
+
+class AnimSoundVoiceEvent
+{
+	int m_iID;
+	ref SoundObjectBuilder m_SoundObjectBuilder;
+	ref SoundParams m_SoundParams;
+	autoptr NoiseParams m_NoiseParams;
+	bool m_IsValid = false;
+
+	void AnimSoundVoiceEvent(string soundPath)
+	{
+		m_iID = GetGame().ConfigGetInt(soundPath + "id");
+
+		if ( !GetGame().IsDedicatedServer() )
+		{
+			string soundSetName;
+			GetGame().ConfigGetText(soundPath + "soundSet", soundSetName);
+			m_SoundParams = new SoundParams(soundSetName);
+			if ( m_SoundParams.IsValid() )
+			{
+				m_SoundObjectBuilder = new SoundObjectBuilder(m_SoundParams);
+				m_IsValid = true;
+			}
+		}
+		
+		if ( GetGame().IsServer() )
+		{
+			string noiseName;
+			if (GetGame().ConfigGetText(soundPath + "noise", noiseName))
+			{
+				m_NoiseParams = new NoiseParams();
+				m_NoiseParams.Load(noiseName);
+				m_IsValid = true;
+			}
+			else
+			{
+				//Print("AnimSoundVoiceEvent: \"" + soundPath + "\" doesn't have defined \"noise\"");
+			}
+		}
+	}
+	
+	bool IsValid()
+	{
+		return m_IsValid;
+	}
+	
+	SoundObjectBuilder GetSoundBuilder()
+	{
+		return m_SoundObjectBuilder;
+	}
+
+	SoundObject GetSoundObject(vector position)
+	{
+		m_SoundObjectBuilder.AddEnvSoundVariables(position);
+		return m_SoundObjectBuilder.BuildSoundObject();
+	}
+}
+
+class AnimStepEvent
+{
+	int m_iID;
+	string m_sSoundLookupTableName;
+	StepSoundLookupTable m_soundLookupTable;
+	autoptr NoiseParams m_NoiseParams;
+
+	void AnimStepEvent(string stepPath)
+	{
+		m_iID = GetGame().ConfigGetInt(stepPath + "id");
+
+		if ( !GetGame().IsDedicatedServer() )
+		{
+			GetGame().ConfigGetText(stepPath + "soundLookupTable", m_sSoundLookupTableName);
+			m_soundLookupTable = StepSoundLookupTable.Cast( AnimSoundLookupTableBank.GetInstance().GetStepTable(m_sSoundLookupTableName) );
+		}
+		
+		if ( GetGame().IsServer() )
+		{
+			string noiseName;
+			if (GetGame().ConfigGetText(stepPath + "noise",noiseName))
+			{
+				m_NoiseParams = new NoiseParams();
+				m_NoiseParams.Load(noiseName);
+			}
+		}
+	}
+	
+	SoundObjectBuilder GetSoundBuilder(int surfaceHash)
+	{
+		return m_soundLookupTable.GetSoundBuilder(surfaceHash);
+	}
+}
+
+class AnimDamageEvent
+{
+	int m_iID;
+	autoptr AnimDamageParams m_DamageParams;
+
+	void AnimDamageEvent(string damagePath)
+	{
+		m_iID = GetGame().ConfigGetInt(damagePath + "id");
+		
+		string damageName;
+		GetGame().ConfigGetText(damagePath + "damage", damageName);
+		m_DamageParams = new AnimDamageParams(damageName);
+	}
+}
+
+class AnimDamageParams
+{
+	string m_sName;
+	string m_sBoneName;
+	string m_sAmmoName;	
+	float m_fRadius;
+	float m_fDuration;
+	bool m_bInvertTeams;
+
+	static const string DAMAGE_CFG_CLASS = "CfgDamages ";
+	void AnimDamageParams(string damageName)
+	{
+		m_sName = damageName;
+		string damagePath = DAMAGE_CFG_CLASS + damageName + " ";
+
+		GetGame().ConfigGetText(damagePath + "bone", m_sBoneName);
+		GetGame().ConfigGetText(damagePath + "ammo", m_sAmmoName);
+		m_fRadius = GetGame().ConfigGetFloat(damagePath + "radius");
+		m_fDuration = GetGame().ConfigGetFloat(damagePath + "duration");
+		
+		m_bInvertTeams = false;
+		string str_invert_teams_cfg;
+		GetGame().ConfigGetText(damagePath + "invertTeams", str_invert_teams_cfg);
+		str_invert_teams_cfg.ToLower();
+		if (str_invert_teams_cfg == "true")
+		{
+			m_bInvertTeams = true;
+		}
+	}
+}
+
+class AnimEffectParams
+{
+	string m_sName;
+
+	static const string EFFECT_CFG_CLASS = "CfgEffects ";
+	void AnimEffectParams(string effectName)
+	{
+		m_sName = effectName;
+		string effectPath = EFFECT_CFG_CLASS + effectName + " ";
+		//TODO load params
+	}
+}

+ 6 - 0
Scripts/3_game/dayzcreature.c

@@ -0,0 +1,6 @@
+enum DayZCreatureAnimScriptDebugVarType
+{
+	INT,
+	FLOAT,
+	BOOL,
+};

+ 4 - 0
Scripts/3_game/dayzcreatureai.c

@@ -0,0 +1,4 @@
+enum DayZCreatureAIConstants
+{
+	DEBUG_SHOWDEBUGPLUGIN
+};

+ 3825 - 0
Scripts/3_game/dayzgame.c

@@ -0,0 +1,3825 @@
+enum DisconnectSessionFlags
+{
+	NONE = 0,
+	JOIN_ERROR_ENABLED = 1,
+	JOIN_ERROR_CHECK = 2,
+	DISCONNECT_ERROR_ENABLED = 4,
+	SELECT_USER = 8,
+	CLOSE_MENUS = 16,
+	IGNORE_WHEN_IN_GAME = 32,
+	ALWAYS_FORCE = 64,
+}
+
+const int DISCONNECT_SESSION_FLAGS_FORCE = int.MAX & ~DisconnectSessionFlags.IGNORE_WHEN_IN_GAME;
+const int DISCONNECT_SESSION_FLAGS_JOIN = int.MAX & ~DisconnectSessionFlags.JOIN_ERROR_CHECK;
+const int DISCONNECT_SESSION_FLAGS_ALL = int.MAX;
+
+class ProjectileStoppedInfo : Managed
+{
+	proto native Object GetSource();
+	proto native vector GetPos();
+	proto native vector GetInVelocity();
+	proto native string GetAmmoType();
+	proto native float GetProjectileDamage();
+}
+
+class CollisionInfoBase: ProjectileStoppedInfo
+{
+	proto native vector GetSurfNormal();
+}
+
+class ObjectCollisionInfo: CollisionInfoBase
+{
+	proto native Object GetHitObj();
+	proto native vector GetHitObjPos();
+	proto native vector GetHitObjRot();
+	proto native int GetComponentIndex();
+}
+
+class TerrainCollisionInfo: CollisionInfoBase
+{
+	proto native bool GetIsWater();
+}
+
+class CrashSoundSets
+{
+	static ref map<int, string> m_Mappings = new map<int, string>;
+	
+	static void RegisterSoundSet(string sound_set)
+	{
+		m_Mappings.Set(sound_set.Hash(), sound_set);
+	}
+	
+	static string GetSoundSetByHash(int hash)
+	{
+		string sound_set;
+		if (m_Mappings)
+			m_Mappings.Find(hash,sound_set);
+		return sound_set;
+	}
+};
+
+
+class LoginScreenBase extends UIScriptedMenu
+{
+	protected ref UiHintPanelLoading m_HintPanel;
+	protected bool m_IsStatic;
+	protected float m_HintTimeAccu;
+	
+	override void Update(float timeslice)
+	{
+		if (m_HintPanel)
+		{
+			m_HintTimeAccu += timeslice;
+			if (CanChangeHintPage(m_HintTimeAccu))
+			{
+				m_HintPanel.ShowRandomPage();
+				m_HintTimeAccu = 0;
+			}
+		}
+		
+		if (GetUApi().GetInputByID(UAUIBack).LocalPress())
+		{
+			Leave();
+		}
+	}
+	
+	protected void Leave()
+	{
+		g_Game.SetGameState(DayZGameState.MAIN_MENU);
+		g_Game.SetLoadState(DayZLoadState.MAIN_MENU_START);
+		
+		g_Game.GetCallQueue(CALL_CATEGORY_SYSTEM).Call(GetGame().DisconnectSessionForce);
+		
+		Close();
+	}
+	
+	protected bool CanChangeHintPage(float timeAccu);
+	
+	bool IsStatic()
+	{
+		return m_IsStatic;
+	}
+	
+	override bool IsHandlingPlayerDeathEvent()
+	{
+		return false;
+	}
+}
+
+class LoginQueueBase extends LoginScreenBase
+{
+	protected TextWidget m_txtPosition;
+	protected TextWidget m_txtNote;
+	protected ButtonWidget m_btnLeave;
+	protected int m_iPosition = -1;
+	
+	void LoginQueueBase()
+	{		
+		g_Game.SetKeyboardHandle(this);	
+	}
+
+	void ~LoginQueueBase()
+	{
+		g_Game.SetKeyboardHandle(NULL);	
+	}
+	
+	override Widget Init()
+	{		
+		layoutRoot 		= GetGame().GetWorkspace().CreateWidgets("gui/layouts/dialog_queue_position.layout");
+		m_HintPanel	= new UiHintPanelLoading(layoutRoot.FindAnyWidget("hint_frame0"));
+		m_txtPosition	= TextWidget.Cast(layoutRoot.FindAnyWidget("txtPosition"));
+		m_txtNote 		= TextWidget.Cast(layoutRoot.FindAnyWidget("txtNote"));
+		m_btnLeave 		= ButtonWidget.Cast(layoutRoot.FindAnyWidget("btnLeave"));
+		m_txtNote.Show(true);
+		layoutRoot.FindAnyWidget("notification_root").Show(false);
+		
+		#ifdef PLATFORM_CONSOLE
+		layoutRoot.FindAnyWidget("toolbar_bg").Show(true);
+		RichTextWidget toolbar_b = RichTextWidget.Cast(layoutRoot.FindAnyWidget("BackIcon"));
+		toolbar_b.SetText(InputUtils.GetRichtextButtonIconFromInputAction("UAUIBack", "", EUAINPUT_DEVICE_CONTROLLER, InputUtils.ICON_SCALE_TOOLBAR));
+		#ifdef PLATFORM_XBOX
+		#ifdef BUILD_EXPERIMENTAL
+		layoutRoot.FindAnyWidget("notification_root").Show(true);
+		#endif
+		#endif
+		#endif
+
+		return layoutRoot;
+	}
+	
+	override bool OnClick(Widget w, int x, int y, int button)
+	{
+		super.OnClick(w, x, y, button);
+		if (w == m_btnLeave)
+		{
+			Leave();
+			return true;
+		}
+		return false;
+	}
+	
+	void Show()
+	{
+		if (layoutRoot)
+		{
+			layoutRoot.Show(true);
+		}
+	}
+	
+	void Hide()
+	{
+		if (layoutRoot)
+			layoutRoot.Show(false);
+		m_HintPanel = null;
+	}
+	
+	void SetPosition(int position)
+	{
+		if (position != m_iPosition)
+		{
+			m_iPosition = position;
+			m_txtPosition.SetText(position.ToString());
+		}
+	}
+	
+	override protected bool CanChangeHintPage(float timeAccu)
+	{
+		return timeAccu >= GameConstants.LOADING_SCREEN_HINT_INTERVAL;
+	}
+};
+
+
+//! LoginQueue position when using -connect since mission is not created yet 
+class LoginQueueStatic extends LoginQueueBase
+{
+	void LoginQueueStatic()
+	{
+		Init();
+		
+		m_IsStatic = true;
+	}
+};
+
+class LoginTimeBase extends LoginScreenBase
+{
+	protected TextWidget m_txtDescription;
+	protected TextWidget m_txtLabel;
+	protected ButtonWidget m_btnLeave;
+	
+	protected bool m_IsRespawn;
+	
+	private ref FullTimeData m_FullTime;
+	
+	void LoginTimeBase()
+	{
+		g_Game.SetKeyboardHandle(this);
+		m_IsRespawn = false;
+		
+		m_FullTime = new FullTimeData();
+	}
+
+	void ~LoginTimeBase()
+	{
+		if (g_Game)
+			g_Game.SetKeyboardHandle(null);
+		m_FullTime = null;
+	}
+	
+	override Widget Init()
+	{
+		layoutRoot 			= GetGame().GetWorkspace().CreateWidgets("gui/layouts/dialog_login_time.layout");
+		
+		m_txtDescription 	= TextWidget.Cast(layoutRoot.FindAnyWidget("txtDescription"));
+		m_txtLabel 			= TextWidget.Cast(layoutRoot.FindAnyWidget("txtLabel"));
+		m_btnLeave 			= ButtonWidget.Cast(layoutRoot.FindAnyWidget("btnLeave"));
+		m_txtDescription.Show(true);
+		layoutRoot.FindAnyWidget("notification_root").Show(false);
+		
+		#ifdef PLATFORM_CONSOLE
+		layoutRoot.FindAnyWidget("toolbar_bg").Show(true);
+		RichTextWidget toolbar_b = RichTextWidget.Cast(layoutRoot.FindAnyWidget("BackIcon"));
+		toolbar_b.SetText(InputUtils.GetRichtextButtonIconFromInputAction("UAUIBack", "", EUAINPUT_DEVICE_CONTROLLER, InputUtils.ICON_SCALE_TOOLBAR));
+		#ifdef PLATFORM_XBOX
+		#ifdef BUILD_EXPERIMENTAL
+		layoutRoot.FindAnyWidget("notification_root").Show(true);
+		#endif
+		#endif
+		#endif
+
+		return layoutRoot;
+	}
+		
+	override bool OnClick(Widget w, int x, int y, int button)
+	{
+		super.OnClick(w, x, y, button);
+		if (w == m_btnLeave)
+		{
+			Leave();
+			return true;
+		}
+		return false;
+	}
+		
+	void Show()
+	{
+		if (layoutRoot)
+		{
+			layoutRoot.Show(true);
+			m_HintPanel	= new UiHintPanelLoading(layoutRoot.FindAnyWidget("hint_frame0"));
+		}
+	}
+	
+	void Hide()
+	{
+		if (layoutRoot)
+			layoutRoot.Show(false);
+		m_HintPanel = null;
+	}
+	
+	void SetTime(int time)
+	{
+		string text = "";
+		TimeConversions.ConvertSecondsToFullTime(time, m_FullTime);
+		if (!m_IsRespawn)
+			text = "#menu_loading_in_";
+		else
+			text = "#dayz_game_spawning_in_";
+		
+		if (m_FullTime.m_Days > 0)
+			text += "dhms";
+		else if (m_FullTime.m_Hours > 0)
+			text += "hms";
+		else if (m_FullTime.m_Minutes > 0)
+			text += "ms";
+		else
+			text += "s";
+		
+		text = Widget.TranslateString(text);
+		text = string.Format(text, m_FullTime.m_Seconds, m_FullTime.m_Minutes, m_FullTime.m_Hours, m_FullTime.m_Days);
+		m_txtLabel.SetText(text);
+		
+		if (m_IsRespawn && time <= 1)
+			GetGame().SetLoginTimerFinished();
+	}
+		
+	void SetStatus(string status)
+	{
+		m_txtDescription.SetText(status);
+	}
+	
+	void SetRespawn(bool value)
+	{
+		m_IsRespawn = value;
+	}
+	
+	bool IsRespawn()
+	{
+		return m_IsRespawn;
+	}
+	
+	override protected bool CanChangeHintPage(float timeAccu)
+	{
+		return timeAccu >= GameConstants.LOADING_SCREEN_HINT_INTERVAL && m_FullTime.m_Seconds >= GameConstants.LOADING_SCREEN_HINT_INTERVAL_MIN;
+	}
+};
+
+//! LoginTime when using -connect since mission is not created yet 
+class LoginTimeStatic extends LoginTimeBase
+{
+	void LoginTimeStatic()
+	{
+		Init();
+		
+		m_IsStatic = true;
+	}
+	
+	void ~LoginTimeStatic()
+	{
+	}
+};
+
+
+
+class ConnectionLost
+{
+	private ref Widget m_WidgetRoot;
+	private TextWidget m_TextWidgetTitle;
+	private float m_duration;
+		
+	void ConnectionLost(DayZGame game)
+	{		
+		m_WidgetRoot = game.GetWorkspace().CreateWidgets("gui/layouts/day_z_connection_lost.layout");
+		m_WidgetRoot.Show(false);
+		
+		Class.CastTo(m_TextWidgetTitle, m_WidgetRoot.FindAnyWidget("TextWidget"));
+		m_duration = 0.0;
+	}
+	
+	void Show()
+	{
+		if (!m_WidgetRoot.IsVisible())
+		{
+			if (g_Game.GetUIManager().IsDialogVisible())
+			{
+				g_Game.GetUIManager().HideDialog();
+			}
+			
+			m_WidgetRoot.Show(true);
+			m_TextWidgetTitle.SetText("");
+		}
+	}
+	
+	void Hide()
+	{
+		if (m_WidgetRoot.IsVisible())
+		{
+			m_WidgetRoot.Show(false);
+		}
+	}
+	
+	void SetText(string text)
+	{
+		m_TextWidgetTitle.SetText(text);
+	}
+	
+	float GetDuration()
+	{
+		return m_duration;
+	}
+	
+	void SetDuration(float duration)
+	{
+		m_duration = duration;
+	}
+};
+
+typedef Param3<string, bool, bool> DayZProfilesOption;
+typedef DayZProfilesOption DayZProfilesOptionBool;
+typedef Param3<string, int, int> DayZProfilesOptionInt;
+typedef Param3<string, float, float> DayZProfilesOptionFloat;
+
+class DayZProfilesOptions
+{
+	private ref map<EDayZProfilesOptions, ref DayZProfilesOptionBool> m_DayZProfilesOptionsBool;
+	private ref map<EDayZProfilesOptions, ref DayZProfilesOptionInt> m_DayZProfilesOptionsInt;
+	private ref map<EDayZProfilesOptions, ref DayZProfilesOptionFloat> m_DayZProfilesOptionsFloat;
+	
+	static ref ScriptInvoker m_OnIntOptionChanged 	= new ScriptInvoker();
+	static ref ScriptInvoker m_OnBoolOptionChanged 	= new ScriptInvoker();
+	static ref ScriptInvoker m_OnFloatOptionChanged = new ScriptInvoker();
+	
+	void DayZProfilesOptions()
+	{
+		m_DayZProfilesOptionsBool 	= new map<EDayZProfilesOptions, ref DayZProfilesOptionBool>();
+		m_DayZProfilesOptionsInt 	= new map<EDayZProfilesOptions, ref DayZProfilesOptionInt>();
+		m_DayZProfilesOptionsFloat 	= new map<EDayZProfilesOptions, ref DayZProfilesOptionFloat>();
+	}
+
+	void RegisterProfileOption(EDayZProfilesOptions option, string profileOptionName, bool def = true)
+	{
+		if (!m_DayZProfilesOptionsBool.Contains(option))
+		{
+			//! init of DayZProfilesOption - profileOptionName, value from Profiles files, or use default value
+			bool profileVal = GetProfileValueBool(profileOptionName, def);
+
+			m_DayZProfilesOptionsBool.Set(option, new DayZProfilesOptionBool(profileOptionName, profileVal, def));
+			SetProfileOptionBool(option, profileVal);
+		}
+	}
+	
+	void RegisterProfileOptionBool(EDayZProfilesOptions option, string profileOptionName, bool defaultValue = true)
+	{
+		RegisterProfileOption(option, profileOptionName, defaultValue);
+	}
+	
+	void RegisterProfileOptionInt(EDayZProfilesOptions option, string profileOptionName, int defaultValue = 0)
+	{
+		if (!m_DayZProfilesOptionsInt.Contains(option))
+		{
+			//! init of DayZProfilesOption - profileOptionName, value from Profiles files, or use default value
+			string outValue;
+			GetGame().GetProfileString(profileOptionName, outValue);
+			int value = outValue.ToInt();
+
+			m_DayZProfilesOptionsInt.Set(option, new DayZProfilesOptionInt(profileOptionName, value, defaultValue));
+			SetProfileOptionInt(option, value);
+		}
+	}
+	
+	void RegisterProfileOptionFloat(EDayZProfilesOptions option, string profileOptionName, float defaultValue = 0.0)
+	{
+		if (!m_DayZProfilesOptionsFloat.Contains(option))
+		{
+			//! init of DayZProfilesOption - profileOptionName, value from Profiles files, or use default value
+			string outValue;
+			GetGame().GetProfileString(profileOptionName, outValue);
+			float value = outValue.ToFloat();
+
+			m_DayZProfilesOptionsFloat.Set(option, new DayZProfilesOptionFloat(profileOptionName, value, defaultValue));
+			SetProfileOptionFloat(option, value);
+		}
+	}
+
+	void ResetOptionsBool()
+	{
+		if (!m_DayZProfilesOptionsBool)
+		{
+			m_DayZProfilesOptionsBool = new map<EDayZProfilesOptions, ref DayZProfilesOptionBool>();
+		}
+
+		foreach (EDayZProfilesOptions e_opt, DayZProfilesOptionBool r_opt : m_DayZProfilesOptionsBool)
+		{
+			bool profileVal = GetProfileValueBool(r_opt.param1, r_opt.param3);
+			SetProfileOptionBool(e_opt, profileVal);
+		}	
+	}
+	
+	void ResetOptions()
+	{
+		ResetOptionsBool();
+	}
+	
+	void ResetOptionsInt()
+	{
+		if (!m_DayZProfilesOptionsInt)
+		{
+			m_DayZProfilesOptionsInt = new map<EDayZProfilesOptions, ref DayZProfilesOptionInt>();
+		}
+
+		foreach (EDayZProfilesOptions e_opt, DayZProfilesOptionInt r_opt : m_DayZProfilesOptionsInt)
+		{
+			string outValue;
+			GetGame().GetProfileString(r_opt.param1, outValue);
+			int value = outValue.ToInt();
+			SetProfileOptionInt(e_opt, value);
+		}	
+	}
+	
+	void ResetOptionsFloat()
+	{
+		if (!m_DayZProfilesOptionsFloat)
+		{
+			m_DayZProfilesOptionsFloat = new map<EDayZProfilesOptions, ref DayZProfilesOptionFloat>();
+		}
+
+		foreach (EDayZProfilesOptions e_opt, DayZProfilesOptionFloat r_opt : m_DayZProfilesOptionsFloat)
+		{
+			string outValue;
+			GetGame().GetProfileString(r_opt.param1, outValue);
+			float value = outValue.ToFloat();
+			SetProfileOptionFloat(e_opt, value);
+		}	
+	}
+	
+	void SetProfileOption(EDayZProfilesOptions option, bool value)
+	{
+		if (m_DayZProfilesOptionsBool && m_DayZProfilesOptionsBool.Contains(option))
+		{
+			DayZProfilesOptionBool po = m_DayZProfilesOptionsBool.Get(option);
+			
+			po.param2 = value;
+			GetGame().SetProfileString(po.param1, value.ToString());
+			GetGame().SaveProfile();
+			
+			m_OnBoolOptionChanged.Invoke(po.param1, value);
+		}	
+	}
+
+	void SetProfileOptionBool(EDayZProfilesOptions option, bool value)
+	{
+		SetProfileOption(option, value);
+	}
+	
+	void SetProfileOptionInt(EDayZProfilesOptions option, int value)
+	{
+		if (m_DayZProfilesOptionsInt && m_DayZProfilesOptionsInt.Contains(option))
+		{
+			DayZProfilesOptionInt po = m_DayZProfilesOptionsInt.Get(option);
+			
+			po.param2 = value;
+			GetGame().SetProfileString(po.param1, value.ToString());
+			GetGame().SaveProfile();
+			
+			m_OnIntOptionChanged.Invoke(option, value);
+		}	
+	}
+	
+	void SetProfileOptionFloat(EDayZProfilesOptions option, float value)
+	{
+		if (m_DayZProfilesOptionsFloat && m_DayZProfilesOptionsFloat.Contains(option))
+		{
+			DayZProfilesOptionFloat po = m_DayZProfilesOptionsFloat.Get(option);
+			
+			po.param2 = value;
+			GetGame().SetProfileString(po.param1, value.ToString());
+			GetGame().SaveProfile();
+			
+			m_OnFloatOptionChanged.Invoke(po.param1, value);
+		}	
+	}
+
+	bool GetProfileOption(EDayZProfilesOptions option)
+	{
+		if (m_DayZProfilesOptionsBool && m_DayZProfilesOptionsBool.Contains(option))
+		{
+			DayZProfilesOptionBool po = m_DayZProfilesOptionsBool.Get(option);
+			return po.param2;
+		}
+		
+		return true;
+	}
+	
+	bool GetProfileOptionBool(EDayZProfilesOptions option)
+	{
+		return GetProfileOption(option);
+	}
+	
+	int GetProfileOptionInt(EDayZProfilesOptions option)
+	{
+		if (m_DayZProfilesOptionsInt && m_DayZProfilesOptionsInt.Contains(option))
+		{
+			DayZProfilesOptionInt po = m_DayZProfilesOptionsInt.Get(option);
+			return po.param2;
+		}
+		
+		return 0;
+	}
+	
+	float GetProfileOptionFloat(EDayZProfilesOptions option)
+	{
+		if (m_DayZProfilesOptionsFloat && m_DayZProfilesOptionsFloat.Contains(option))
+		{
+			DayZProfilesOptionFloat po = m_DayZProfilesOptionsFloat.Get(option);
+			return po.param2;
+		}
+		
+		return 0.0;
+	}
+	
+	bool GetProfileOptionDefault(EDayZProfilesOptions option)
+	{
+		return GetProfileOptionDefaultBool(option);
+	}
+	
+	bool GetProfileOptionDefaultBool(EDayZProfilesOptions option)
+	{
+		if (m_DayZProfilesOptionsBool && m_DayZProfilesOptionsBool.Contains(option))
+		{
+			DayZProfilesOptionBool po = m_DayZProfilesOptionsBool.Get(option);
+			return po.param3;
+		}
+		
+		ErrorEx("Invalid profile option id! Returning 'true'.", ErrorExSeverity.WARNING);
+		return true;
+	}
+	
+	int GetProfileOptionDefaultInt(EDayZProfilesOptions option)
+	{
+		if (m_DayZProfilesOptionsInt && m_DayZProfilesOptionsInt.Contains(option))
+		{
+			DayZProfilesOptionInt po = m_DayZProfilesOptionsInt.Get(option);
+			return po.param3;
+		}
+		
+		ErrorEx("Invalid profile option id! Returning '0'.", ErrorExSeverity.WARNING);
+		return 0;
+	}
+	
+	float GetProfileOptionDefaultFloat(EDayZProfilesOptions option)
+	{
+		if (m_DayZProfilesOptionsFloat && m_DayZProfilesOptionsFloat.Contains(option))
+		{
+			DayZProfilesOptionFloat po = m_DayZProfilesOptionsFloat.Get(option);
+			return po.param3;
+		}
+		
+		ErrorEx("Invalid profile option id! Returning '0.0'.", ErrorExSeverity.WARNING);
+		return 0.0;
+	}
+	
+	map<EDayZProfilesOptions, ref DayZProfilesOptionBool> GetProfileOptionMap()
+	{
+		if (m_DayZProfilesOptions)
+			return m_DayZProfilesOptions;
+
+		return null;
+	}
+
+	//!
+	//! DEPRECATED
+	private ref map<EDayZProfilesOptions, ref DayZProfilesOption> m_DayZProfilesOptions;
+	private DayZGame m_Game;
+}
+
+enum DayZGameState
+{
+	UNDEFINED,
+	MAIN_MENU,
+	JOIN,
+	PARTY,
+	CONNECT,
+	CONNECTING,
+	IN_GAME
+}
+
+enum DayZLoadState
+{
+	UNDEFINED,
+	MAIN_MENU_START,
+	MAIN_MENU_CONTROLLER_SELECT,
+	MAIN_MENU_USER_SELECT,
+	JOIN_START,
+	JOIN_CONTROLLER_SELECT,
+	JOIN_USER_SELECT,
+	PARTY_START,
+	PARTY_CONTROLLER_SELECT,
+	PARTY_USER_SELECT,
+	CONNECT_START,
+	CONNECT_USER_SELECT,
+	CONNECT_CONTROLLER_SELECT,
+	MISSION_START,
+	MISSION_USER_SELECT,
+	MISSION_CONTROLLER_SELECT
+}
+
+class LoadingScreen
+{
+	ref Widget m_WidgetRoot;
+	TextWidget m_TextWidgetTitle;
+	TextWidget m_TextWidgetStatus;
+	TextWidget m_ModdedWarning;
+	ImageWidget m_ImageWidgetBackground;
+	DayZGame m_DayZGame;
+	float m_LastProgressUpdate;
+	
+	ImageWidget m_ImageLogoMid;
+	ImageWidget m_ImageLogoCorner;
+	ImageWidget m_ImageLoadingIcon;
+	ImageWidget m_ImageBackground;
+	ProgressBarWidget m_ProgressLoading;
+	float m_ImageLoadingIconRotation;
+	TextWidget m_ProgressText;
+	
+	int m_Counter;
+	ref Timer m_Timer;
+	ref UiHintPanelLoading m_HintPanel;
+	void LoadingScreen(DayZGame game)
+	{
+		m_DayZGame = game;
+		
+		m_WidgetRoot = game.GetLoadingWorkspace().CreateWidgets("gui/layouts/loading.layout");
+		Class.CastTo(m_ImageLogoMid, m_WidgetRoot.FindAnyWidget("ImageLogoMid"));
+		Class.CastTo(m_ImageLogoCorner, m_WidgetRoot.FindAnyWidget("ImageLogoCorner"));
+		
+		Class.CastTo(m_TextWidgetTitle, m_WidgetRoot.FindAnyWidget("TextWidget"));
+		Class.CastTo(m_TextWidgetStatus, m_WidgetRoot.FindAnyWidget("StatusText"));
+		Class.CastTo(m_ImageWidgetBackground, m_WidgetRoot.FindAnyWidget("ImageBackground"));
+		Class.CastTo(m_ImageLoadingIcon, m_WidgetRoot.FindAnyWidget("ImageLoadingIcon"));
+		Class.CastTo(m_ModdedWarning, m_WidgetRoot.FindAnyWidget("ModdedWarning"));
+
+		m_ImageBackground = ImageWidget.Cast(m_WidgetRoot.FindAnyWidget("ImageBackground"));
+		m_ProgressLoading = ProgressBarWidget.Cast(m_WidgetRoot.FindAnyWidget("LoadingBar"));
+		
+		string tmp;
+		m_ProgressText = TextWidget.Cast(m_WidgetRoot.FindAnyWidget("ProgressText"));
+		if (GetGame())
+		{
+			m_ProgressText.Show(GetGame().CommandlineGetParam("loadingTest", tmp));
+		}
+		m_WidgetRoot.FindAnyWidget("notification_root").Show(false);
+		
+		#ifdef PLATFORM_CONSOLE
+		#ifdef PLATFORM_XBOX
+		#ifdef BUILD_EXPERIMENTAL
+			Widget expNotification = m_WidgetRoot.FindAnyWidget("notification_root");
+			if (expNotification)
+			{
+				expNotification.Show(true);
+			}
+		#endif
+		#endif
+		#endif
+		
+		m_ModdedWarning.Show(g_Game.ReportModded());
+		m_ImageLogoMid.Show(true);
+		m_ImageLogoCorner.Show(false);
+		
+		m_ImageWidgetBackground.Show(true);		
+		m_Counter = 0;
+				
+		// lighten up your desktop
+		game.GetBacklit().LoadingAnim();
+		
+		ProgressAsync.SetProgressData(m_ProgressLoading);
+		ProgressAsync.SetUserData(m_ImageBackground);
+	}
+
+	//! DEPRECATED
+	void OnTimer();
+	
+	void Inc()
+	{
+		m_LastProgressUpdate = m_DayZGame.GetTickTime();
+		m_Counter++;
+		if (m_Counter == 1)
+		{
+			Show();
+		}
+	}
+	
+	void Dec()
+	{
+		m_Counter = m_Counter - 1;
+	
+		if (m_Counter <= 0)
+		{
+			m_Counter = 0;
+			EndLoading();
+			m_HintPanel = null;
+		}
+	}
+	
+	void EndLoading()
+	{
+		ProgressAsync.SetProgressData(null);
+		ProgressAsync.SetUserData(null);
+		m_WidgetRoot.Show(false);
+		GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).Call(g_Game.CheckDialogs);
+	}
+	
+	bool IsLoading()
+	{
+		return m_WidgetRoot.IsVisible();
+	}
+	
+	void SetTitle(string title)
+	{
+		m_TextWidgetTitle.SetText(title);
+	}
+	
+	void SetStatus(string status)
+	{
+		m_TextWidgetStatus.SetText(status);
+	}
+	
+	void SetProgress(float val)
+	{
+		float time_delta = m_DayZGame.GetTickTime() - m_LastProgressUpdate;
+		
+		m_LastProgressUpdate = m_DayZGame.GetTickTime();
+	}
+	
+	void OnUpdate(float timeslice)
+	{
+
+	}
+	
+	void ShowEx(DayZGame game)
+	{
+		if (!m_HintPanel)
+		{
+			m_HintPanel					= new UiHintPanelLoading(m_WidgetRoot.FindAnyWidget("hint_frame"));
+			m_HintPanel.Init(game);
+		}
+
+		Show();
+	}
+	
+	void Show()
+	{
+		Widget lIcon = m_ImageBackground;
+		Widget pText = m_ProgressLoading;
+		m_ProgressText.SetText("");
+		m_ProgressLoading.SetCurrent(0.0);
+		m_ImageBackground.SetMaskProgress(0.0);
+		
+		if (!m_WidgetRoot.IsVisible())
+		{
+			if (m_DayZGame.GetUIManager().IsDialogVisible())
+			{
+				m_DayZGame.GetUIManager().HideDialog();
+			}
+			
+			if (m_DayZGame.GetMissionState() == DayZGame.MISSION_STATE_MAINMENU)
+			{
+				m_ImageLogoMid.Show(false);
+				m_ImageLogoCorner.Show(false);				
+				m_ImageWidgetBackground.Show(true);		
+				m_TextWidgetStatus.Show(true);
+			}
+			else
+			{
+				m_ImageLogoMid.Show(true);
+				m_ImageLogoCorner.Show(false);
+				m_ImageWidgetBackground.Show(true);
+				m_TextWidgetStatus.Show(false);
+			}
+			
+			m_WidgetRoot.Show(true);
+			m_TextWidgetTitle.SetText("");
+			m_TextWidgetStatus.SetText("");
+		}
+		
+		ProgressAsync.SetProgressData(pText);
+		ProgressAsync.SetUserData(lIcon);
+	}
+	
+	void Hide(bool force)
+	{
+		if (force)
+		{
+			while (m_Counter > 0)
+			{
+				Dec();
+			}
+		}
+
+		if (m_Counter <= 0)
+		{
+			m_WidgetRoot.Show(false);
+			ProgressAsync.SetUserData(null);
+			ProgressAsync.SetProgressData(null);
+			m_HintPanel = null;
+		}
+	}
+};
+
+
+class DayZGame extends CGame
+{
+	protected ref BillboardSetHandler m_BillboardSetHandler;
+	
+	const int MISSION_STATE_MAINMENU = 0;
+	const int MISSION_STATE_GAME = 1;
+	const int MISSION_STATE_FINNISH = 2;
+	
+	private const int STATS_COUNT = EConnectivityStatType.COUNT;
+	private EConnectivityStatLevel m_ConnectivityStatsStates[STATS_COUNT];
+	
+	private int m_MissionState;
+	
+	//HK stuff
+	protected DayZGameState						m_GameState;
+	protected DayZLoadState						m_LoadState;
+	protected ref NotificationUI				m_Notifications;
+	protected bool								m_FirstConnect = true;
+	//End HK stuff
+	
+	ref LoadingScreen m_loading;
+	private ref LoginTimeBase m_LoginTimeScreen;
+	private ref LoginQueueBase m_LoginQueue;
+	private int m_LoginTime;
+	
+	private ref ConnectionLost m_connectionLost;
+	private ref TimerQueue m_timerQueue[CALL_CATEGORY_COUNT];
+	private ref ScriptCallQueue m_callQueue[CALL_CATEGORY_COUNT];
+	private ref ScriptInvoker m_updateQueue[CALL_CATEGORY_COUNT];
+	private ref ScriptInvoker m_postUpdateQueue[CALL_CATEGORY_COUNT];
+	private ref DragQueue m_dragQueue;
+	private ref ScriptInvoker m_YieldDataInitInvoker;
+	private ref DayZProfilesOptions m_DayZProfileOptions;
+	private bool m_early_access_dialog_accepted;
+	private UIScriptedMenu m_keyboard_handler;
+	private ScriptModule m_mission_module;
+	private string 	m_MissionPath;
+	private string 	m_MissionFolderPath;
+	private bool	m_IsCtrlHolding;
+	private bool	m_IsWinHolding;
+	private bool	m_IsLeftAltHolding;
+	private bool	m_IsRightAltHolding;
+	
+	private bool	m_IsWorldWetTempUpdateEnabled = true;
+	private bool	m_IsFoodDecayEnabled = true;
+	private float	m_FoodDecayModifier;
+	
+	static bool		m_ReportModded;
+	private bool	m_IsStressTest;
+	private bool 	m_AimLoggingEnabled;
+	int 			m_OriginalCharactersCount;
+	private string 	m_PlayerName;
+	private bool 	m_IsNewCharacter;
+	private bool 	m_IsConnecting;
+	private bool	m_ConnectFromJoin;
+	private bool	m_ShouldShowControllerDisconnect;
+	private bool	m_CursorDesiredVisibilityScript = true;
+	private int		m_PreviousGamepad;
+	private float	m_UserFOV;
+
+	private float	m_DeltaTime;
+
+	float 	m_volume_sound;
+	float 	m_volume_speechEX;
+	float 	m_volume_music;
+	float 	m_volume_VOIP;
+	float 	m_volume_radio;
+	
+	float 	m_PreviousEVValue;
+	float 	m_EVValue = 0;
+	
+	#ifdef DIAG_DEVELOPER
+	private static ref ServerFpsStatsUpdatedEventParams m_ServerFpsStatsParams; 
+	#endif
+	
+	static ref AmmoCamParams m_AmmoShakeParams = new AmmoCamParams();//TODO: make static, reuse
+	
+	static ref ScriptInvoker Event_OnRPC = new ScriptInvoker();
+	
+	private ref Backlit m_Backlit;
+	
+	private ref array<string> m_CharClassNames = new array<string>();
+	private ref array<int> m_ConnectedInputDeviceList; //has to be owned here, 'Input' is a native class
+	
+	//Used for helicrash sound
+	private ref EffectSound m_CrashSound;
+	
+	//Used for Artillery sound
+	private ref EffectSound m_ArtySound;
+	private const int MIN_ARTY_SOUND_RANGE = 300; // The distance under which sound is no longer heard
+	
+	static ref NoiseParams m_NoiseParams = new NoiseParams();
+	static ref TemperatureAccessManager m_TAManager = new TemperatureAccessManager();
+	#ifdef DEVELOPER
+	static bool m_IsPreviewSpawn;//! we set this to 'true' when spawning item through Script Console only for item preview purposes
+	#endif
+	#ifdef DIAG_DEVELOPER
+	ref CameraToolsMenuServer m_CameraToolsMenuServer;
+	#endif
+	// CGame override functions
+	void DayZGame()
+	{
+		PPEManagerStatic.CreateManagerStatic();
+		
+#ifdef PLATFORM_CONSOLE
+		SetMainMenuWorld("MainMenuSceneXbox");
+#endif
+		m_MissionState = MISSION_STATE_GAME;
+		
+		m_keyboard_handler = null;
+		
+		#ifdef DEVELOPER
+		m_early_access_dialog_accepted = true;
+		#endif
+		
+		for (int i = 0; i < CALL_CATEGORY_COUNT; i++)
+		{
+			m_callQueue[i] 		= new ScriptCallQueue();
+			m_updateQueue[i] 	= new ScriptInvoker();
+			m_timerQueue[i] 	= new TimerQueue();
+			
+			m_postUpdateQueue[i] = new ScriptInvoker();
+		}
+		
+		m_dragQueue = new DragQueue;
+		
+		m_LoginTime 		 = 0;
+		
+		string tmp;
+		if (CommandlineGetParam("stresstest", tmp))
+		{
+			m_IsStressTest = true;
+		}
+
+		if (CommandlineGetParam("doAimLogs", tmp))
+		{
+			m_AimLoggingEnabled = true;
+		}
+		
+		// initialize backlit effects
+		m_Backlit = new Backlit();
+		m_Backlit.OnInit(this);
+		
+		m_ReportModded = GetModToBeReported();
+
+	#ifndef NO_GUI
+		if (m_loading == null)
+		{
+			m_loading = new LoadingScreen(this);
+		}
+
+		if (m_loading)
+		{
+			m_loading.ShowEx(this);
+		}
+
+		RefreshMouseCursorVisibility();
+	#endif
+			
+		Debug.Init();
+		Component.Init();
+		CachedObjectsParams.Init();
+		CachedObjectsArrays.Init();
+		BleedChanceData.InitBleedChanceData();
+		GetUApi().PresetSelect(GetUApi().PresetCurrent());
+
+		m_DayZProfileOptions = new DayZProfilesOptions();
+		
+		GetCallQueue(CALL_CATEGORY_GUI).Call(DeferredInit);
+		GetCallQueue(CALL_CATEGORY_GAMEPLAY).Call(GlobalsInit);
+		
+		string path = "cfgVehicles";
+		string child_name = "";
+		int count = ConfigGetChildrenCount(path);
+		
+		for (int p = 0; p < count; ++p)
+		{
+			ConfigGetChildName(path, p, child_name);
+			
+			if (ConfigGetInt(path + " " + child_name + " scope") == 2 && IsKindOf(child_name, "SurvivorBase"))
+				m_CharClassNames.Insert(child_name);
+		}
+		
+		m_IsConnecting = false;
+		m_ConnectFromJoin = false;
+	}
+	
+	// ------------------------------------------------------------
+	private void ~DayZGame()
+	{
+		PPEManagerStatic.DestroyManagerStatic();
+		BleedChanceData.Cleanup();
+		NotificationSystem.CleanupInstance();
+		
+		g_Game = null;
+		SetDispatcher(null);
+		Print("~DayZGame()");
+	}
+	
+	// ------------------------------------------------------------
+	void DeferredInit()
+	{
+		GameOptions opt = new GameOptions();
+		opt.Initialize();
+		
+		GetInput().UpdateConnectedInputDeviceList();
+
+		m_UserFOV = GetUserFOVFromConfig();
+		
+		m_volume_sound 		= GetSoundScene().GetSoundVolume();
+		m_volume_speechEX 	= GetSoundScene().GetSpeechExVolume();
+		m_volume_music 		= GetSoundScene().GetMusicVolume();
+		m_volume_VOIP 		= GetSoundScene().GetVOIPVolume();
+		m_volume_radio 		= GetSoundScene().GetRadioVolume();
+		
+		PPEManagerStatic.GetPPEManager().Init();
+		GetMenuDefaultCharacterData();
+	}
+	
+	// ------------------------------------------------------------
+	void GlobalsInit()
+	{
+		if (GetCEApi())
+		{
+			m_IsWorldWetTempUpdateEnabled = (GetCEApi().GetCEGlobalInt("WorldWetTempUpdate") == 1);
+			
+			m_FoodDecayModifier = GetCEApi().GetCEGlobalFloat("FoodDecay");
+			
+			//check for legacy INT format, if value == float.MIN when read as FLOAT, it is of type INT, so we read it as such below	
+			if (m_FoodDecayModifier == float.MIN)
+			{
+				m_FoodDecayModifier = GetCEApi().GetCEGlobalInt("FoodDecay");
+			}
+		}
+		
+		//we need to perform the load here as some objects behaving correctly after spawn is dependent on CE being initialized before spawning them
+		ObjectSpawnerHandler.OnGameplayDataHandlerLoad();
+	}
+	
+	// ------------------------------------------------------------
+	void RegisterProfilesOptions()
+	{
+		m_DayZProfileOptions.RegisterProfileOptionBool(EDayZProfilesOptions.CROSSHAIR, SHOW_CROSSHAIR);
+		m_DayZProfileOptions.RegisterProfileOptionBool(EDayZProfilesOptions.HUD, SHOW_HUD);
+		m_DayZProfileOptions.RegisterProfileOptionBool(EDayZProfilesOptions.HUD_VEHICLE, SHOW_HUD_VEHICLE);
+		m_DayZProfileOptions.RegisterProfileOptionBool(EDayZProfilesOptions.QUICKBAR, SHOW_QUICKBAR);
+		m_DayZProfileOptions.RegisterProfileOptionBool(EDayZProfilesOptions.SERVER_MESSAGES, SYSTEM_CHAT_MSG);
+		m_DayZProfileOptions.RegisterProfileOptionBool(EDayZProfilesOptions.USERS_CHAT, DIRECT_CHAT_MSG);
+		m_DayZProfileOptions.RegisterProfileOptionBool(EDayZProfilesOptions.RADIO_CHAT, RADIO_CHAT_MSG);
+		m_DayZProfileOptions.RegisterProfileOptionBool(EDayZProfilesOptions.GAME_MESSAGES, GAME_CHAT_MSG, false);
+		m_DayZProfileOptions.RegisterProfileOptionBool(EDayZProfilesOptions.ADMIN_MESSAGES, ADMIN_CHAT_MSG, false);
+		m_DayZProfileOptions.RegisterProfileOptionBool(EDayZProfilesOptions.PLAYER_MESSAGES, PLAYER_CHAT_MSG, false);
+		m_DayZProfileOptions.RegisterProfileOptionBool(EDayZProfilesOptions.SERVERINFO_DISPLAY, SHOW_SERVERINFO, true);
+		m_DayZProfileOptions.RegisterProfileOptionBool(EDayZProfilesOptions.BLEEDINGINDICATION, ENABLE_BLEEDINGINDICATION, true);
+		m_DayZProfileOptions.RegisterProfileOptionBool(EDayZProfilesOptions.CONNECTIVITY_INFO, SHOW_CONNECTIVITYINFO, true);
+		
+		m_DayZProfileOptions.RegisterProfileOptionFloat(EDayZProfilesOptions.HUD_BRIGHTNESS, HUD_BRIGHTNESS, 0.0);
+		
+		m_DayZProfileOptions.RegisterProfileOptionInt(EDayZProfilesOptions.AMBIENT_MUSIC_MODE, OPTIONS_SOUND_AMBIENT_SOUND_MODE, 0);
+	}
+	
+	void ResetProfileOptions()
+	{
+		m_DayZProfileOptions.ResetOptionsBool();
+		m_DayZProfileOptions.ResetOptionsInt();
+		m_DayZProfileOptions.ResetOptionsFloat();
+	}
+	
+	//! Called from C++
+	void SetMissionPath(string path)
+	{
+		m_MissionPath = path;
+		
+		int pos_end = 0;
+		int pos_cur = 0;
+				
+		while (pos_cur != -1)
+		{
+			pos_end = pos_cur;
+			pos_cur = path.IndexOfFrom(pos_cur + 1 , "\\");
+		}
+		
+		m_MissionFolderPath = path.Substring(0, pos_end);	
+	}
+	
+	string GetMissionPath()
+	{
+		return m_MissionPath;
+	}
+	
+	string GetMissionFolderPath()
+	{
+		return m_MissionFolderPath;
+	}
+	
+	override ScriptCallQueue GetCallQueue(int call_category)
+	{
+		return m_callQueue[call_category];
+	}
+
+	override ScriptInvoker GetUpdateQueue(int call_category)
+	{
+		return m_updateQueue[call_category];
+	}
+
+	override ScriptInvoker GetPostUpdateQueue(int call_category)
+	{
+		return m_postUpdateQueue[call_category];
+	}
+	
+	ScriptInvoker GetYieldDataInitInvoker()
+	{
+		if (!m_YieldDataInitInvoker)
+			m_YieldDataInitInvoker = new ScriptInvoker();
+
+		return m_YieldDataInitInvoker;
+	}
+	
+	override TimerQueue GetTimerQueue(int call_category)
+	{
+		return m_timerQueue[call_category];
+	}
+
+	override DragQueue GetDragQueue()
+	{
+		return m_dragQueue;
+	}
+	
+	// ------------------------------------------------------------
+	void OnGameplayDataHandlerLoad()
+	{
+	
+	}
+	
+
+	// ------------------------------------------------------------
+	int GetMissionState()
+	{
+		return m_MissionState;
+	}
+	
+	// ------------------------------------------------------------
+	void SetMissionState(int state)
+	{
+		m_MissionState = state;
+	}
+	
+	// ------------------------------------------------------------
+	bool GetProfileOption(EDayZProfilesOptions option)
+	{
+		return m_DayZProfileOptions.GetProfileOption(option);
+	}
+	 	
+	bool GetProfileOptionBool(EDayZProfilesOptions option)
+	{
+		return GetProfileOption(option);
+	}
+	
+	int GetProfileOptionInt(EDayZProfilesOptions option)
+	{
+		return m_DayZProfileOptions.GetProfileOptionInt(option);
+	}
+	
+	float GetProfileOptionFloat(EDayZProfilesOptions option)
+	{
+		return m_DayZProfileOptions.GetProfileOptionFloat(option);
+	}
+	
+	bool GetProfileOptionDefault(EDayZProfilesOptions option)
+	{
+		return m_DayZProfileOptions.GetProfileOptionDefaultBool(option);
+	}
+	
+	bool GetProfileOptionDefaultBool(EDayZProfilesOptions option)
+	{
+		return GetProfileOptionDefault(option);
+	}
+	
+	int GetProfileOptionDefaultInt(EDayZProfilesOptions option)
+	{
+		return m_DayZProfileOptions.GetProfileOptionDefaultInt(option);
+	}
+	
+	float GetProfileOptionDefaultFloat(EDayZProfilesOptions option)
+	{
+		return m_DayZProfileOptions.GetProfileOptionDefaultFloat(option);
+	}
+	
+	void SetProfileOption(EDayZProfilesOptions option, bool value)
+	{
+		m_DayZProfileOptions.SetProfileOptionBool(option, value);
+	}
+	
+	void SetProfileOptionBool(EDayZProfilesOptions option, bool value)
+	{
+		SetProfileOption(option, value);
+	}
+	
+	void SetProfileOptionInt(EDayZProfilesOptions option, int value)
+	{
+		m_DayZProfileOptions.SetProfileOptionInt(option, value);
+	}
+	
+	void SetProfileOptionFloat(EDayZProfilesOptions option, float value)
+	{
+		m_DayZProfileOptions.SetProfileOptionFloat(option, value);
+	}
+	
+	map<EDayZProfilesOptions, ref DayZProfilesOption> GetProfileOptionMap()
+	{
+		return m_DayZProfileOptions.GetProfileOptionMap();
+	}
+	
+	bool IsStressTest()
+	{
+		return m_IsStressTest;
+	}
+	
+	bool IsAimLogEnabled()
+	{
+		return m_AimLoggingEnabled;
+	}
+	
+	void SetGameState(DayZGameState state)
+	{
+		m_GameState = state;
+	}
+	
+	DayZGameState GetGameState()
+	{
+		return m_GameState;
+	}
+	
+	void SetLoadState(DayZLoadState state)
+	{
+		m_LoadState = state;
+	}
+	
+	DayZLoadState GetLoadState()
+	{
+		return m_LoadState;
+	}
+	
+	static bool ReportModded()
+	{
+		return m_ReportModded;
+	}
+	
+	Backlit GetBacklit()
+	{
+		return m_Backlit;
+	}
+	
+	// ------------------------------------------------------------
+	override bool IsInventoryOpen()
+	{
+#ifndef NO_GUI
+		if (GetUIManager().FindMenu(MENU_INVENTORY) != NULL)
+		{
+			return true;
+		}
+#endif
+		return false;
+	}
+	
+	// ------------------------------------------------------------
+	void EarlyAccessDialog(UIScriptedMenu parent)
+	{
+		if (!m_early_access_dialog_accepted)
+		{
+			g_Game.GetUIManager().EnterScriptedMenu(MENU_EARLYACCESS, parent);
+			m_early_access_dialog_accepted = true;
+		}
+	}
+	
+	// ------------------------------------------------------------
+	//! create custom main menu part (submenu)
+	override UIScriptedMenu CreateScriptedMenu(int id)
+	{
+	#ifndef NO_GUI
+		Mission mission = GetMission();
+		if (mission)
+		{
+			return mission.CreateScriptedMenu(id);
+		}
+	#endif
+		return NULL;
+	}
+		
+	// ------------------------------------------------------------
+	void ReloadMission()
+	{
+	#ifdef ENABLE_LOGGING
+		Print("Reloading mission module!");
+		CreateMission(m_MissionPath);
+	#endif
+	}
+	
+		// ------------------------------------------------------------
+	void CancelLoginQueue()
+	{
+		if (m_LoginQueue)
+		{
+			if (m_LoginQueue.IsStatic())
+			{
+				m_LoginQueue.Hide();
+				delete m_LoginQueue;
+			}
+			else
+			{
+				m_LoginQueue.Close();
+			}
+		}
+	}
+	// ------------------------------------------------------------
+	void CancelLoginTimeCountdown()
+	{
+		GetCallQueue(CALL_CATEGORY_SYSTEM).Remove(this.LoginTimeCountdown);
+		
+		if (m_LoginTimeScreen)
+		{
+			if (m_LoginTimeScreen.IsStatic())
+			{
+				m_LoginTimeScreen.Hide();
+				delete m_LoginTimeScreen;
+			}
+			else
+			{
+				m_LoginTimeScreen.Close();
+			}
+		}
+	}
+	// ------------------------------------------------------------
+	private void ClearConnectivityStates()
+	{
+		for (int i = 0; i < STATS_COUNT; i++)
+			m_ConnectivityStatsStates[i] = 0;
+	}
+	
+	
+	// ------------------------------------------------------------
+	override void OnEvent(EventType eventTypeId, Param params)
+	{
+		string address;
+		int port;
+		int high, low;
+		
+		switch (eventTypeId)
+		{
+			case StartupEventTypeID:
+			{
+				#ifndef SERVER
+				// Just call it, to create the global instance if it doesn't exist yet
+				ParticleManager.GetInstance();
+				#endif
+				break;
+			}
+			case MPSessionStartEventTypeID:
+			{
+				#ifndef SERVER
+				ClearConnectivityStates();
+				#endif
+				m_FirstConnect = true;
+				ClientData.ResetClientData();
+				break;
+			}
+			case MPSessionEndEventTypeID:
+			{
+				LoadingHide();
+				CancelLoginTimeCountdown();
+				SetConnecting(false);
+				SetGameState(DayZGameState.MAIN_MENU);
+				m_FirstConnect = true;
+				#ifdef PLATFORM_CONSOLE
+				if (GetUserManager().GetSelectedUser())
+				{
+					OnlineServices.LeaveGameplaySession();
+					OnlineServices.ClearCurrentServerInfo();
+					if (GetGameState() == DayZGameState.IN_GAME)
+					{
+						SetLoadState(DayZLoadState.MAIN_MENU_START);
+					}
+				}
+				m_Notifications.ClearVoiceNotifications();
+				#endif
+
+				// analytics - disconnected player
+				StatsEventDisconnectedData discData = new StatsEventDisconnectedData();
+				discData.m_CharacterId = g_Game.GetDatabaseID();
+				discData.m_Reason = "quit";
+				Analytics.PlayerDisconnected(discData);
+				break;
+			}
+			case MPSessionFailEventTypeID:
+			{
+				CancelLoginQueue();
+				LoadingHide(true);
+				SetConnecting(false);
+				ProgressAsync.DestroyAllPendingProgresses();
+				
+				if (GetGameState() == DayZGameState.CONNECTING)
+				{
+					SetGameState(DayZGameState.MAIN_MENU);
+				}
+				
+				break;
+			}
+			case MPSessionPlayerReadyEventTypeID:
+			{
+				LoadingHide(true);
+				ProgressAsync.DestroyAllPendingProgresses();
+				
+				SetGameState(DayZGameState.IN_GAME);
+				
+				// analytics - spawned
+				StatsEventSpawnedData spawnData = new StatsEventSpawnedData();
+				spawnData.m_CharacterId = g_Game.GetDatabaseID();
+				spawnData.m_Lifetime = 0;
+				spawnData.m_Position = vector.Zero;
+				if (GetPlayer())
+				{
+					spawnData.m_Position = GetPlayer().GetPosition();
+				}
+				spawnData.m_DaytimeHour = 0;
+				spawnData.m_Population = 0;
+				Analytics.PlayerSpawned(spawnData);
+				
+				#ifdef PLATFORM_CONSOLE
+				m_Notifications.ClearVoiceNotifications();
+				OnlineServices.SetMultiplayState(true);
+				#endif
+				if (m_FirstConnect)
+				{
+					m_FirstConnect = false;
+					if (GetHostAddress(address, port))
+					{
+						AddVisitedServer(address, port);
+					}
+					
+					#ifdef PLATFORM_CONSOLE
+						#ifndef PLATFORM_WINDOWS // if app is not on Windows with -XBOX parameter
+							if (null != GetUserManager().GetSelectedUser())
+							{
+								OnlineServices.EnterGameplaySession();
+								OnlineServices.LoadVoicePrivilege();
+							}
+						#endif
+					#endif
+				}
+				
+				UpdateInputDeviceDisconnectWarning();
+				
+				break;
+			}
+			case MPConnectionLostEventTypeID:
+			{
+				MPConnectionLostEventParams conLost_params;
+				if (Class.CastTo(conLost_params, params))
+				{
+					int duration = conLost_params.param1;
+					OnMPConnectionLostEvent(duration);
+				}
+				break;
+			}
+			case WorldCleaupEventTypeID:
+			{
+				LoadingShow();
+				break;
+			}
+			case DialogQueuedEventTypeID:
+			{
+				GetCallQueue(CALL_CATEGORY_SYSTEM).Call(g_Game.CheckDialogs);
+				break;
+			}
+			case ChatMessageEventTypeID:
+			{
+				ChatMessageEventParams chat_params;
+				if (Class.CastTo(chat_params, params))
+				{
+					
+				}
+				break;
+			}
+			case ProgressEventTypeID:
+			{
+				ProgressEventParams prog_params;
+				if (Class.CastTo(prog_params, params))
+					LoadProgressUpdate(prog_params.param1, prog_params.param2, prog_params.param3);
+				break;
+			}
+			case LoginTimeEventTypeID:
+			{
+				LoginTimeEventParams loginTimeParams;
+				if (Class.CastTo(loginTimeParams, params))
+				{
+					OnLoginTimeEvent(loginTimeParams.param1);
+				}
+				break;
+			}	
+			case RespawnEventTypeID:
+			{
+				RespawnEventParams respawnParams;
+				if (Class.CastTo(respawnParams, params))
+				{
+					OnRespawnEvent(respawnParams.param1);
+				}	
+				break;
+			}
+			case PreloadEventTypeID:
+			{
+				PreloadEventParams preloadParams;
+				if (Class.CastTo(preloadParams, params))
+				{
+					OnPreloadEvent(preloadParams.param1);
+				}	
+				break;
+			}
+			case LogoutEventTypeID:
+			{
+				LogoutEventParams logoutParams;
+				if (Class.CastTo(logoutParams, params))
+				{
+					GetCallQueue(CALL_CATEGORY_GUI).Call(GetMission().StartLogoutMenu, logoutParams.param1);						
+				}
+				break;
+			}
+			case SelectedUserChangedEventTypeID:
+			{
+				OnlineServices.Init();
+				break;
+			}
+			case LoginStatusEventTypeID:
+			{
+				LoginStatusEventParams loginStatusParams;
+				Class.CastTo(loginStatusParams, params);
+	
+				string msg1 = loginStatusParams.param1;
+				string msg2 = loginStatusParams.param2;
+				string finalMsg;
+					
+				// write either to login time screen or loading screen
+				if (m_LoginTimeScreen)
+				{
+					finalMsg = msg1;
+					// login time screen supports two lines
+					if (msg2.Length() > 0)
+						finalMsg += "\n" + msg2;
+						
+					m_LoginTimeScreen.SetStatus(finalMsg);
+				}
+				else if (m_loading)
+				{
+					// loading only one line, but it's a long one
+					finalMsg = msg1 + " " + msg2;
+					m_loading.SetStatus(finalMsg);
+				}
+				break;
+			}
+			case ConnectingStartEventTypeID:
+			{
+				g_Game.SetGameState(DayZGameState.CONNECTING);
+				SetConnecting(true);
+				break;
+			}
+			case ConnectingAbortEventTypeID:
+			{
+				g_Game.SetGameState(DayZGameState.MAIN_MENU);
+				SetConnecting(false);
+				if (m_ConnectFromJoin)
+				{
+					m_ConnectFromJoin = false;
+					AbortMission();
+				}
+				break;
+			}
+			case DLCOwnerShipFailedEventTypeID:
+			{
+				DLCOwnerShipFailedParams dlcParams;
+				if (Class.CastTo(dlcParams, params))
+				{
+					Print("### DLC Ownership failed !!! Map: " + dlcParams.param1);
+				}
+				break;
+			}
+			case ConnectivityStatsUpdatedEventTypeID:
+			{
+				ConnectivityStatsUpdatedEventParams connectivityStatsParams; 
+				if (Class.CastTo(connectivityStatsParams, params))
+				{
+					PlayerIdentity playerIdentity = connectivityStatsParams.param1;
+					
+					int pingAvg = playerIdentity.GetPingAvg();
+					if (pingAvg < GetWorld().GetPingWarningThreshold())
+					{
+						SetConnectivityStatState(EConnectivityStatType.PING, EConnectivityStatLevel.OFF);
+					}
+					else if (pingAvg < GetWorld().GetPingCriticalThreshold())
+					{
+						SetConnectivityStatState(EConnectivityStatType.PING, EConnectivityStatLevel.LEVEL1);
+					}
+					else
+					{
+						SetConnectivityStatState(EConnectivityStatType.PING, EConnectivityStatLevel.LEVEL2);
+					}
+				}
+				break;
+			}
+			case ServerFpsStatsUpdatedEventTypeID:
+			{
+				ServerFpsStatsUpdatedEventParams serverFpsStatsParams; 
+				if (Class.CastTo(serverFpsStatsParams, params))
+				{
+					#ifdef DIAG_DEVELOPER
+					m_ServerFpsStatsParams = serverFpsStatsParams;
+					#endif
+					float fps = serverFpsStatsParams.param1;
+					if (fps > GetWorld().GetServerFpsWarningThreshold())
+					{
+						SetConnectivityStatState(EConnectivityStatType.SERVER_PERF, EConnectivityStatLevel.OFF);
+					}
+					else if (fps > GetWorld().GetServerFpsCriticalThreshold())
+					{
+						SetConnectivityStatState(EConnectivityStatType.SERVER_PERF, EConnectivityStatLevel.LEVEL1);
+					}
+					else
+					{
+						SetConnectivityStatState(EConnectivityStatType.SERVER_PERF, EConnectivityStatLevel.LEVEL2);
+					}
+				}
+				break;
+			}
+		}
+		
+		VONManager.GetInstance().OnEvent(eventTypeId, params);
+
+		Mission mission = GetMission();
+		if (mission)
+		{
+			mission.OnEvent(eventTypeId, params);
+		}
+		
+		ErrorModuleHandler emh = ErrorModuleHandler.GetInstance();
+		if (emh)
+			emh.OnEvent(eventTypeId, params);
+	}
+	
+	protected void SetConnectivityStatState(EConnectivityStatType type, EConnectivityStatLevel level)
+	{
+		if (level != m_ConnectivityStatsStates[type])
+		{
+			if (OnConnectivityStatChange(type, level, m_ConnectivityStatsStates[type]))//before setting the prev. level to be the current level, we need to make sure we successfully set the icon
+			{
+				m_ConnectivityStatsStates[type] = level;
+			}
+		}
+	}
+	
+	protected bool OnConnectivityStatChange(EConnectivityStatType type, EConnectivityStatLevel newLevel, EConnectivityStatLevel oldLevel)
+	{
+		if (!GetGame() || !GetGame().GetMission())
+			return false;
+		Hud hud = GetGame().GetMission().GetHud();
+		if (!hud) 
+			return false;
+
+		hud.SetConnectivityStatIcon(type, newLevel);
+		return true;
+	}
+	
+	#ifdef DIAG_DEVELOPER
+	private void DrawPerformanceStats(float pingAct, float pingAvg, float throttleInput, float throttleOutput)
+	{
+		DbgUI.Begin("Performance Stats", 720, 10);
+		DbgUI.Text("pingAct:" + pingAct );
+		int color = COLOR_WHITE;
+		if ( pingAvg >= GetWorld().GetPingCriticalThreshold())
+			color = COLOR_RED;
+		else if ( pingAvg >= GetWorld().GetPingWarningThreshold())
+			color = COLOR_YELLOW;
+
+		DbgUI.ColoredText(color, "pingAvg:" + pingAvg);
+		DbgUI.Text("Ping Warning Threshold:" + GetWorld().GetPingWarningThreshold());
+		DbgUI.Text("Ping Critical Threshold:" + GetWorld().GetPingCriticalThreshold());
+		DbgUI.PlotLive("pingAvg history:", 300, 125, pingAvg, 100, 100 );
+		DbgUI.Text("Server Fps Warning Threshold:" + GetWorld().GetServerFpsWarningThreshold());
+		DbgUI.Text("Server Fps Critical Threshold:" + GetWorld().GetServerFpsCriticalThreshold());
+		if (m_ServerFpsStatsParams)// SERVER FPS
+		{
+			color = COLOR_WHITE;
+			if ( m_ServerFpsStatsParams.param1 <= GetWorld().GetServerFpsCriticalThreshold())
+				color = COLOR_RED;
+			else if ( m_ServerFpsStatsParams.param1 <= GetWorld().GetServerFpsWarningThreshold())
+				color = COLOR_YELLOW;
+
+			DbgUI.ColoredText(color, "serverFPS:" + m_ServerFpsStatsParams.param1.ToString() );
+			DbgUI.PlotLive("serverFPS history:", 300, 125, m_ServerFpsStatsParams.param1, 100, 100 );
+
+			color = COLOR_WHITE;
+			DbgUI.ColoredText(COLOR_WHITE, "serverFrameTime:" + m_ServerFpsStatsParams.param2.ToString() );
+			DbgUI.PlotLive("serverFrameTime history:", 300, 75, m_ServerFpsStatsParams.param2, 100, 100 );
+
+			color = COLOR_WHITE;
+			if (m_ServerFpsStatsParams.param3 > 0)
+				color = COLOR_RED;
+
+			DbgUI.ColoredText(color, "physStepsSkippedServer:" + m_ServerFpsStatsParams.param3.ToString() );
+			DbgUI.PlotLive("physStepsSkippedServer history:", 300, 75, m_ServerFpsStatsParams.param3, 100, 100 );
+
+			color = COLOR_WHITE;
+			if (m_ServerFpsStatsParams.param4 > 0)
+				color = COLOR_RED;
+			DbgUI.ColoredText(color, "physStepsSkippedClient:" + m_ServerFpsStatsParams.param4.ToString() );
+			DbgUI.PlotLive("physStepsSkippedClient history:", 300, 75, m_ServerFpsStatsParams.param4, 100, 100 );
+		}
+
+		DbgUI.Text("throttleInput:" + throttleInput);
+		DbgUI.PlotLive("throttleInput history:", 300, 75, throttleInput, 100, 50 );
+		DbgUI.Text("throttleOutput:" + throttleOutput);
+		DbgUI.PlotLive("throttleOutput history:", 300, 75, throttleOutput, 100, 50 );
+		DbgUI.End();
+	}
+	#endif
+	
+	void AddVoiceNotification(VONStopSpeakingEventParams vonStartParams)
+	{
+		m_Notifications.AddVoiceNotification(vonStartParams.param2, vonStartParams.param1);
+	}
+	
+	void RemoveVoiceNotification(VONStopSpeakingEventParams vonStopParams)
+	{
+		m_Notifications.RemoveVoiceNotification(vonStopParams.param2);
+	}
+	
+	// ------------------------------------------------------------	
+	void UpdateLoginQueue(float timeslice)
+	{
+		int pos = GetUIManager().GetLoginQueuePosition();
+		
+		//! Display login queue position dialog
+		if (!m_LoginQueue && pos > 0)
+		{	
+			GetUIManager().CloseAll();
+			
+			if (GetMission())
+			{
+				UIScriptedMenu parent = GetUIManager().GetMenu();
+				EnterLoginQueue(parent);
+			}
+			else
+			{
+				m_LoginQueue = new LoginQueueStatic();
+				GetUIManager().ShowScriptedMenu(m_LoginQueue, null);
+			}
+		}
+		if (m_LoginQueue)
+		{
+			m_LoginQueue.SetPosition(pos);
+
+			//! manually update static login queue dialog
+			LoginQueueStatic loginQueue;
+			if (LoginQueueBase.CastTo(loginQueue, m_LoginQueue))
+			{
+				loginQueue.Update(timeslice);
+			}
+		}
+	}
+	
+	// ------------------------------------------------------------
+	void OnLoginTimeEvent(int loginTime)
+	{
+#ifndef NO_GUI
+		// remove login queue if exits	
+		CancelLoginQueue();	
+		
+		GetUserManager().GetUserDatabaseIdAsync();
+		
+		m_LoginTime = loginTime;
+		
+		// timer for login
+		if (m_LoginTime > 0)
+		{	
+			if (!m_LoginTimeScreen)
+			{
+				GetUIManager().CloseAll();
+				
+				if (GetMission())
+				{
+					UIScriptedMenu parent = GetUIManager().GetMenu();
+					EnterLoginTime(parent);
+				}
+				else
+				{
+					m_LoginTimeScreen = new LoginTimeStatic();
+					GetUIManager().ShowScriptedMenu(m_LoginTimeScreen, null);
+				}
+			}
+			
+			m_LoginTimeScreen.SetTime(m_LoginTime);
+			m_LoginTimeScreen.Show();
+			
+			GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(this.LoginTimeCountdown, 1000, true);
+		}
+#endif
+	}
+	
+	// ------------------------------------------------------------
+	void LoginTimeCountdown()
+	{
+		if (m_LoginTime > 0)
+		{
+			if (m_LoginTimeScreen)
+				m_LoginTimeScreen.SetTime(m_LoginTime);
+
+			m_LoginTime--;
+		}
+		else
+		{
+			// stop the call loop
+			CancelLoginTimeCountdown();
+		}
+	}
+	
+	// ------------------------------------------------------------
+	void OnRespawnEvent(int time)
+	{	
+		// use login time screen for respawn timer
+		if (time >= 0)
+		{	
+			m_LoginTime = time;
+			if (!m_LoginTimeScreen)
+			{
+				GetUIManager().CloseAll();
+				
+				UIScriptedMenu parent = GetUIManager().GetMenu();
+				EnterLoginTime(parent);
+			}
+			
+			m_LoginTimeScreen.SetRespawn(true);
+			m_LoginTimeScreen.SetTime(m_LoginTime);
+			m_LoginTimeScreen.Show();
+			
+			GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(this.LoginTimeCountdown, 1000, true);
+		}
+
+		if (GetPlayer())
+			GetPlayer().StopDeathDarkeningEffect();
+
+		PPERequesterBank.GetRequester(PPERequester_DeathDarkening).Start(new Param1<float>(1.0));
+	}
+	
+	// ------------------------------------------------------------
+	void OnPreloadEvent(vector pos)
+	{
+		// cancel only login time (respawn time is parallel with preload, but login time is not)
+		if (m_LoginTimeScreen && !m_LoginTimeScreen.IsRespawn())
+			CancelLoginTimeCountdown();
+		
+		// tell game to continue
+		StoreLoginDataPrepare();
+	}
+		
+	// ------------------------------------------------------------
+	// Serialize and send default character information to server (must be called)
+	void StoreLoginDataPrepare()
+	{
+		ScriptReadWriteContext ctx = new ScriptReadWriteContext;
+		
+		//GetMenuData().RequestGetDefaultCharacterData();
+		GetMenuDefaultCharacterData().SerializeCharacterData(ctx.GetWriteContext());
+		StoreLoginData(ctx.GetWriteContext());
+	}
+	
+	// ------------------------------------------------------------
+	void EnterLoginQueue(UIMenuPanel parent)
+	{
+		m_LoginQueue = LoginQueueBase.Cast(GetUIManager().EnterScriptedMenu(MENU_LOGIN_QUEUE, parent)); 		
+	}
+	
+	// ------------------------------------------------------------
+	void EnterLoginTime(UIMenuPanel parent)
+	{			 	
+		m_LoginTimeScreen = LoginTimeBase.Cast(GetUIManager().EnterScriptedMenu(MENU_LOGIN_TIME, parent)); 		
+	}
+	
+	// ------------------------------------------------------------
+	void OnMPConnectionLostEvent(int duration)
+	{
+		if (duration >= 0)//(-1 means conn. reestablished)
+			SetConnectivityStatState(EConnectivityStatType.CONN_LOST, EConnectivityStatLevel.LEVEL1);
+		else
+			SetConnectivityStatState(EConnectivityStatType.CONN_LOST, EConnectivityStatLevel.OFF);
+		
+		#ifdef PLATFORM_PS4
+		//PSN Set multiplay state	
+		if (duration < 0 && GetGameState() == DayZGameState.IN_GAME)
+		{
+			OnlineServices.SetMultiplayState(true);
+		}
+		else
+		{
+			OnlineServices.SetMultiplayState(false);
+		}
+		#endif
+	}
+	
+	// ------------------------------------------------------------
+	void LoadProgressUpdate(int progressState, float progress, string title)
+	{
+	#ifndef NO_GUI
+		switch (progressState)
+		{
+		case PROGRESS_START:
+			{
+			#ifndef NO_GUI	
+				// get out of the black screen immediately
+				GetUIManager().ScreenFadeOut(0);
+			#endif
+				m_loading.Inc();
+				m_loading.SetTitle(title);
+				if (m_loading.m_HintPanel)
+					m_loading.m_HintPanel.ShowRandomPage();
+				
+			}
+			break;
+	
+		case PROGRESS_FINISH:
+			{
+				m_loading.Dec();
+			}
+			break;
+	
+		case PROGRESS_PROGRESS:
+			{
+				m_loading.SetProgress(progress);
+				
+			}
+			break;
+	
+		case PROGRESS_UPDATE:
+			{
+				m_loading.SetProgress(0);
+			}
+			break;
+		}
+	#endif
+	}
+	
+	// ------------------------------------------------------------
+	override void OnAfterCreate()
+	{
+		Math.Randomize(-1);
+	}
+	
+	// ------------------------------------------------------------
+	override void OnActivateMessage()
+	{
+		RefreshMouseCursorVisibility();
+	}
+
+	// ------------------------------------------------------------
+	override void OnDeactivateMessage()
+	{
+		RefreshMouseCursorVisibility();
+	}
+	
+	// ------------------------------------------------------------
+	override bool OnInitialize()
+	{
+		ParticleList.PreloadParticles();
+		
+		RegisterProfilesOptions();
+		SetHudBrightness(GetHUDBrightnessSetting());
+		
+		InitNotifications();
+		m_Visited = new TStringArray;
+		GetProfileStringList("SB_Visited", m_Visited);
+		
+		if (GetLoadState() == DayZLoadState.UNDEFINED)
+		{
+			string param;
+			
+			if (GetCLIParam("join", param))
+			{
+				JoinLaunch();
+				#ifndef PLATFORM_PS4
+				CreateTitleScreen();
+				#endif
+			}
+			else if (GetCLIParam("connect", param))
+			{
+				ConnectLaunch();
+			}
+			else if (GetCLIParam("mission", param))
+			{
+				MissionLaunch();
+			}
+			else if (GetCLIParam("party", param))
+			{
+				PartyLaunch();
+			}
+			else
+			{
+				MainMenuLaunch();
+			}
+			
+			return true;
+		}
+		
+		return false;
+	}
+	
+	void InitNotifications()
+	{
+		NotificationSystem.InitInstance();
+		m_Notifications = new NotificationUI();
+	}
+	
+	protected ref Widget		m_IntroMenu;
+	protected ref Widget		m_GamepadDisconnectMenu; //DEPRECATED
+	protected int				m_PrevBlur;
+	
+	protected string			m_DatabaseID;
+	
+	protected string			m_ConnectAddress;
+	protected int				m_ConnectPort;
+	protected int				m_ConnectSteamQueryPort;
+	protected string			m_ConnectPassword;
+	
+	protected const int			MAX_VISITED = 50;
+	protected ref TStringArray	m_Visited;
+	
+	string GetDatabaseID()
+	{
+		return m_DatabaseID;
+	}
+	
+	void SetDatabaseID(string id)
+	{
+		m_DatabaseID = id;
+		if (GetUIManager().GetMenu())
+		{
+			GetUIManager().GetMenu().Refresh();
+		}
+	}
+	
+	void CreateTitleScreen()
+	{
+		DeleteTitleScreen();
+		m_IntroMenu = GetWorkspace().CreateWidgets("gui/layouts/xbox/day_z_title_screen.layout");
+		RichTextWidget text_widget = RichTextWidget.Cast(m_IntroMenu.FindAnyWidget("InputPromptText"));
+		m_IntroMenu.FindAnyWidget("notification_root").Show(false);
+		if (text_widget)
+		{
+			string text = Widget.TranslateString("#console_start_game");
+			#ifdef PLATFORM_XBOX
+				BiosUserManager user_manager = GetGame().GetUserManager();
+				if (user_manager && user_manager.GetSelectedUser())
+					text_widget.SetText(string.Format(text, "<image set=\"xbox_buttons\" name=\"A\" />"));
+				else
+					text_widget.SetText(string.Format(text, "<image set=\"xbox_buttons\" name=\"A\" />"));
+			#endif
+					
+			#ifdef PLATFORM_PS4
+				string confirm = "cross";
+				if (GetGame().GetInput().GetEnterButton() == GamepadButton.A)
+				{
+					confirm = "cross";
+				}
+				else
+				{
+					confirm = "circle";
+				}
+				text_widget.SetText(string.Format(text, "<image set=\"playstation_buttons\" name=\"" + confirm + "\" />"));
+			#endif
+		}
+		
+		#ifdef PLATFORM_CONSOLE
+		#ifdef PLATFORM_XBOX
+		#ifdef BUILD_EXPERIMENTAL
+			m_IntroMenu.FindAnyWidget("notification_root").Show(true);
+		#endif
+		#endif
+		#endif
+	}
+	
+	void DeleteTitleScreen()
+	{
+		if (m_IntroMenu)
+		{
+			delete m_IntroMenu;
+		}
+	}
+	
+	bool ShouldShowControllerDisconnect()
+	{
+		return m_ShouldShowControllerDisconnect;
+	}
+	
+	void UpdateInputDeviceDisconnectWarning()
+	{
+		#ifdef PLATFORM_CONSOLE
+		if (!GetUIManager().IsMenuOpen(MENU_WARNING_INPUTDEVICE_DISCONNECT))
+		{
+			m_ShouldShowControllerDisconnect = !GetInput().AreAllAllowedInputDevicesActive();
+			if (m_ShouldShowControllerDisconnect)
+			{
+				GetCallQueue(CALL_CATEGORY_GUI).Call(GetUIManager().EnterScriptedMenu,MENU_WARNING_INPUTDEVICE_DISCONNECT,GetUIManager().GetMenu());
+			}
+		}
+		#endif
+	}
+	
+	void JoinLaunch()
+	{
+		SetGameState(DayZGameState.JOIN);
+		SetLoadState(DayZLoadState.JOIN_START);
+		
+		#ifdef PLATFORM_CONSOLE
+			string join_param;
+			if (GetCLIParam("join", join_param))
+			{
+				BiosUserManager user_manager = GetUserManager();
+				user_manager.ParseJoinAsync(join_param);
+			}
+		#endif
+	}
+	
+	void ConnectLaunch()
+	{
+		BiosUserManager user_manager = GetUserManager();
+		if (user_manager.GetTitleInitiator())
+		{
+			user_manager.SelectUserEx(user_manager.GetTitleInitiator());
+		}
+		
+		SetGameState(DayZGameState.CONNECT);
+		SetLoadState(DayZLoadState.CONNECT_START);
+		
+		#ifndef PLATFORM_WINDOWS
+			#ifdef PLATFORM_CONSOLE
+				CreateTitleScreen();
+				GamepadCheck();
+			#endif
+		#else
+			ConnectFromCLI();
+		#endif
+	}
+	
+	void PartyLaunch()
+	{
+		SetGameState(DayZGameState.PARTY);
+		SetLoadState(DayZLoadState.PARTY_START);
+		BiosUserManager user_manager = GetGame().GetUserManager();
+		
+		string param;
+		if (GetCLIParam("party", param))
+		{
+			user_manager.ParsePartyAsync(param);
+			StartRandomCutscene(GetMainMenuWorld());
+		}
+	}
+	
+	void MainMenuLaunch()
+	{
+#ifdef PLATFORM_WINDOWS
+		BiosUserManager user_manager = GetUserManager();
+		if (user_manager)
+		{
+			if (user_manager.GetTitleInitiator())
+			{
+				user_manager.SelectUserEx(user_manager.GetTitleInitiator());
+			}
+		}
+#endif
+		
+		SetGameState(DayZGameState.MAIN_MENU);
+		SetLoadState(DayZLoadState.MAIN_MENU_START);		
+		StartRandomCutscene(GetMainMenuWorld());		
+		DeleteTitleScreen();
+	}
+	
+	void MissionLaunch()
+	{
+		BiosUserManager user_manager = GetUserManager();
+		if (user_manager)
+		{
+			if (user_manager.GetTitleInitiator())
+			{
+				user_manager.SelectUserEx(user_manager.GetTitleInitiator());
+			}
+		}
+		
+		SetGameState(DayZGameState.IN_GAME);
+		SetLoadState(DayZLoadState.MISSION_START);
+		
+
+		#ifndef PLATFORM_WINDOWS
+			#ifdef PLATFORM_CONSOLE			
+				#ifndef DEVELOPER
+					CreateTitleScreen();
+					GamepadCheck();
+					return;
+				#endif
+			#endif
+		#endif
+
+		string mission;
+		GetCLIParam("mission", mission);
+		PlayMission(mission);
+	}
+	
+	void SelectUser(int gamepad = -1)
+	{
+		BiosUserManager user_manager = GetUserManager();
+		if (user_manager)
+		{
+			BiosUser selected_user;
+			if (gamepad > -1)
+			{
+				GetInput().GetGamepadUser(gamepad, selected_user);
+				#ifdef PLATFORM_PS4
+				if (selected_user)
+				#endif
+				{
+					if (user_manager.SelectUserEx(selected_user))
+					{
+						GetGame().GetInput().IdentifyGamepad(GamepadButton.BUTTON_NONE);
+						GetInput().SelectActiveGamepad(gamepad);
+					}
+					else
+					{
+						selected_user = user_manager.GetSelectedUser();
+					}
+					
+					#ifdef PLATFORM_PS4
+					if (!selected_user.IsOnline())
+					{
+						user_manager.LogOnUserAsync(selected_user); 
+						return;
+					}
+					#endif
+				}
+				#ifdef PLATFORM_PS4
+				else
+				{
+					GetInput().ResetActiveGamepad();
+					GamepadCheck();
+				}
+				#endif
+			}
+			
+			if (!selected_user)
+				selected_user = user_manager.GetSelectedUser();
+			
+			if (!selected_user)
+			{
+				user_manager.PickUserAsync();
+				return;
+			}
+			
+			user_manager.SelectUserEx(selected_user);
+			
+			switch (GetLoadState())
+			{
+				case DayZLoadState.JOIN_START:
+				{
+					SetLoadState(DayZLoadState.JOIN_USER_SELECT);				
+					break;
+				}
+				case DayZLoadState.PARTY_START:
+				{
+					SetLoadState(DayZLoadState.PARTY_USER_SELECT);
+					break;
+				}
+				case DayZLoadState.MAIN_MENU_START:
+				{
+					SetLoadState(DayZLoadState.MAIN_MENU_USER_SELECT);
+					break;
+				}
+				case DayZLoadState.CONNECT_START:
+				{
+					SetLoadState(DayZLoadState.CONNECT_USER_SELECT);
+					break;
+				}
+				case DayZLoadState.MISSION_START:
+				{
+					SetLoadState(DayZLoadState.MISSION_USER_SELECT);
+					break;
+				}
+				default:
+					break;
+			}
+			
+			SelectGamepad();
+			g_Game.SetHudBrightness(g_Game.GetHUDBrightnessSetting());
+		}
+	}
+	
+	void SetPreviousGamepad(int gamepad)
+	{
+		m_PreviousGamepad = gamepad;
+	}
+	
+	int GetPreviousGamepad()
+	{
+		return m_PreviousGamepad;
+	}
+	
+	void GamepadCheck()
+	{
+#ifndef AUTOTEST
+		if (GetInput().IsActiveGamepadSelected())
+		{
+#endif
+			DeleteTitleScreen();
+			SelectUser();
+#ifndef AUTOTEST
+		}
+		else
+		{
+	#ifdef PLATFORM_CONSOLE
+		#ifndef PLATFORM_WINDOWS
+			#ifdef PLATFORM_PS4
+			if (GetUserManager().GetSelectedUser())
+			{
+				int gamepad = GetInput().GetUserGamepad(GetUserManager().GetSelectedUser());
+				if (gamepad > -1)
+				{
+					SelectUser(gamepad);
+				}
+				else
+				{
+					if (!m_IntroMenu && !(GetGame().GetUIManager().GetMenu() && GetGame().GetUIManager().GetMenu().GetID() == MENU_TITLE_SCREEN))
+						CreateTitleScreen();
+					GetGame().GetInput().IdentifyGamepad(GetGame().GetInput().GetEnterButton());
+				}
+			}
+			else
+			#endif
+			{
+				if (!m_IntroMenu && !(GetUIManager().GetMenu() && GetUIManager().GetMenu().GetID() == MENU_TITLE_SCREEN))
+					CreateTitleScreen();
+				GetInput().IdentifyGamepad(GetInput().GetEnterButton());
+			}
+		#endif
+	#endif
+		}
+#endif
+	}
+	
+	void SelectGamepad()
+	{
+		ResetProfileOptions();
+		BiosUserManager user_manager = GetUserManager();
+		
+		if (user_manager)
+		{
+			BiosUser selected_user = user_manager.GetSelectedUser();
+			if (selected_user)
+			{
+				OnlineServices.SetBiosUser(selected_user);
+				SetPlayerName(selected_user.GetName());
+				SetUserFOV(GetUserFOVFromConfig());
+				#ifdef PLATFORM_CONSOLE
+				SetPlayerGameName(selected_user.GetName());
+				user_manager.GetUserDatabaseIdAsync();
+				#endif
+			}
+			
+			if (GetUIManager().GetMenu())
+			{
+				GetUIManager().GetMenu().Refresh();
+			}
+		}
+		
+		switch (GetLoadState())
+		{
+			case DayZLoadState.JOIN_USER_SELECT:
+			{
+				SetLoadState(DayZLoadState.JOIN_CONTROLLER_SELECT);
+				OnlineServices.LoadMPPrivilege();
+				break;
+			}
+			case DayZLoadState.PARTY_USER_SELECT:
+			{
+				SetLoadState(DayZLoadState.PARTY_CONTROLLER_SELECT);
+				DeleteTitleScreen();
+				GetUIManager().EnterScriptedMenu(MENU_SERVER_BROWSER, GetUIManager().GetMenu());
+				break;
+			}
+			case DayZLoadState.CONNECT_USER_SELECT:
+			{
+				SetLoadState(DayZLoadState.CONNECT_CONTROLLER_SELECT);
+				OnlineServices.LoadMPPrivilege();
+				break;
+			}
+			case DayZLoadState.MAIN_MENU_USER_SELECT:
+			{
+				SetLoadState(DayZLoadState.MAIN_MENU_CONTROLLER_SELECT);
+				DeleteTitleScreen();
+				GetUIManager().EnterScriptedMenu(MENU_MAIN, GetUIManager().GetMenu());
+				break;
+			}
+			case DayZLoadState.MISSION_USER_SELECT:
+			{
+				SetLoadState(DayZLoadState.MISSION_CONTROLLER_SELECT);
+				DeleteTitleScreen();
+				string mission;
+				GetCLIParam("mission", mission);
+				PlayMission(mission);
+				break;
+			}
+		}
+	}
+	
+	void TryConnect()
+	{
+		if (GetLoadState() == DayZLoadState.JOIN_CONTROLLER_SELECT)
+		{
+			SetGameState(DayZGameState.CONNECTING);
+			OnlineServices.GetSession();
+		}
+		else
+		{
+			if (GetGameState() != DayZGameState.CONNECTING)
+			{
+				switch (GetLoadState())
+				{
+					case DayZLoadState.CONNECT_CONTROLLER_SELECT:
+					{
+						SetGameState(DayZGameState.CONNECTING);
+						ConnectFromCLI();
+						break;
+					}
+					case DayZLoadState.PARTY_CONTROLLER_SELECT:
+					{
+						SetGameState(DayZGameState.CONNECTING);
+						Connect();
+						break;
+					}
+					case DayZLoadState.MAIN_MENU_CONTROLLER_SELECT:
+					{
+						SetGameState(DayZGameState.CONNECTING);
+						Connect();
+						break;
+					}
+				}
+			}
+			else
+			{
+				string address;
+				int port;
+				if (GetHostAddress(address, port))
+				{
+					if (m_ConnectAddress == address && m_ConnectPort == port)
+						ErrorModuleHandler.ThrowError(ErrorCategory.ConnectErrorScript, EConnectErrorScript.ALREADY_CONNECTING_THIS);
+					else
+						ErrorModuleHandler.ThrowError(ErrorCategory.ConnectErrorScript, EConnectErrorScript.ALREADY_CONNECTING, string.Format("%1:%2", address, port));
+				}
+				else	
+				{
+					DisconnectSessionForce();
+					DisconnectSessionScript();
+					TryConnect();
+				}
+			}
+		}
+	}
+	
+	bool GetLastVisitedServer(out string ip, out int port)
+	{
+		if (m_Visited)
+		{
+			if (m_Visited.Count() > 0)
+			{
+				string uid = m_Visited.Get(m_Visited.Count() - 1);
+				TStringArray output = new TStringArray;
+				uid.Split(":", output);
+				ip = output[0];
+				port = output[1].ToInt();
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	void AddVisitedServer(string ip, int port)
+	{
+		string uid = ip + ":" + port;
+		if (m_Visited)
+		{
+			int pos = m_Visited.Find(uid);
+			 
+			if (pos < 0)
+			{
+				if (m_Visited.Count() == MAX_VISITED)
+					m_Visited.Remove(0);
+				m_Visited.Insert(uid);
+			}
+			else
+			{
+				// if item is not saved as last server, move it
+				if (pos != (m_Visited.Count() - 1))
+				{
+					m_Visited.Remove(pos);
+					m_Visited.Insert(uid);
+				}
+			}
+			SetProfileStringList("SB_Visited", m_Visited);
+			SaveProfile();
+		}
+	}
+	
+	bool IsVisited(string ip, int port)
+	{
+		string uid = ip + ":" + port;
+		int index = m_Visited.Find(uid);
+		return (index >= 0);
+	}
+	
+	void RefreshCurrentServerInfo()
+	{
+		string addr;
+		int port;
+		if (GetHostAddress(addr, port))
+		{
+			m_ConnectAddress = addr;
+			m_ConnectPort = port;
+		}
+		OnlineServices.GetCurrentServerInfo(m_ConnectAddress, m_ConnectPort);
+	}
+
+	void Connect()
+	{
+		SetConnecting(true);
+		
+		DeleteTitleScreen();
+		string addr;
+		int port;
+		if (GetHostAddress(addr, port))
+		{
+			if (m_ConnectAddress == addr && m_ConnectPort == port)
+				return;
+		}
+		
+		string connectAddress = m_ConnectAddress;
+		
+		if (m_ConnectSteamQueryPort)
+			connectAddress = string.Format("%1:%2:%3", m_ConnectAddress, m_ConnectPort, m_ConnectSteamQueryPort);
+
+		if (Connect(GetUIManager().GetMenu(), connectAddress, m_ConnectPort, m_ConnectPassword) != 0)
+			DisconnectSessionScript(true);
+	}
+	
+	void DisconnectSessionScript(bool displayJoinError = false)
+	{
+		DisconnectSessionFlags flags = DisconnectSessionFlags.SELECT_USER | DisconnectSessionFlags.IGNORE_WHEN_IN_GAME;
+		if (displayJoinError)
+		{
+			flags |= DisconnectSessionFlags.JOIN_ERROR_ENABLED;
+			flags |= DisconnectSessionFlags.JOIN_ERROR_CHECK;
+		}
+		
+		DisconnectSessionEx(flags);
+	}
+	
+	void DisconnectSessionEx(DisconnectSessionFlags flags)
+	{
+		if (flags & DisconnectSessionFlags.SELECT_USER && OnlineServices.GetBiosUser())
+		{
+			GetGame().GetUserManager().SelectUserEx(OnlineServices.GetBiosUser());
+		}
+		
+		if (flags & DisconnectSessionFlags.JOIN_ERROR_ENABLED)
+		{
+			if (!(flags & DisconnectSessionFlags.JOIN_ERROR_CHECK) || GetGameState() == DayZGameState.JOIN)
+			{
+				NotificationSystem.AddNotification(NotificationType.JOIN_FAIL_GET_SESSION, NotificationSystem.DEFAULT_TIME_DISPLAYED);
+			}
+		}
+		
+		if (flags & DisconnectSessionFlags.IGNORE_WHEN_IN_GAME && GetGameState() == DayZGameState.IN_GAME)
+		{
+			return;
+		}
+		
+		if (flags & DisconnectSessionFlags.CLOSE_MENUS && GetGame().GetUIManager())
+		{
+			GetGame().GetUIManager().CloseAllSubmenus();
+			
+			if ( GetGame().GetUIManager().IsDialogVisible() )
+			{
+				GetGame().GetUIManager().CloseDialog();
+			}
+		}
+			
+		if (flags & DisconnectSessionFlags.ALWAYS_FORCE)
+		{
+			DisconnectSessionForce();
+		}
+		
+		if (GetGame().GetMission())
+		{
+			if (g_Game.GetGameState() != DayZGameState.MAIN_MENU)
+			{	
+				if (flags & DisconnectSessionFlags.DISCONNECT_ERROR_ENABLED)
+				{
+					NotificationSystem.AddNotification(NotificationType.DISCONNECTED, NotificationSystem.DEFAULT_TIME_DISPLAYED);
+				}
+				
+				GetGame().GetMission().AbortMission();
+
+				SetGameState(DayZGameState.MAIN_MENU);
+				SetLoadState(DayZLoadState.MAIN_MENU_CONTROLLER_SELECT);
+				
+				GamepadCheck();
+			}
+		}
+		
+		else
+		{
+			MainMenuLaunch();
+		}
+	}
+	
+	void ConnectFromServerBrowser(string ip, int port, string password = "")
+	{
+		m_ConnectAddress	= ip;
+		m_ConnectPort		= port;
+		m_ConnectPassword	= password;
+		m_ConnectFromJoin	= false;
+		OnlineServices.LoadMPPrivilege();
+	}
+	
+	void ConnectFromServerBrowserEx(string ip, int port, int steamQueryPort, string password = "")
+	{
+		m_ConnectSteamQueryPort = steamQueryPort;
+		ConnectFromServerBrowser(ip, port, password);
+	}
+	
+	void ConnectFromJoin(string ip, int port)
+	{
+		m_ConnectAddress	= ip;
+		m_ConnectPort		= port;
+		m_ConnectFromJoin	= true;
+		Connect();
+	}
+	
+	void ConnectFromCLI()
+	{
+		string port;
+		if (GetCLIParam("connect", m_ConnectAddress))
+		{
+			GetCLIParam("port", port);
+			m_ConnectPort = port.ToInt();
+			
+			GetCLIParam("password", m_ConnectPassword);
+			
+			m_ConnectFromJoin = false;
+			Connect();
+		}
+	}
+	
+	bool IsLeftCtrlDown()
+	{
+		return m_IsCtrlHolding;
+	}
+	
+	// ------------------------------------------------------------
+	override void OnKeyPress(int key)
+	{
+	
+		if (key == KeyCode.KC_LCONTROL) 
+		{
+			m_IsCtrlHolding = true;
+		}
+
+		if (key == KeyCode.KC_LMENU)
+		{
+			m_IsLeftAltHolding = true;
+		}
+			
+		if (key == KeyCode.KC_RMENU)
+		{
+			m_IsRightAltHolding = true;
+		}
+	
+		if (m_keyboard_handler)
+		{
+			m_keyboard_handler.OnKeyDown(NULL, 0, 0, key);
+		}
+		
+		Mission mission = GetMission();
+		if (mission)
+		{
+			mission.OnKeyPress(key);
+		}
+	
+#ifdef DEVELOPER
+		if ((m_IsLeftAltHolding || m_IsLeftAltHolding) && key == KeyCode.KC_F4)
+		{
+			RequestExit(0);
+		}
+#endif
+		
+	}
+	
+	// ------------------------------------------------------------
+	override void OnKeyRelease(int key)
+	{
+		if (key == KeyCode.KC_LCONTROL) 
+		{
+			m_IsCtrlHolding = false;
+		}
+		
+		if (key == KeyCode.KC_LWIN) 
+		{
+			m_IsWinHolding = false;
+		}
+
+		if (key == KeyCode.KC_LMENU || key == KeyCode.KC_RMENU)
+		{
+			m_IsLeftAltHolding = false;
+		}
+
+		if (key == KeyCode.KC_RMENU)
+		{
+			m_IsRightAltHolding  = false;
+		}
+
+		if (m_keyboard_handler)
+		{
+			m_keyboard_handler.OnKeyUp(NULL, 0, 0, key);
+		}
+	
+		Mission mission = GetMission();
+		if (mission)
+		{
+			mission.OnKeyRelease(key);
+		}
+	}
+	
+	// ------------------------------------------------------------	
+	override void OnMouseButtonPress(int button)
+	{
+		Mission mission = GetMission();
+		if (mission)
+		{
+			mission.OnMouseButtonPress(button);
+		}
+	}
+	
+	// ------------------------------------------------------------
+	override void OnMouseButtonRelease(int button)
+	{
+		Mission mission = GetMission();
+		if (mission)
+		{
+			mission.OnMouseButtonRelease(button);
+		}
+	}
+	
+	// ------------------------------------------------------------
+	override void OnDeviceReset()
+	{
+		m_IsCtrlHolding = false;
+		m_IsWinHolding = false;
+		m_IsLeftAltHolding = false;
+		m_IsRightAltHolding  = false;
+	}
+
+	// ------------------------------------------------------------
+	float GetDeltaT()
+	{
+		return m_DeltaTime;
+	}
+	
+	// ------------------------------------------------------------
+	override void OnUpdate(bool doSim, float timeslice)
+	{
+		m_DeltaTime = timeslice;
+
+		Mission mission = GetMission();
+		bool gameIsRunning = false;
+	
+		if (doSim && mission && !mission.IsPaused())
+		{
+			gameIsRunning = true;
+		}
+	
+		if (doSim && mission)
+		{
+			mission.OnUpdate(timeslice);
+			
+			// update local weather effects
+			if ( IsClient() || !IsMultiplayer() )
+			{
+				WorldData worldData = mission.GetWorldData();
+				if ( worldData )
+					worldData.UpdateWeatherEffects( GetWeather(), timeslice );
+			}
+		}
+		
+		SEffectManager.OnUpdate(timeslice);
+	
+		// queues and timers update
+		GetCallQueue(CALL_CATEGORY_SYSTEM).Tick(timeslice);
+		GetUpdateQueue(CALL_CATEGORY_SYSTEM).Invoke(timeslice);
+		GetTimerQueue(CALL_CATEGORY_SYSTEM).Tick(timeslice);
+	
+	#ifndef NO_GUI	
+		if (m_IsConnecting)
+			UpdateLoginQueue(timeslice);
+		
+		if (m_loading && m_loading.IsLoading())
+		{
+			m_loading.OnUpdate(timeslice);
+		}
+		else if (m_LoginTimeScreen && m_LoginTimeScreen.IsStatic())
+		{
+			m_LoginTimeScreen.Update(timeslice);
+		}
+		else
+		{
+			GetCallQueue(CALL_CATEGORY_GUI).Tick(timeslice);
+			GetUpdateQueue(CALL_CATEGORY_GUI).Invoke(timeslice);
+			GetTimerQueue(CALL_CATEGORY_GUI).Tick(timeslice);
+			GetDragQueue().Tick();
+		}
+		
+		NotificationSystem.Update(timeslice);
+		if (m_Notifications)
+		{
+			m_Notifications.Update(timeslice);
+		}
+		
+		#ifndef SERVER
+		#ifdef DIAG_DEVELOPER
+		if (GetGame().IsMultiplayer() && GetPlayer() && DiagMenu.GetBool(DiagMenuIDs.MISC_CONNECTION_STATS))
+		{
+			PlayerIdentity playerIdentity = GetPlayer().GetIdentity();
+			
+			if (playerIdentity)
+			{
+				int pingAct = playerIdentity.GetPingAct();
+				int pingAvg = playerIdentity.GetPingAvg();
+
+				float throttleInput = playerIdentity.GetInputThrottle();
+				float throttleOutput = playerIdentity.GetOutputThrottle();
+				
+				DrawPerformanceStats(pingAct, pingAvg, throttleInput, throttleOutput);
+			}
+		}
+		#endif
+		#endif
+		
+	#endif
+	
+		if (gameIsRunning)
+		{
+			GetCallQueue(CALL_CATEGORY_GAMEPLAY).Tick(timeslice);
+			GetUpdateQueue(CALL_CATEGORY_GAMEPLAY).Invoke(timeslice);
+			GetTimerQueue(CALL_CATEGORY_GAMEPLAY).Tick(timeslice);
+		}
+	}
+	
+	// ------------------------------------------------------------
+	override void OnPostUpdate(bool doSim, float timeslice)
+	{
+		Mission mission = GetMission();
+		bool gameIsRunning = false;
+	
+		if (doSim && mission && !mission.IsPaused())
+		{
+			gameIsRunning = true;
+		}
+		
+		GetPostUpdateQueue(CALL_CATEGORY_SYSTEM).Invoke(timeslice);
+	
+	#ifndef NO_GUI	
+		if (m_loading && m_loading.IsLoading())
+		{
+		}
+		else if (m_LoginTimeScreen && m_LoginTimeScreen.IsStatic())
+		{
+		}
+		else
+		{
+			GetPostUpdateQueue(CALL_CATEGORY_GUI).Invoke(timeslice);
+		}
+	#endif
+	
+		if (gameIsRunning)
+		{
+			GetPostUpdateQueue(CALL_CATEGORY_GAMEPLAY).Invoke(timeslice);
+		}
+	}
+	
+	// ------------------------------------------------------------
+	override void OnRPC(PlayerIdentity sender, Object target, int rpc_type, ParamsReadContext ctx)
+	{
+		super.OnRPC(sender, target, rpc_type, ctx);
+		Event_OnRPC.Invoke(sender, target, rpc_type, ctx);
+		
+		//Print("["+ GetGame().GetTime().ToString() +"] => DayZGame::OnRPC = "+ EnumTools.EnumToString(ERPCs,rpc_type));
+		
+		if (target)
+		{
+			// call rpc on target
+			target.OnRPC(sender, rpc_type, ctx);
+		}
+		else
+		{
+			switch (rpc_type)
+			{
+				#ifndef SERVER
+				#ifndef NO_GUI
+				case ERPCs.RPC_CFG_GAMEPLAY_SYNC:
+				{
+					CfgGameplayHandler.OnRPC(null, ctx);
+					break;
+				}
+				case ERPCs.RPC_UNDERGROUND_SYNC:
+				{
+					UndergroundAreaLoader.OnRPC(ctx);
+					break;
+				}
+				case ERPCs.RPC_PLAYERRESTRICTEDAREAS_SYNC:
+				{
+					CfgPlayerRestrictedAreaHandler.OnRPC(ctx);
+					break;
+				}
+				case ERPCs.RPC_SEND_NOTIFICATION:
+				{
+					NotificationType type;
+					float show_time;
+					string detail_text;
+					
+					ctx.Read(type);
+					ctx.Read(show_time);
+					ctx.Read(detail_text);
+					
+					NotificationSystem.AddNotification(type, show_time, detail_text);
+					break;
+				}
+				case ERPCs.RPC_SEND_NOTIFICATION_EXTENDED:
+				{
+					float show_time_ext;
+					string title_text_ext;
+					string detail_text_ext;
+					string icon_ext;
+					
+					ctx.Read(show_time_ext);
+					ctx.Read(title_text_ext);
+					ctx.Read(detail_text_ext);
+					ctx.Read(icon_ext);
+					
+					NotificationSystem.AddNotificationExtended(show_time_ext, title_text_ext, detail_text_ext, icon_ext);
+					break;
+				}
+				
+				
+				case ERPCs.RPC_SOUND_HELICRASH:
+				{
+					bool playSound;
+					vector pos;
+					string sound_set;
+					
+					//Helicrash is a world event, we want anyone to be able to hear it
+					Param3<bool, vector, int> playCrashSound = new Param3<bool, vector, int>(false, "0 0 0",0);
+					if (ctx.Read(playCrashSound))
+					{
+						playSound = playCrashSound.param1;
+						pos = playCrashSound.param2;
+						sound_set = CrashSoundSets.GetSoundSetByHash(playCrashSound.param3);
+					}
+					
+					if (playSound)
+					{
+						m_CrashSound = SEffectManager.PlaySound(sound_set, pos, 0.1, 0.1);
+						m_CrashSound.SetAutodestroy(true);
+					}
+				
+				break;
+				}
+				//Random off map artillery barrage
+				case ERPCs.RPC_SOUND_ARTILLERY:
+				{
+					vector position;
+					Param1<vector> playArtySound = new Param1<vector>(vector.Zero);
+					if (ctx.Read(playArtySound))
+					{
+						position = playArtySound.param1;
+						if (position == vector.Zero)
+							break;
+					}
+					else
+						break;
+					
+					if (!GetGame().GetPlayer())
+						break;
+					
+					if (vector.DistanceSq(GetGame().GetPlayer().GetPosition(), position) <= (MIN_ARTY_SOUND_RANGE * MIN_ARTY_SOUND_RANGE))
+						break;
+					
+					m_ArtySound = SEffectManager.PlaySound("Artillery_Distant_Barrage_SoundSet", position, 0.1, 0.1);
+					m_ArtySound.SetAutodestroy(true);
+				
+				break;
+				}
+				case ERPCs.RPC_SOUND_CONTAMINATION:
+				{
+					vector soundPos;
+					
+					Param1<vector> playContaminatedSound = new Param1<vector>(vector.Zero);
+					if (ctx.Read(playContaminatedSound))
+					{
+						soundPos = playContaminatedSound.param1;
+						if (soundPos == vector.Zero)
+							break;
+					}
+					else
+						break;
+					
+					if (!GetGame().GetPlayer())
+						break;
+					
+					EffectSound closeArtySound = SEffectManager.PlaySound("Artillery_Close_SoundSet", soundPos);
+					closeArtySound.SetAutodestroy(true);
+					
+					// We add camera shake upon shell detonation
+					float distance_to_player = vector.DistanceSq(soundPos, GetGame().GetPlayer().GetPosition());
+					if (distance_to_player <= GameConstants.CAMERA_SHAKE_ARTILLERY_DISTANCE2)
+					{
+						float strength_factor = Math.InverseLerp(GameConstants.CAMERA_SHAKE_ARTILLERY_DISTANCE, 0, Math.Sqrt(distance_to_player));
+						DayZPlayerCamera camera = GetGame().GetPlayer().GetCurrentCamera();
+						if (camera)
+							camera.SpawnCameraShake(strength_factor * 4);
+					}
+					
+					ParticleManager.GetInstance().PlayInWorld(ParticleList.CONTAMINATED_AREA_GAS_SHELL, soundPos);
+					break;
+				}
+				// Single artillery shot to announce dynamic contaminated area
+				case ERPCs.RPC_SOUND_ARTILLERY_SINGLE:
+				{
+					vector soundPosition;
+					vector delayedSoundPos;
+					float soundDelay;
+					
+					Param3<vector, vector, float> playArtyShotSound = new Param3<vector, vector, float>(vector.Zero, vector.Zero, 0);
+					if (ctx.Read(playArtyShotSound))
+					{
+						soundPosition = playArtyShotSound.param1;
+						delayedSoundPos = playArtyShotSound.param2;
+						soundDelay = playArtyShotSound.param3;
+						if (soundPosition == vector.Zero)
+							break;
+					}
+					else
+						break;
+					
+					if (!GetGame().GetPlayer())
+						break;
+					
+					m_ArtySound = SEffectManager.PlaySound("Artillery_Distant_SoundSet", soundPosition, 0.1, 0.1);
+					m_ArtySound.SetAutodestroy(true);
+					
+					// We remove the amount of time the incoming sound lasts
+					soundDelay -= 5;
+					// We convert to milliseconds
+					soundDelay *= 1000;
+					GetCallQueue(CALL_CATEGORY_GAMEPLAY).CallLater(DelayedMidAirDetonation, soundDelay, false, delayedSoundPos[0], delayedSoundPos[1], delayedSoundPos[2]);
+					break;
+				}
+				case ERPCs.RPC_SET_BILLBOARDS:
+				{
+					if (!m_BillboardSetHandler)
+						m_BillboardSetHandler = new BillboardSetHandler();
+					
+					Param1<int> indexP = new Param1<int>(-1);
+					if (ctx.Read(indexP))
+					{
+						int index = indexP.param1;
+						m_BillboardSetHandler.OnRPCIndex(index);
+					}
+					break;
+				}
+				#endif
+				#endif
+
+				case ERPCs.RPC_USER_SYNC_PERMISSIONS:
+				{
+					map<string, bool> mute_list;
+					if (ctx.Read(mute_list))
+					{
+						for (int i = 0; i < mute_list.Count(); i++)
+						{
+							string uid = mute_list.GetKey(i);
+							bool mute = mute_list.GetElement(i);
+							MutePlayer(uid, sender.GetPlainId(), mute);
+						}
+					}
+					break;
+				}
+				
+				/*
+				case ERPCs.RPC_SERVER_RESPAWN_MODE:
+				{
+					int mode;
+					if (ctx.Read(mode) && !IsServer())
+					{
+						GetMission().SetRespawnModeClient(mode);
+					}
+				}
+				*/
+
+				#ifdef DEVELOPER
+				case ERPCs.DEV_SET_WEATHER:
+				{
+					Param1<DebugWeatherRPCData> p1data = new Param1<DebugWeatherRPCData>(null);
+					
+					if ( ctx.Read(p1data) )
+					{
+						DebugWeatherRPCData data = p1data.param1;
+						
+						if (data.m_FogValue >= 0)
+							GetGame().GetWeather().GetFog().Set(data.m_FogValue, data.m_FogInterpolation, data.m_FogDuration);
+						
+						if (data.m_OvercastValue >= 0)
+							GetGame().GetWeather().GetOvercast().Set(data.m_OvercastValue, data.m_OvercastInterpolation, data.m_OvercastDuration);
+						
+						if (data.m_RainValue >= 0)
+							GetGame().GetWeather().GetRain().Set(data.m_RainValue, data.m_RainInterpolation, data.m_RainDuration);
+						
+						if (data.m_SnowfallValue >= 0)
+							GetGame().GetWeather().GetSnowfall().Set(data.m_SnowfallValue, data.m_SnowfallInterpolation, data.m_SnowfallDuration);
+					}
+					else
+					{
+						ErrorEx("Failed to read weather debug data");
+					}
+					break;
+				}
+				#endif
+				
+				
+				#ifdef DIAG_DEVELOPER
+				#ifdef SERVER
+				case ERPCs.DIAG_CAMERATOOLS_CAM_DATA:
+				{
+					if (!m_CameraToolsMenuServer)
+					{
+						m_CameraToolsMenuServer = new CameraToolsMenuServer;
+					}
+					m_CameraToolsMenuServer.OnRPC(rpc_type, ctx);
+					break;
+				}
+				
+				case ERPCs.DIAG_CAMERATOOLS_CAM_SUBSCRIBE:
+				{
+					if (!m_CameraToolsMenuServer)
+					{
+						m_CameraToolsMenuServer = new CameraToolsMenuServer;
+					}
+					m_CameraToolsMenuServer.OnRPC(rpc_type, ctx);
+					break;
+				}
+
+				#endif
+				#endif
+
+			}
+			// global rpc's handling
+		}
+	}
+	
+	void DelayedMidAirDetonation(float x, float y, float z)
+	{
+		EffectSound artilleryFallSound = SEffectManager.PlaySound("Artillery_Fall_SoundSet", Vector(x, y, z));
+		artilleryFallSound.SetAutodestroy(true);
+	}
+	
+	// ------------------------------------------------------------
+	void CheckDialogs()
+	{
+		#ifndef NO_GUI	
+		Mission mission = GetMission();
+		if (mission && !m_loading.IsLoading() && GetUIManager().IsDialogQueued())
+		{
+			mission.Pause();
+			GetUIManager().ShowQueuedDialog();
+		}
+		#endif
+	}
+	
+	//! Returns true when connecting to server
+	void SetConnecting(bool value)
+	{
+		m_IsConnecting = value;
+	}
+	
+	bool IsConnecting()
+	{
+		return m_IsConnecting;
+	}
+	
+	// ------------------------------------------------------------
+	bool IsLoading()
+	{
+		return m_loading && m_loading.IsLoading();
+	}
+	
+	// ------------------------------------------------------------
+	void SetKeyboardHandle(UIScriptedMenu handler)
+	{
+		m_keyboard_handler = handler;
+	}
+	
+	// ------------------------------------------------------------
+	void LoadingShow()
+	{
+		#ifndef NO_GUI	
+		m_loading.ShowEx(this);
+		#endif
+	}
+	
+	// ------------------------------------------------------------
+	void LoadingHide(bool force = false)
+	{
+		#ifndef NO_GUI
+			m_loading.Hide(force);
+			// turn the lights back on
+			PPEManagerStatic.GetPPEManager().StopAllEffects();
+			#ifdef PLATFORM_CONSOLE
+			if (!IsLoading())
+			{
+				if (m_LoadState != DayZLoadState.MAIN_MENU_START && m_LoadState != DayZLoadState.MAIN_MENU_USER_SELECT)
+				{
+					UpdateInputDeviceDisconnectWarning();
+				}
+			}
+			#endif
+		#endif
+	}
+
+	// ------------------------------------------------------------
+	override string CreateDefaultPlayer()
+	{				
+		if (m_CharClassNames.Count() > 0)
+			return m_CharClassNames[0];
+
+		return "";
+	}
+	
+	// ------------------------------------------------------------
+	override string CreateRandomPlayer()
+	{
+		return m_CharClassNames.GetRandomElement();
+	}
+	
+	// ------------------------------------------------------------
+	override TStringArray ListAvailableCharacters()
+	{
+		return m_CharClassNames;
+	}
+	
+	// ------------------------------------------------------------
+	void ExplosionEffectsEx(Object source, Object directHit, int componentIndex, float energyFactor, float explosionFactor, HitInfo hitInfo)
+	{
+		vector pos = hitInfo.GetPosition();
+		string ammoType = hitInfo.GetAmmoType();
+		
+		// Call legacy method
+		ExplosionEffects(source, directHit, componentIndex, hitInfo.GetSurface(), pos, hitInfo.GetSurfaceNormal(), energyFactor, explosionFactor, hitInfo.IsWater(), ammoType);
+		
+		// add explosion noise
+		if (IsServer())
+		{
+			//NoiseParams npar = new NoiseParams();
+			m_NoiseParams.LoadFromPath(string.Format("cfgAmmo %1 NoiseExplosion", ammoType));
+			
+			float multiplier = hitInfo.GetSurfaceNoiseMultiplier();
+			if (multiplier == 0)
+				multiplier = 1;
+			
+			GetNoiseSystem().AddNoiseTarget(pos, 21, m_NoiseParams, multiplier * GetGame().GetWeather().GetNoiseReductionByWeather());
+		}
+	}
+	
+	// ------------------------------------------------------------
+	void ExplosionEffects(Object source, Object directHit, int componentIndex, string surface, vector pos, vector surfNormal,
+		float energyFactor, float explosionFactor, bool isWater, string ammoType)
+	{
+		#ifndef SERVER
+		if (source)
+		{
+			source.OnExplosionEffects(source, directHit, componentIndex, surface, pos, surfNormal, energyFactor, explosionFactor, isWater, ammoType);
+			
+			if (source.ShootsExplosiveAmmo() && ammoType == "Explosion_40mm_Ammo")
+				ParticleManager.GetInstance().PlayInWorld(ParticleList.EXPLOSION_LANDMINE, pos);
+			
+			float distance_to_player = vector.Distance(pos, GetGame().GetPlayer().GetPosition());
+			m_AmmoShakeParams.Load(ammoType);
+			
+			if (distance_to_player < m_AmmoShakeParams.m_Radius)
+			{
+				float dist01 = Math.InverseLerp(0, m_AmmoShakeParams.m_Radius, distance_to_player);
+				float modifier = Math.Lerp(m_AmmoShakeParams.m_ModifierClose, m_AmmoShakeParams.m_ModifierFar,dist01);
+				
+				GetGame().GetPlayer().GetCurrentCamera().SpawnCameraShake(modifier * m_AmmoShakeParams.m_Strength);
+			}
+		}
+		#endif
+	}
+	
+	// ------------------------------------------------------------
+	void OnProjectileStopped(ProjectileStoppedInfo info)
+	{
+		string simulation;
+		
+		GetGame().ConfigGetText("cfgAmmo " + info.GetAmmoType() + " simulation", simulation);	
+
+		if (simulation == "shotArrow")
+		{
+			string pile;
+			
+			GetGame().ConfigGetText("cfgAmmo " + info.GetAmmoType() + " spawnPileType", pile);
+			
+			EntityAI arrow = EntityAI.Cast(GetGame().CreateObjectEx(pile, info.GetPos(), ECE_DYNAMIC_PERSISTENCY));
+			arrow.PlaceOnSurface();	
+			arrow.SetFromProjectile(info);
+		}
+	}
+	
+	const float ARROW_PIERCE_DEPTH = 0.05;
+	
+	// ------------------------------------------------------------
+	void OnProjectileStoppedInTerrain(TerrainCollisionInfo info)
+	{
+		string simulation;
+		
+		if (info.GetIsWater())
+			return;
+		
+		GetGame().ConfigGetText("cfgAmmo " + info.GetAmmoType() + " simulation", simulation);
+		if (simulation == "shotArrow")
+		{
+			string pile;
+			GetGame().ConfigGetText("cfgAmmo " + info.GetAmmoType() + " spawnPileType", pile);
+			vector pos = info.GetPos();
+			vector dir = -info.GetInVelocity();
+			
+			dir.Normalize();
+			pos -= dir * ARROW_PIERCE_DEPTH;
+			
+			EntityAI arrow = EntityAI.Cast(GetGame().CreateObjectEx(pile, pos, ECE_KEEPHEIGHT|ECE_DYNAMIC_PERSISTENCY));
+			arrow.SetDirection(dir);
+			arrow.SetFromProjectile(info);
+		}
+	}
+	
+	// ------------------------------------------------------------
+	void OnProjectileStoppedInObject(ObjectCollisionInfo info)
+	{
+		string simulation;
+		
+		GetGame().ConfigGetText("cfgAmmo " + info.GetAmmoType() + " simulation", simulation);	
+		if (simulation == "shotArrow")
+		{
+			string pile;
+			GetGame().ConfigGetText("cfgAmmo " + info.GetAmmoType() + " spawnPileType", pile);
+			
+			EntityAI arrow = null;
+			EntityAI ent = EntityAI.Cast(info.GetHitObj());
+			if (ent)
+			{
+				EntityAI parent = ent.GetHierarchyParent();
+				if (parent && parent.IsPlayer())
+				{
+					arrow = EntityAI.Cast(GetGame().CreateObjectEx(pile, parent.GetPosition(), ECE_DYNAMIC_PERSISTENCY));
+					arrow.PlaceOnSurface();	
+					arrow.SetFromProjectile(info);
+	
+					return;
+				}
+			}
+			
+			vector pos = info.GetPos();
+			vector dir = -info.GetInVelocity();
+			
+			dir.Normalize();
+			pos -= dir * ARROW_PIERCE_DEPTH;
+			
+			arrow = EntityAI.Cast(GetGame().CreateObjectEx(pile, pos, ECE_KEEPHEIGHT|ECE_DYNAMIC_PERSISTENCY));
+			arrow.SetDirection(dir);
+			arrow.SetFromProjectile(info);
+			
+			info.GetHitObj().AddArrow(arrow, info.GetComponentIndex(), info.GetHitObjPos(), info.GetHitObjRot());
+		}
+	}
+	
+	// ------------------------------------------------------------
+	void FirearmEffects(Object source, Object directHit, int componentIndex, string surface, vector pos, vector surfNormal,
+		 vector exitPos, vector inSpeed, vector outSpeed, bool isWater, bool deflected, string ammoType) 
+	{
+		#ifndef SERVER
+		ImpactEffectsData impactEffectsData = new ImpactEffectsData();
+		impactEffectsData.m_DirectHit 		= directHit;
+		impactEffectsData.m_ComponentIndex 	= componentIndex;
+		impactEffectsData.m_Surface 		= surface;
+		impactEffectsData.m_Position		= pos;
+		impactEffectsData.m_ImpactType		= ImpactTypes.UNKNOWN;
+		impactEffectsData.m_SurfaceNormal	= surfNormal;
+		impactEffectsData.m_ExitPosition	= exitPos;
+		impactEffectsData.m_InSpeed			= inSpeed;
+		impactEffectsData.m_OutSpeed		= outSpeed;
+		impactEffectsData.m_IsDeflected		= deflected;
+		impactEffectsData.m_AmmoType		= ammoType;
+		impactEffectsData.m_IsWater			= isWater;
+
+		if (directHit)
+		{
+			directHit.OnReceivedHit(impactEffectsData);
+		}
+
+		ImpactMaterials.EvaluateImpactEffectEx(impactEffectsData);
+		#endif
+		
+		
+		if (IsServer())
+		{
+			if (source && source.ShootsExplosiveAmmo() && !deflected && outSpeed == vector.Zero)
+			{
+				if (ammoType == "Bullet_40mm_ChemGas")
+				{
+					GetGame().CreateObject("ContaminatedArea_Local", pos);
+				}
+				else if (ammoType == "Bullet_40mm_Explosive")
+				{
+					DamageSystem.ExplosionDamage(EntityAI.Cast(source), null, "Explosion_40mm_Ammo", pos, DamageType.EXPLOSION);
+				}
+			}
+			
+			// add hit noise
+			m_NoiseParams.LoadFromPath("cfgAmmo " + ammoType + " NoiseHit");
+			
+			float surfaceCoef = SurfaceGetNoiseMultiplier(directHit, pos, componentIndex);
+			float coefAdjusted = surfaceCoef * inSpeed.Length() / ConfigGetFloat("cfgAmmo " + ammoType + " initSpeed");
+			if (coefAdjusted == 0)
+				coefAdjusted = 1;
+			
+			GetNoiseSystem().AddNoiseTarget(pos, 10, m_NoiseParams, coefAdjusted * GetGame().GetWeather().GetNoiseReductionByWeather()); // Leave a ping for 5 seconds
+		}
+	}
+	
+	// ------------------------------------------------------------
+	void CloseCombatEffects(Object source, Object directHit, int componentIndex, string surface, vector pos, vector surfNormal,
+		 bool isWater, string ammoType) 
+	{
+		#ifndef SERVER
+		ImpactEffectsData impactEffectsData = new ImpactEffectsData();
+		impactEffectsData.m_DirectHit 		= directHit;
+		impactEffectsData.m_ComponentIndex 	= componentIndex;
+		impactEffectsData.m_Surface 		= surface;
+		impactEffectsData.m_Position		= pos;
+		impactEffectsData.m_ImpactType		= ImpactTypes.MELEE;
+		impactEffectsData.m_SurfaceNormal	= Vector(Math.RandomFloat(-1,1), Math.RandomFloat(-1,1), Math.RandomFloat(-1,1));
+		impactEffectsData.m_ExitPosition	= "0 0 0";
+		impactEffectsData.m_InSpeed			= "0 0 0";
+		impactEffectsData.m_OutSpeed		= "0 0 0";
+		impactEffectsData.m_IsDeflected		= false;
+		impactEffectsData.m_AmmoType		= ammoType;
+		impactEffectsData.m_IsWater			= isWater;
+
+		if (directHit)
+			directHit.OnReceivedHit(impactEffectsData);
+		
+		ImpactMaterials.EvaluateImpactEffectEx(impactEffectsData);
+		#endif
+		
+		// add hit noise
+		if (IsServer())
+		{
+			m_NoiseParams.LoadFromPath("cfgAmmo " + ammoType + " NoiseHit");
+			
+			float surfaceCoef = SurfaceGetNoiseMultiplier(directHit, pos, componentIndex);
+			if (surfaceCoef == 0)
+				surfaceCoef = 1;
+			
+			GetNoiseSystem().AddNoisePos(EntityAI.Cast(source), pos, m_NoiseParams, surfaceCoef * GetGame().GetWeather().GetNoiseReductionByWeather());
+		}
+	}
+	
+	void UpdateVoiceLevel(int level)
+	{
+		GetMission().UpdateVoiceLevelWidgets(level);	
+	}
+	
+	void InitCharacterMenuDataInfo(int menudata_count)
+	{
+		m_OriginalCharactersCount = menudata_count;
+	}
+	
+	void SetPlayerGameName(string name)
+	{
+		m_PlayerName = name;
+	}
+	
+	string GetPlayerGameName()
+	{
+		return m_PlayerName;
+	}
+	
+	void SetNewCharacter(bool state)
+	{
+		m_IsNewCharacter = state;
+	}
+	
+	bool IsNewCharacter()
+	{
+		return m_IsNewCharacter;
+	}
+	
+	void SetUserFOV(float pFov)
+	{
+		if (pFov < OPTIONS_FIELD_OF_VIEW_MIN)
+			pFov = OPTIONS_FIELD_OF_VIEW_MIN;
+
+		if (pFov > OPTIONS_FIELD_OF_VIEW_MAX)
+			pFov = OPTIONS_FIELD_OF_VIEW_MAX;
+		
+		m_UserFOV = pFov;
+	}
+	
+	float GetUserFOV()
+	{
+		return m_UserFOV;
+	}
+	
+	static float GetUserFOVFromConfig()
+	{
+		GameOptions gameOptions = new GameOptions;
+		NumericOptionsAccess noa;
+		if (gameOptions && Class.CastTo(noa,gameOptions.GetOptionByType(OptionAccessType.AT_OPTIONS_FIELD_OF_VIEW)))
+		{
+			return noa.ReadValue();
+		}
+		return 1.0;
+	}
+	
+	float GetFOVByZoomType(ECameraZoomType type)
+	{
+		switch (type)
+		{
+			case ECameraZoomType.NONE:
+				return GetUserFOV();
+			case ECameraZoomType.NORMAL:
+				return Math.Min(GetUserFOV(), GameConstants.DZPLAYER_CAMERA_FOV_EYEZOOM);
+			case ECameraZoomType.SHALLOW:
+				return Math.Min(GetUserFOV(),GameConstants.DZPLAYER_CAMERA_FOV_EYEZOOM_SHALLOW);
+			default:
+				return GetUserFOV();
+		}
+		return GetUserFOV();
+	}
+	
+	void SetHudBrightness(float value)
+	{
+		Widget.SetLV(value);
+		Widget.SetTextLV(value);
+	}
+	
+	float GetHUDBrightnessSetting()
+	{
+		return g_Game.GetProfileOptionFloat(EDayZProfilesOptions.HUD_BRIGHTNESS);
+	}
+	
+	// Check if ammo is compatible with a weapon in hands 
+	static bool CheckAmmoCompability(EntityAI weaponInHand, EntityAI ammo)
+	{	
+		TStringArray ammo_names = new TStringArray;										// Array of ammo types (their name) that can be used with weapon in hand
+		
+		string cfg_path = "CfgWeapons " + weaponInHand.GetType() + " chamberableFrom";	// Create config path 
+		GetGame().ConfigGetTextArray(cfg_path, ammo_names);								// Get ammo types 
+			
+		foreach (string ammo_name : ammo_names)				// for every ammo in ammo string compare passed ammo 
+		{
+			if (ammo.GetType() == ammo_name)					
+			{
+				return true;			
+			}
+		}
+		
+		// if no ammo from the array matches with ammo passed, return false 
+		return false;
+	}
+	
+	void SetEVValue(float value)
+	{
+		m_PreviousEVValue = m_EVValue;
+		SetEVUser(value);
+		m_EVValue = value;
+	}
+	
+	float GetCurrentEVValue()
+	{
+		return m_EVValue;
+	}
+	
+	float GetPreviousEVValue()
+	{
+		return m_PreviousEVValue;
+	}
+	
+	int GetCurrentDisplayLanguageIdx()
+	{
+		ListOptionsAccess	language_option;
+		GameOptions options = new GameOptions();
+		language_option = ListOptionsAccess.Cast(options.GetOptionByType(OptionAccessType.AT_OPTIONS_LANGUAGE));
+		int idx = -1;
+		if (language_option)
+		{
+			idx = language_option.GetIndex();
+		}
+		
+		return idx;
+	}
+	
+	bool IsWorldWetTempUpdateEnabled()
+	{
+		return m_IsWorldWetTempUpdateEnabled;
+	}
+	
+	bool IsFoodDecayEnabled()
+	{
+		return (GetFoodDecayModifier() != 0);
+	}	
+	
+	float GetFoodDecayModifier()
+	{
+		#ifdef DIAG_DEVELOPER
+		
+		if (FeatureTimeAccel.GetFeatureTimeAccelEnabled(ETimeAccelCategories.FOOD_DECAY))
+		{
+			return m_FoodDecayModifier * FeatureTimeAccel.GetFeatureTimeAccelValue();
+		}
+		#endif
+		return m_FoodDecayModifier;
+	}
+	
+	array<int> GetConnectedInputDeviceList()
+	{
+		if (!m_ConnectedInputDeviceList)
+		{
+			m_ConnectedInputDeviceList = new array<int>;
+		}
+		return m_ConnectedInputDeviceList;
+	}
+	
+	void SetMouseCursorDesiredVisibility(bool visible)
+	{
+		m_CursorDesiredVisibilityScript = visible;
+
+		RefreshMouseCursorVisibility();
+	}
+	
+	bool GetMouseCursorDesiredVisibility()
+	{
+		return m_CursorDesiredVisibilityScript;
+	}
+	
+	//! extend as needed, only game focus and M&K setting (consoles only!) are checked natively
+	bool CanDisplayMouseCursor()
+	{
+		//! Only checking on console because while loading on PC, the mouse might not be detected
+#ifdef PLATFORM_CONSOLE
+		if (GetInput())
+		{
+			return GetInput().IsMouseConnected();
+		}
+#endif
+
+		//! Platform defaults
+#ifdef PLATFORM_CONSOLE
+		return false;
+#else
+		return true;
+#endif
+	}
+	
+	void RefreshMouseCursorVisibility()
+	{
+#ifndef NO_GUI
+#ifdef FEATURE_CURSOR
+		if (!IsAppActive())
+		{
+			ShowCursorWidget(true);
+		}
+		else
+#endif
+		{
+			bool showCursor = m_CursorDesiredVisibilityScript && CanDisplayMouseCursor();
+			
+			UIManager ui = GetUIManager();
+			if (ui)
+			{
+				//! Handles app active-ness
+				ui.ShowCursor(showCursor);
+			}
+			else
+			{
+				//! Fallback, just in-case
+				ShowCursorWidget(showCursor);
+			}
+		}
+#endif
+	}
+
+	BillboardSetHandler GetBillboardHandler()
+	{
+		return m_BillboardSetHandler;
+	}
+	
+	///////////////
+	//DEPRECATED//
+	//////////////
+	void CreateGamepadDisconnectMenu();
+	void DeleteGamepadDisconnectMenu();
+};
+
+DayZGame g_Game;
+
+DayZGame GetDayZGame()
+{
+	return g_Game;
+}

+ 1396 - 0
Scripts/3_game/dayzplayer.c

@@ -0,0 +1,1396 @@
+/** @file 
+
+  this file is interface DayZPlayer classes 
+
+*/
+
+
+// *************************************************************************************
+// ! DayZPlayerCameraResult - camera result -
+// *************************************************************************************
+class DayZPlayerCameraResult
+{
+
+	vector		m_CameraTM[4];				//!< transformation matrix - pos + orient of the camera
+	float 		m_fFovMultiplier;			//!< fov multiplier - 1.0 default - used for modifying fov - 
+	float 		m_fFovAbsolute;				//!< fov absolute value override - -1.0 default, if set - overrides absolute fov setting
+	float		m_fNearPlane;				//!< nearplane distance
+	float 		m_fPositionModelSpace;  	//!< 0.0 position is in heading space, 1.0 position is in model space
+	float 		m_fDistance;				//!< camera distance (external cameras only)
+	float 		m_fUseHeading;				//!< 0..1 (0 uses direct dir returned, 1 uses heading from player)
+	float		m_fPredictCollisionRadius;	//!< sphere radius used for collision prediction
+
+	int 		m_iDirectBone;				//!< -1 no bone, >= 0 - bone index camera is bound to, m_CameraTM is offset to the bone 
+	int 		m_iDirectBoneMode;			//! 0 not used, 1 - pos, 2 - rot, 3 - pos+rot applied as a parent to m_CameraTM, 4 as 3 but cam aligned with Y
+	float 		m_fInsideCamera;			//!< 0..1 (0 normal lod, 1 inside lod), >0.7 -> inside
+	bool		m_bUpdateWhenBlendOut;		//!< true - camera is updated when blending to new camera (Ironsights == false)
+	float 		m_fShootFromCamera;			//!< 1(default) - uses shoot from camera (+aiming sway), 0 pure weapon shoot (ironsights == 0)
+	float		m_fIgnoreParentRoll;		//!< 1 - resets base transforms roll
+	float		m_fIgnoreParentPitch;		//!< 1 - resets base transforms pitch
+	float		m_fIgnoreParentYaw;			//!< 1 - resets base transforms yaw
+	bool		m_bUpdateEveryFrame;		//!< Whether the camera updates the next frame or blends with next character update
+	
+	vector		m_OwnerTM[4];				//!< override automatically calculated owner transform during rendering (default - false)
+	bool		m_bOwnerTMOverride;			//!< The world space transform of the owner to the camera
+
+	IEntity		m_CollisionIgnoreEntity;	//!< ignore entity in 3rd person camera collision solver
+
+	//! cannot be instanced from script (always created from C++)
+	private void DayZPlayerCameraResult()
+	{
+	}
+
+	//! cannot be instanced from script (always created from C++)
+	private void ~DayZPlayerCameraResult()
+	{
+	}
+
+}
+
+// *************************************************************************************
+// ! DayZPlayerCamera - main dayz player camera implement 
+// *************************************************************************************
+class DayZPlayerCamera 
+{
+
+	void DayZPlayerCamera(DayZPlayer pPlayer, HumanInputController pInput)
+	{
+		m_pPlayer		= pPlayer;
+		m_pInput 		= pInput;
+	}
+
+	//! this overrides freelook for cameras
+	bool CanFreeLook()
+	{
+		return true;
+	}
+
+	//! virtual callback - called when camera is created
+	void OnActivate(DayZPlayerCamera pPrevCamera, DayZPlayerCameraResult pPrevCameraResult)
+	{
+	}
+
+	//!	virtual callback - called each frame
+	void OnUpdate(float pDt, out DayZPlayerCameraResult pOutResult)
+	{
+	}
+
+	//!	helper to blend between cameras 
+	//! ret[0] - up down angle
+	//! ret[1] - left right angle
+	//! ret[2] - roll angle
+	vector GetBaseAngles()
+	{
+		return "0 0 0";
+	}
+
+	vector GetAdditiveAngles()
+	{
+		return "0 0 0";
+	}
+	
+	string GetCameraName()
+	{
+		return "DayZPlayerCamera";
+	}
+	
+	float GetCurrentYaw()
+	{
+		return -1;
+	}
+	
+	float GetCurrentPitch()
+	{
+		return -1;
+	}
+	
+	float GetCurrentRoll()
+	{
+		return -1;
+	}
+
+	vector GetCurrentOrientation()
+	{
+		return Vector(GetCurrentYaw(), GetCurrentPitch(), GetCurrentRoll());
+	}
+	
+	bool IsCamera3rdRaised()
+	{
+		return false;
+	}
+
+	void SpawnDiagCameraShake()
+	{
+		SpawnCameraShakeProper(1, 1, 15, 4);
+	}
+
+	void SpawnCameraShake(float strength = 1, float radius = 2, float smoothness = 5, float radius_decay_speed = 6)
+	{
+		SpawnCameraShakeProper(strength, radius, smoothness, radius_decay_speed);//done this way in order to avoid duplicating default params which could cause issues under certain circumstances
+	}
+	
+	void SpawnCameraShakeProper(float strength, float radius, float smoothness, float radius_decay_speed);
+	
+	//! data 
+	protected 	DayZPlayer 				m_pPlayer;		//!< player camera is attached to
+	protected 	HumanInputController	m_pInput;		//!< human input 
+	
+	//! m_fCamPosOffsetZ info, used to adjust near plane in DayZPlayerCameraIronsights now
+	void SendRecoilOffsetZ(float offset) {};
+}
+
+
+// *************************************************************************************
+// ! DayZPlayerTypeStepSoundLookupTable - virtual 
+// *************************************************************************************
+class DayZPlayerTypeStepSoundLookupTable
+{
+	SoundObjectBuilder GetSoundBuilder(int eventId, int pMovement, int pSurfaceHash, AnimBootsType pBoots)
+	{
+		return null;
+	}
+}
+
+// *************************************************************************************
+// ! DayZPlayerTypeVoiceSoundLookupTable - virtual 
+// *************************************************************************************
+class DayZPlayerTypeVoiceSoundLookupTable
+{
+	SoundObjectBuilder GetSoundBuilder(int eventId, int parameterHash)
+	{
+		return null;
+	}
+	
+	NoiseParams GetNoiseParams(int eventId);
+}
+
+// *************************************************************************************
+// ! DayZPlayerTypeAttachmentSoundLookupTable - virtual 
+// *************************************************************************************
+class DayZPlayerTypeAttachmentSoundLookupTable
+{
+	SoundObjectBuilder GetSoundBuilder(int eventId, string slotName, int attachmentHash)
+	{
+		return null;
+	}
+}
+
+class DayZPlayerTypeAnimTable
+{
+	AnimSoundEvent GetSoundEvent(int event_id)
+	{
+		return null;
+	}
+}
+
+// *************************************************************************************
+// ! VegetationSound
+// *************************************************************************************
+
+class VegetationSound
+{
+	private ref SoundObjectBuilder m_SoundObjectBuilder;
+	private ref TIntArray m_AnimEventIds;
+	
+	void VegetationSound(SoundObjectBuilder soundObjectBuilder, TIntArray animEventIds)
+	{
+		m_SoundObjectBuilder = soundObjectBuilder;
+		m_AnimEventIds = animEventIds;
+	}
+	
+	SoundObjectBuilder GetSoundObjectBuilder()
+	{
+		return m_SoundObjectBuilder;
+	}
+	
+	TIntArray GetAnimEventIds()
+	{
+		return m_AnimEventIds;
+	}
+}
+
+// *************************************************************************************
+// ! DayZPlayerType - DayZPlayer configuration 
+// *************************************************************************************
+
+//! class that configures static data for DayZPlayer
+//! on each mission start DayZPlayerTypeCreate(DayZPlayerType pType) is called - can call methods
+
+class DayZPlayerType
+{
+	//!----------------------------------------------------
+	// item in hands config
+
+	//! 
+	proto native 	void SetDefaultItemInHandsProfile(string pAnimInstanceName, HumanItemBehaviorCfg pBehaviorCfg);
+
+
+	//! reset profiles 
+	proto native 	void ResetItemInHandsProfiles();
+
+	//! adds setup profile for items of class pItemClass
+	//! when item is in hands - pAnimInstanceName is used for animation sourcing 
+	//! pCanRaise is whether weapon / item can be raised
+	//! pRHandIK == false -> rhand ik is always turned off
+	//! pLHandIK == false -> lhand ik is always turned off
+
+	//! VKOSTIK: DO NOT FORGET !!! HumanItemBehaviorCfg.m_iPerItemCameraUD - per item camera user data - enables you setup different cameras for different items in hands
+
+	//!
+	proto native 	int AddItemInHandsProfile(string pItemClass, string pAnimInstanceName, HumanItemBehaviorCfg pBehaviorCfg);
+
+	//!
+	proto native 	int AddItemInHandsProfileIK(string pItemClass, string pAnimInstanceName, HumanItemBehaviorCfg pBehaviorCfg, string pIkPoseAnim, string pWeaponStates = "");
+
+	//! add bone remap for item class
+	//! pBoneRemap has always 2x N members
+	//! bone in item's P3D first, bone in Character skeleton second
+
+	//! array<string> remap = { "bolt", "Weapon_Bolt", "magazine", "Weapon_Magazine", "trigger", "Weapon_Trigger" };
+	//! AddItemBoneRemap("class", remap);
+
+	proto native 	int AddItemBoneRemap(string pItemClass, array<string> pBoneRemap);
+
+
+	//! debug / hack - loads all animation instances
+	proto native 	void DebugPreloadAnimationInstances();
+
+
+
+	//!----------------------------------------------------
+	// camera creators
+
+	//! resets camera creators
+	proto native 	void ResetCameraCreators();
+
+	//! registers camera creator - camera type => camera type (must be descendant of DayZPlayerCamera)
+	proto native 	void RegisterCameraCreator(int pCameraID, typename pCameraType);
+
+	//! registers camera on change function - static function 
+	proto native 	void RegisterCameraOnChangeFnStatic(typename pClass, string pFnName);
+
+	//! registers camera on change function - 
+	proto native 	void RegisterCameraOnChangeFn(Class pInstance, string pFnName);
+
+
+	//!----------------------------------------------------
+	// global options
+
+	//! sets look limits for a player
+	proto native 	void SetLookLimits(float pDown, float pUp, float pLeft, float pRight);
+
+	//! sets aim limits for a player
+	proto native 	void SetAimLimits(float pDown, float pUp, float pLeft, float pRight);
+	
+	//! sets vertical minimum aim limit for a player
+	proto native 	void SetVerticalMinimumAimLimit(float value);
+
+	//! sets aim limits for a player
+	proto native 	void SetCameraShootParams(float pRayDistance, float pRayRadius, float pMaxAngleCos);
+
+	//!----------------------------------------------------
+	// bone indices
+
+	proto native	int  GetHeadBoneIdx();
+
+	//!----------------------------------------------------
+	// event handling
+
+	//! calls DayZPlayer.OnStepEvent();
+	proto native	void RegisterStepEvent(string pEventType, float pFilterTimeout);
+
+	//! calls DayZPlayer.OnSoundEvent();
+	proto native	void RegisterSoundEvent(string pEventType, float pFilterTimeout);
+
+	//! calls DayZPlayer.OnParticleEvent();
+	proto native	void RegisterParticleEvent(string pEventType, float pFilterTimeout);
+
+
+	void 				 RegisterStepSoundLookupTable(DayZPlayerTypeStepSoundLookupTable pSSLUT)
+	{
+		m_pStepSoundLookupTable = pSSLUT;
+	}
+	
+	DayZPlayerTypeStepSoundLookupTable	GetStepSoundLookupTable()
+	{
+		return m_pStepSoundLookupTable;
+	}
+	
+	void RegisterAttachmentSoundLookupTable(DayZPlayerTypeAttachmentSoundLookupTable pASLUT)
+	{
+		m_pAttachmentSoundLookupTable = pASLUT;
+	}
+	
+	DayZPlayerTypeAttachmentSoundLookupTable	GetAttachmentSoundLookupTable()
+	{
+		return m_pAttachmentSoundLookupTable;
+	}
+	
+	void RegisterVoiceSoundLookupTable(DayZPlayerTypeVoiceSoundLookupTable pASLUT)
+	{
+		m_pVoiceSoundLookupTable = pASLUT;
+	}
+	
+	DayZPlayerTypeVoiceSoundLookupTable	GetVoiceSoundLookupTable()
+	{
+		return m_pVoiceSoundLookupTable;
+	}
+	
+	void RegisterSoundTable(DayZPlayerTypeAnimTable pST)
+	{
+		m_pSoundTable = pST;
+	}
+	
+	DayZPlayerTypeAnimTable GetSoundTable()
+	{
+		return m_pSoundTable;
+	}
+	
+	/*
+	void RegisterSoundVoiceTable(DayZPlayerTypeAnimTable pVST)
+	{
+		m_pSoundVoiceTable = pVST;
+	}
+	
+	DayZPlayerTypeAnimTable GetSoundVoiceTable()
+	{
+		return m_pSoundVoiceTable;
+	}
+	*/
+	
+	array<ref VegetationSound> GetVegetationSounds()
+	{
+		return m_pVegetationSounds;
+	}
+	
+	NoiseParams GetNoiseParamsStand()
+	{
+		return m_pNoiseStepStand;
+	}
+	
+	NoiseParams GetNoiseParamsCrouch()
+	{
+		return m_pNoiseStepCrouch;
+	}
+	
+	NoiseParams GetNoiseParamsProne()
+	{
+		return m_pNoiseStepProne;
+	}
+	
+	NoiseParams GetNoiseParamsLandLight()
+	{
+		return m_pNoiseLandLight;	
+	}
+	
+	NoiseParams GetNoiseParamsLandHeavy()
+	{
+		return m_pNoiseLandHeavy;
+	}
+	
+	NoiseParams GetNoiseParamsWhisper()
+	{
+		return m_pNoiseWhisper;	
+	}
+	
+	NoiseParams GetNoiseParamsTalk()
+	{
+		return m_pNoiseTalk;	
+	}
+	
+	NoiseParams GetNoiseParamsShout()
+	{
+		return m_pNoiseShout;	
+	}
+	
+	void LoadSoundWeaponEvent()
+	{
+		string cfgPath = "CfgVehicles SurvivorBase AnimEvents SoundWeapon ";
+		
+		m_animSoundEventsAttack = new array<ref AnimSoundEvent>;
+
+		int soundCount = GetGame().ConfigGetChildrenCount(cfgPath);
+		for(int i = 0; i < soundCount; i++)
+		{
+			string soundName;
+			GetGame().ConfigGetChildName(cfgPath, i, soundName);
+			string soundPath = cfgPath + soundName + " ";
+			AnimSoundEvent soundEvent = new AnimSoundEvent(soundPath);
+			if(soundEvent.IsValid())
+				m_animSoundEventsAttack.Insert(soundEvent);
+		}
+	}
+	
+	void LoadVegetationSounds()
+	{
+		m_pVegetationSounds = new array<ref VegetationSound>;
+
+		string vegSoundsCfgPath = "CfgVehicles SurvivorBase VegetationSounds ";
+		int vegSoundsCount = GetGame().ConfigGetChildrenCount(vegSoundsCfgPath);
+
+		for (int v = 0; v < vegSoundsCount; ++v)
+		{
+			string vegSoundParamName;
+			GetGame().ConfigGetChildName(vegSoundsCfgPath, v, vegSoundParamName);
+			
+			string soundSet = "";
+			GetGame().ConfigGetText(vegSoundsCfgPath + vegSoundParamName + " soundSet", soundSet);
+
+			TIntArray animEventIds = new TIntArray;
+			GetGame().ConfigGetIntArray(vegSoundsCfgPath + vegSoundParamName + " animEventIds", animEventIds);
+
+			SoundParams soundParams = new SoundParams(soundSet);
+
+			if (soundParams.IsValid() && animEventIds.Count() > 0)
+			{
+				m_pVegetationSounds.Insert(new VegetationSound(new SoundObjectBuilder(soundParams), animEventIds));
+			}
+		}
+	}
+	
+	AnimSoundEvent GetSoundWeaponEvent(int event_id)
+	{
+		foreach (AnimSoundEvent soundEvent : m_animSoundEventsAttack)
+		{
+			if (soundEvent.m_iID == event_id)
+				return soundEvent;
+		}
+
+		return null;
+	}
+	
+	//! register hit components for AI melee (used by attacking AI)
+	void RegisterHitComponentsForAI()
+	{
+		m_HitComponentsForAI = new array<ref DayZAIHitComponent>;
+
+		//! registers default hit compoent for entity
+		m_DefaultHitComponent = "dmgZone_torso";
+		//! registers default hit position for entity
+		m_DefaultHitPositionComponent = "Pelvis";
+
+		//! list of components suitable for melee finisher attacks (used in fight logic)
+		m_SuitableFinisherHitComponents = new array<string>;
+		m_SuitableFinisherHitComponents.Insert("Head");
+
+		//! register hit components that are selected by probability
+		//DayZAIHitComponentHelpers.RegisterHitComponent(m_HitComponentsForAI, "dmgZone_head", 5); // TMP comment out
+		DayZAIHitComponentHelpers.RegisterHitComponent(m_HitComponentsForAI, "dmgZone_leftArm", 50);
+		DayZAIHitComponentHelpers.RegisterHitComponent(m_HitComponentsForAI, "dmgZone_torso", 65);
+		DayZAIHitComponentHelpers.RegisterHitComponent(m_HitComponentsForAI, "dmgZone_rightArm", 50);
+		DayZAIHitComponentHelpers.RegisterHitComponent(m_HitComponentsForAI, "dmgZone_leftLeg", 40);
+		DayZAIHitComponentHelpers.RegisterHitComponent(m_HitComponentsForAI, "dmgZone_rightLeg", 40);
+	}
+	
+	string GetHitComponentForAI()
+	{
+		string hitComp;
+		
+		if (DayZAIHitComponentHelpers.SelectMostProbableHitComponent(m_HitComponentsForAI, hitComp))
+		{
+			return hitComp;
+		}
+		
+		return GetDefaultHitComponent();
+	}
+	
+	string GetDefaultHitComponent()
+	{
+		return m_DefaultHitComponent;
+	}
+	
+	string GetDefaultHitPositionComponent()
+	{
+		return m_DefaultHitPositionComponent;
+	}
+	
+	array<string> GetSuitableFinisherHitComponents()
+	{
+		return m_SuitableFinisherHitComponents;
+	}
+	
+	private void DayZPlayerType()
+	{
+		string cfgPath = "CfgVehicles SurvivorBase ";
+	
+		m_pNoiseStepStand = new NoiseParams();
+		m_pNoiseStepStand.LoadFromPath(cfgPath + "NoiseStepStand");
+		
+		m_pNoiseStepCrouch = new NoiseParams();
+		m_pNoiseStepCrouch.LoadFromPath(cfgPath + "NoiseStepCrouch");
+		
+		m_pNoiseStepProne = new NoiseParams();
+		m_pNoiseStepProne.LoadFromPath(cfgPath + "NoiseStepProne");
+		
+		m_pNoiseLandLight = new NoiseParams();
+		m_pNoiseLandLight.LoadFromPath(cfgPath + "NoiseLandLight");
+		
+		m_pNoiseLandHeavy = new NoiseParams();
+		m_pNoiseLandHeavy.LoadFromPath(cfgPath + "NoiseLandHeavy");
+		
+		m_pNoiseWhisper = new NoiseParams();
+		m_pNoiseWhisper.LoadFromPath(cfgPath + "NoiseWhisper");
+		
+		m_pNoiseTalk = new NoiseParams();
+		m_pNoiseTalk.LoadFromPath(cfgPath + "NoiseTalk");
+		
+		m_pNoiseShout = new NoiseParams();
+		m_pNoiseShout.LoadFromPath(cfgPath + "NoiseShout");
+		
+		LoadSoundWeaponEvent();
+		LoadVegetationSounds();
+	}
+	
+	private void ~DayZPlayerType();
+
+	//!----------------------------------------------------
+	// global settings
+
+	//! returns Human global settings for DayZPlayer
+	proto native 	SHumanGlobalSettings 		GetGlobalSettingsW();
+
+
+	//!----------------------------------------------------
+	// command configs
+
+	// returns command move setting for write - in init phase
+	proto native 	SHumanCommandMoveSettings	CommandMoveSettingsW();
+
+	// returns command swim setting for write - in init phase
+	proto native 	SHumanCommandSwimSettings	CommandSwimSettingsW();
+
+	// returns command swim setting for write - in init phase
+	proto native 	SHumanCommandClimbSettings	CommandClimbSettingsW();
+
+
+	//!< this is used for getting appropriate sound effect to play step event on various surfaces && boots
+	//!< it's downcasted to StepSoundLookupTable
+	ref DayZPlayerTypeStepSoundLookupTable m_pStepSoundLookupTable;
+	ref DayZPlayerTypeAttachmentSoundLookupTable m_pAttachmentSoundLookupTable;
+	ref DayZPlayerTypeVoiceSoundLookupTable m_pVoiceSoundLookupTable;
+	ref DayZPlayerTypeAnimTable m_pSoundTable;
+	//ref DayZPlayerTypeAnimTable m_pSoundVoiceTable;
+	ref NoiseParams m_pNoiseStepStand;
+	ref NoiseParams m_pNoiseStepCrouch;
+	ref NoiseParams m_pNoiseStepProne;
+	ref NoiseParams m_pNoiseLandLight;
+	ref NoiseParams m_pNoiseLandHeavy;
+	
+	// von noises
+	ref NoiseParams m_pNoiseWhisper;
+	ref NoiseParams m_pNoiseTalk;
+	ref NoiseParams m_pNoiseShout;
+
+	ref array<ref VegetationSound> m_pVegetationSounds;
+
+	//! Melee hit components (AI targeting)	
+	protected ref array<ref DayZAIHitComponent> m_HitComponentsForAI;
+	protected string m_DefaultHitComponent;
+	protected string m_DefaultHitPositionComponent;
+
+	protected ref array<string> m_SuitableFinisherHitComponents;
+	
+	ref array<ref AnimSoundEvent> m_animSoundEventsAttack;
+}
+
+
+// *************************************************************************************
+// ! DayZPlayerConstants - dayz player constants 
+// *************************************************************************************
+//! defined in C++
+enum DayZPlayerConstants
+{
+    //! ---------------------------------------------------------
+    //! ---------------------- movement stances -----------------
+    //! ---------------------------------------------------------
+	DEBUG_MENU,				//!< dayz player debug menu in enfusion 
+	DEBUG_TURNSLIDE,		//!< over turn slides / clamps
+	DEBUG_SHOWDEBUGPLUGIN,  //!< menu for showing debug plugin
+	DEBUG_SHOWINJURY,		//!< menu for showing injuries
+	DEBUG_SHOWEXHAUSTION,	//!< menu for showing exhaustion
+	DEBUG_ENABLEJUMP,		//!< menu for showing exhaustion
+	DEBUG_ENABLETALKING,	//!< option for showing talk command
+	
+
+    //! ---------------------------------------------------------
+    //! ---------------------- movement stances -----------------
+    //! ---------------------------------------------------------
+
+	STANCEIDX_ERECT,
+	STANCEIDX_CROUCH,
+	STANCEIDX_PRONE,
+	STANCEIDX_RAISEDERECT,
+	STANCEIDX_RAISEDCROUCH,
+	STANCEIDX_RAISEDPRONE,
+	/*
+	 STANCEIDX_ERECT + STANCEIDX_RAISED = STANCEIDX_RAISEDERECT
+	 STANCEIDX_RAISEDCROUCH - STANCEIDX_RAISED = STANCEIDX_CROUCH...
+	*/
+	STANCEIDX_RAISED,
+
+
+	//! stance masks 
+	STANCEMASK_ERECT,
+	STANCEMASK_CROUCH,
+	STANCEMASK_PRONE,
+	STANCEMASK_RAISEDERECT,
+	STANCEMASK_RAISEDCROUCH,
+	STANCEMASK_RAISEDPRONE,
+	STANCEMASK_ALL,		// STANCEMASK_ERECT | STANCEMASK_CROUCH | STANCEMASK_PRONE | STANCEMASK_RAISEDERECT | STANCEMASK_RAISEDCROUCH | STANCEMASK_RAISEDPRONE
+	STANCEMASK_NOTRAISED 	= STANCEMASK_ERECT | STANCEMASK_CROUCH | STANCEMASK_PRONE,
+	STANCEMASK_RAISED 		= STANCEMASK_RAISEDERECT | STANCEMASK_RAISEDCROUCH | STANCEMASK_RAISEDPRONE,
+
+
+	//! movements - masks 
+	MOVEMENT_IDLE,  			//! 0x1
+	MOVEMENT_WALK,				//! 0x2
+	MOVEMENT_RUN,				//! 0x4
+	MOVEMENT_SPRINT,			//! 0x8 
+
+	//! rotation modes
+	
+	ROTATION_DISABLE,			//!
+	ROTATION_ENABLE,			//!
+	
+	//! movement idx
+	MOVEMENTIDX_SLIDE	= -2,
+	MOVEMENTIDX_IDLE	= 0,
+	MOVEMENTIDX_WALK	= 1,
+	MOVEMENTIDX_RUN		= 2,
+	MOVEMENTIDX_SPRINT  = 3,
+	MOVEMENTIDX_CROUCH_RUN = 4,
+	
+	//! melee hit type
+	MELEE_LIGHT = 0,
+	MELEE_HEAVY = 1,
+	
+
+	//! vehicle classes
+	VEHICLECLASS_CAR,
+	VEHICLECLASS_HELI,
+	VEHICLECLASS_BOAT,
+
+	//! vehicle seats
+	VEHICLESEAT_DRIVER,
+	VEHICLESEAT_CODRIVER,
+	VEHICLESEAT_PASSENGER_L,
+	VEHICLESEAT_PASSENGER_R,
+
+	//! death types
+	DEATH_DEFAULT = -1,			//! not defining in C++ as it is only used in script for undefined type
+	DEATH_PULL_OUT_TRANSPORT,	//! transport death -> death - special handling for pulling a dead player out of a vehicle
+	DEATH_BODY,					//! locomotion -> death - normal death animation while a player is conciscious 
+	DEATH_FAST,					//! locomotion -> death - faster animation, for impulse driven deaths, i.e. hit by vehicle
+	DEATH_WATER,				//! swimming -> death 
+	DEATH_FALL,					//! falling -> death 
+	DEATH_UNCON_ON_LAND,		//! unconscious -> death - while not in water
+	DEATH_UNCON_IN_WATER,		//! unconscious -> death - while in water
+	// - Type not used for "swimming to death" or "transport to death"
+
+    //! ---------------------------------------------------------
+    //! ---------------------- COMMAND IDs ----------------------
+    //! ---------------------------------------------------------
+	
+	//! command ids - main movement commands 
+	COMMANDID_NONE,    		// type is int - no command - invalid state 
+	COMMANDID_MOVE,			// type is int (overridden from C++) - normal movement (idle, walk, run, sprint, ... )
+	COMMANDID_ACTION,		// type is int (overridden from C++) - full body action
+	COMMANDID_MELEE,		// type is int (overridden from C++) - melee attacks
+	COMMANDID_MELEE2,		// type is int (overridden from C++) - melee attacks
+	COMMANDID_FALL,			// type is int (overridden from C++) - falling
+	COMMANDID_DEATH,		// type is int (overridden from C++) - dead 
+	COMMANDID_DAMAGE,		// type is int (overridden from C++) - fullbody damage
+	COMMANDID_LADDER,		// type is int (overridden from C++) - ladder
+	COMMANDID_UNCONSCIOUS,	// type is int (overridden from C++) - unconscious
+	COMMANDID_SWIM,			// type is int (overridden from C++) - swimming
+	COMMANDID_VEHICLE,		// type is int (overridden from C++) - vehicle
+	COMMANDID_CLIMB,		// type is int (overridden from C++) - climb
+	COMMANDID_SCRIPT,		// type is int (overridden from C++) - all scripted commands
+
+
+	//! modifier commands - additive behaviour 
+	COMMANDID_MOD_LOOKAT,    	// look at - always on 
+	COMMANDID_MOD_WEAPONS,   	// weapons - always on 
+    COMMANDID_MOD_ACTION,		// action - additive action 
+	COMMANDID_MOD_DAMAGE,		// damage - additive damage 
+
+
+
+
+    //! ---------------------------------------------------------
+    //! ---------------------- ACTIONS --------------------------
+    //! ---------------------------------------------------------
+
+	//! internal action commands used in HumanCommandActionCallback.InternalCommand()
+	CMD_ACTIONINT_INTERRUPT				= -2,		//!< totally interrupt action (no animation, just blend)
+	CMD_ACTIONINT_FINISH				= -1,		//!< secondary ending (finishing action, eg running out of water while drinking, not all actions have this)
+	CMD_ACTIONINT_END					= 0,		//!< end action (stopping action, without finish, all actions have this)
+	CMD_ACTIONINT_ACTION				= 1,		//!< one time secondary action within an action
+	CMD_ACTIONINT_ACTIONLOOP			= 2,		//!< loop secondary action within an action
+
+
+	//! animations constants 
+
+	//! note: (erc - standing, cro - crouching, pne - prone)    	anim pose it can start from
+	//! note: (end, end2, action, loop2)							internal command which can be send in loop state 
+
+	//! looping 	
+		
+    //! --------------------------
+    //! modifier (differential animation)
+    CMD_ACTIONMOD_DRINK							= 0,		// erc,cro    		[end, end2]
+	CMD_ACTIONMOD_EAT							= 1,		// erc,cro    		[end, end2]
+	CMD_ACTIONMOD_EMPTY_VESSEL					= 2,		// erc,cro          [end]
+	CMD_ACTIONMOD_CATCHRAIN						= 3,		// erc,cro			[end]
+	CMD_ACTIONMOD_VIEWCOMPASS					= 7,		// erc,cro          [end]
+	CMD_ACTIONMOD_ITEM_TUNE						= 9,		// erc,cro			[end]
+	CMD_ACTIONMOD_GIVEL							= 10,		// erc,cro			[end]
+	CMD_ACTIONMOD_GIVER							= 11,		// erc,cro			[end]
+	CMD_ACTIONMOD_SHAVE							= 12,		// erc,cro			[end]
+	CMD_ACTIONMOD_FILLMAG						= 13,		// erc,cro			[end]
+	CMD_ACTIONMOD_EMPTYMAG						= 14,		// erc,cro			[end]
+	CMD_ACTIONMOD_OPENITEM						= 15,		// erc,cro			[end]
+	CMD_ACTIONMOD_TAKETEMPSELF					= 18,		// erc,cro			[end]
+	CMD_ACTIONMOD_VIEWMAP						= 19,		// erc,cro			[end]
+	CMD_ACTIONMOD_RAISEITEM						= 20,		// erc,cro			[end]
+	CMD_ACTIONMOD_SEARCHINVENTORY				= 21,		// erc,cro			[end]
+	CMD_ACTIONMOD_CRAFTING						= 22,		// erc,cro			[end]
+	CMD_ACTIONMOD_RESTRAINEDSTRUGGLE			= 23,		// erc,cro 			[end, end2]
+	CMD_ACTIONMOD_COVERHEAD_SELF				= 24,		// erc,cro 			[end, end2]
+	CMD_ACTIONMOD_COVERHEAD_TARGET				= 25,		// erc,cro 			[end, end2]
+	CMD_ACTIONMOD_SET_ALARM						= 250,
+	CMD_ACTIONMOD_SET_KITCHENTIMER				= 252,
+	CMD_ACTIONMOD_RESET_KITCHENTIMER			= 253,
+	CMD_ACTIONMOD_BLOODTEST 		    		= 254,      // erc,cro          [end]
+	CMD_ACTIONMOD_BLOODTESTOTHER 				= 255,      // erc,cro          [end]
+	
+	// onetime 
+	CMD_ACTIONMOD_PICKUP_HANDS					= 500,		// erc,cro
+	CMD_ACTIONMOD_PICKUP_INVENTORY				= 501,		// erc,cro
+	CMD_ACTIONMOD_LICKBATTERY					= 502,		// erc,cro
+	CMD_ACTIONMOD_LIGHTFLARE					= 503,		// erc,cro
+	CMD_ACTIONMOD_LITCHEMLIGHT					= 504,		// erc,cro
+	CMD_ACTIONMOD_UNPINGRENAGE					= 505,		// erc,cro
+	CMD_ACTIONMOD_OPENDOORFW					= 506,		// erc,cro
+	CMD_ACTIONMOD_OPENLID						= 507,		// erc,cro 
+	CMD_ACTIONMOD_CLOSELID						= 508,		// erc,cro 	
+	CMD_ACTIONMOD_ITEM_ON						= 509,		// erc,cro
+	CMD_ACTIONMOD_ITEM_OFF						= 510,		// erc,cro
+	CMD_ACTIONMOD_BATONEXTEND					= 511,		// erc,cro
+	CMD_ACTIONMOD_BATONRETRACT					= 512,		// erc,cro
+	CMD_ACTIONMOD_UNLOCKHANDCUFFTARGET			= 513,		// erc,cro
+	CMD_ACTIONMOD_FISHINGRODEXTEND				= 514,		// erc,cro
+	CMD_ACTIONMOD_FISHINGRODRETRACT				= 515,		// erc,cro
+	CMD_ACTIONMOD_CLEANHANDSBOTTLE				= 516,		// erc,cro
+	CMD_ACTIONMOD_OPENITEM_ONCE					= 517,		// erc,cro
+	CMD_ACTIONMOD_ATTACHSCOPE					= 518,		// erc,cro
+	CMD_ACTIONMOD_ATTACHBARREL					= 519,		// erc,cro
+	CMD_ACTIONMOD_EMPTYSEEDSPACK				= 520,		// erc,cro
+	CMD_ACTIONMOD_INTERACTONCE					= 521,		// erc,cro
+	CMD_ACTIONMOD_ATTACHITEM					= 522,		// erc,cro
+	CMD_ACTIONMOD_CLOSEITEM_ONCE				= 523,		// erc,cro,pne
+	CMD_ACTIONMOD_FOLDITEM_ONCE					= 524,		// erc,cro
+	CMD_ACTIONMOD_UNFOLDITEM_ONCE				= 525,		// erc,cro
+	CMD_ACTIONMOD_PRESS_TRIGGER					= 526,		// erc,cro
+	CMD_ACTIONMOD_STOP_ALARM					= 251,
+	CMD_ACTIONMOD_EAT_PILL			    		= 527,      // erc,cro
+	CMD_ACTIONMOD_EAT_TABLET					= 528,      // erc,cro
+	CMD_ACTIONMOD_HEATPACK			    		= 529,      // erc,cro
+
+	
+	
+	CMD_ACTIONMOD_DROPITEM_HANDS				= 900,		// erc, cro
+	CMD_ACTIONMOD_DROPITEM_INVENTORY			= 901,		// erc, cro
+	
+	
+
+    //! --------------------------
+    //! fb (full body)
+    CMD_ACTIONFB_DRINK							= 0,		// pne				[end, end2]
+	CMD_ACTIONFB_EAT							= 1,		// pne				[end, end2]
+	CMD_ACTIONFB_CATCHRAIN						= 3,		// pne				[end]
+	CMD_ACTIONFB_ITEM_TUNE						= 9,		// pne				[end]
+	CMD_ACTIONFB_GIVEL							= 10,		// pne				[end]
+	CMD_ACTIONFB_GIVER							= 11,		// pne				[end]
+	CMD_ACTIONFB_FILLMAG						= 13,		// pne				[end]
+	CMD_ACTIONFB_EMPTYMAG						= 14,		// pne				[end]
+	CMD_ACTIONFB_DRINKPOND						= 50,		// cro 	      	    [end]
+	CMD_ACTIONFB_DRINKWELL						= 51,		// cro 	            [end]
+	CMD_ACTIONFB_FILLBOTTLEWELL					= 52,		// cro	            [end]
+	CMD_ACTIONFB_FIREESTINGUISHER				= 53,		// erc              [end]
+	CMD_ACTIONFB_WRING							= 54,		// cro 		        [end]
+	CMD_ACTIONFB_FISHING						= 56,		// cro			    [action (check fish), end(catch fish), end2(not catching anything ]
+	CMD_ACTIONFB_CPR							= 57,		// cro     		    [end]
+	CMD_ACTIONFB_BANDAGE						= 58,		// cro		        [end]
+	CMD_ACTIONFB_CRAFTING						= 59,		// cro		        [end]
+	CMD_ACTIONFB_INTERACT						= 60,		// erc,cro			[end]
+	CMD_ACTIONFB_FORCEFEED						= 62,		// erc,cro          [end]
+	CMD_ACTIONFB_BANDAGETARGET					= 63,		// erc,cro          [end]
+	CMD_ACTIONFB_SPRAYPLANT						= 64,		// cro     		    [end]
+	CMD_ACTIONFB_STARTFIRE						= 65,		// cro			    [end]
+	CMD_ACTIONFB_ANIMALSKINNING					= 66,		// cro				[end]
+	CMD_ACTIONFB_WASHHANDSWELL					= 67,		// cro				[end]
+	CMD_ACTIONFB_WASHHANDSPOND					= 68,		// cro				[end]
+	CMD_ACTIONFB_SALINEBLOODBAGTARGET			= 69,		// erc,cro			[end]
+	CMD_ACTIONFB_SALINEBLOODBAG					= 70,		// erc,cro			[end]
+	CMD_ACTIONFB_STITCHUPSELF					= 71,		// erc,cro			[end]
+	CMD_ACTIONFB_VOMIT							= 72,		// cro				[end]
+	CMD_ACTIONFB_UNRESTRAINTARGET				= 73,		// erc,cro			[end (finish cutting), end2 (cancel cutting)]
+	CMD_ACTIONFB_RESTRAINTARGET					= 74,		// erc,cro			[end (finish tying up), end2 (cancel tying up)]
+	CMD_ACTIONFB_CHECKPULSE						= 76,		// cro				[end]
+	CMD_ACTIONFB_CLEANWOUNDSTARGET				= 78,		// erc, cro			[end]
+	CMD_ACTIONFB_COLLECTBLOODSELF				= 81,		// erc, cro			[end]
+	CMD_ACTIONFB_EMPTY_VESSEL					= 82,		// erc, cro			[end]
+	CMD_ACTIONFB_OPENITEM						= 83,		// pne				[end]
+	CMD_ACTIONFB_HACKBUSH						= 85,		// erc				[end, end2]
+	CMD_ACTIONFB_HACKTREE						= 86,		// erc				[end, end2]
+	CMD_ACTIONFB_TAKETEMPSELF					= 87,		// pne				[end]
+	CMD_ACTIONFB_DIG							= 88,		// erc				[end, end2]
+	CMD_ACTIONFB_DIGUPCACHE						= 89,		// erc				[end, end2]
+	CMD_ACTIONFB_DIGMANIPULATE					= 90,		// erc				[end, end2]
+	CMD_ACTIONFB_DEPLOY_HEAVY					= 95,		// erc				[end, end2]
+	CMD_ACTIONFB_DEPLOY_2HD						= 96,		// cro				[end, end2]
+	CMD_ACTIONFB_DEPLOY_1HD						= 97,		// cro				[end, end2]
+	CMD_ACTIONFB_BLOWFIREPLACE					= 98,		// cro				[end]
+	CMD_ACTIONFB_VIEWMAP						= 99,		// pne				[end]
+	CMD_ACTIONFB_VIEWCOMPASS					= 100,		// pne				[end]
+	CMD_ACTIONFB_FILLBOTTLEPOND					= 101,		// erc, cro			[end]
+	CMD_ACTIONFB_PLACING_HEAVY					= 102,		// erc				[end, end2]
+	CMD_ACTIONFB_PLACING_2HD					= 103,		// cro				[end, end2]
+	CMD_ACTIONFB_PLACING_1HD					= 104,		// cro				[end, end2]
+	CMD_ACTIONFB_CUTBARK						= 105,		// erc,cro			[end, end2]
+	CMD_ACTIONFB_VIEWNOTE						= 106,		// erc,cro,pne		[end]
+	CMD_ACTIONFB_SEARCHINVENTORY				= 107,		// pne				[end]
+	CMD_GESTUREFB_LOOKOPTICS					= 108,		// erc,cro,pne		[end]
+	CMD_ACTIONFB_MINEROCK						= 109,		// erc				[end, end2]
+	CMD_ACTIONFB_RAISEITEM						= 110,		// pne 				[end]
+	CMD_ACTIONFB_RESTRAINEDSTRUGGLE				= 111,		// ,pne 			[end, end2]
+	CMD_ACTIONFB_RESTRAINSELF					= 112,		// erc,cro 			[end]
+	CMD_ACTIONFB_ASSEMBLE						= 113,		// erc,cro			[end, end2]
+	CMD_ACTIONFB_DISASSEMBLE					= 114,		// erc,cro			[end, end2]
+	CMD_ACTIONFB_FLAME_REPAIR					= 115,		// erc, cro	
+	CMD_ACTIONFB_TURN_VALVE						= 116,		// erc
+	CMD_ACTIONFB_SET_ALARM						= 250,		// erc,cro			??not sure
+	CMD_ACTIONFB_SHOVEL_DIG		     			= 117,		// cro			    [end, end2]
+	CMD_ACTIONFB_VEHICLE_PUSH					= 118,		// erc
+	CMD_ACTIONFB_PATCHING_TIRE					= 119,		// cro              [end]
+	CMD_ACTIONFB_PATCHING_DUCTTAPE				= 120,		// cro              [end]
+	CMD_ACTIONFB_PATCHING_SEWING				= 121,		// cro              [end]
+	CMD_ACTIONFB_PATCHING_LEATHER_SEWING_KIT	= 122,		// cro              [end]
+	CMD_ACTIONFB_SPLITTING_FIREWOOD				= 123,		// cro              [end]
+	CMD_ACTIONFB_BREAKING_STICK		    		= 124,		// cro              [end]
+	CMD_ACTIONFB_CLEANING_WEAPON	    		= 125,		// cro              [end]
+	CMD_ACTIONFB_EATING_SNOW	        		= 126,		// cro              [end]
+	CMD_ACTIONFB_FILLING_CONTAINER_SNOW			= 127,		// cro              [end]
+	CMD_ACTIONFB_DIGGIN_WORMS	        		= 128,		// erc,cro              [end]
+	
+	// onetime 
+	CMD_ACTIONFB_PICKUP_HANDS					= 500,		// pne
+	CMD_ACTIONFB_PICKUP_INVENTORY				= 501,		// pne
+	CMD_ACTIONFB_LICKBATTERY					= 502,		// pne
+	CMD_ACTIONFB_LIGHTFLARE						= 503,		// pne
+	CMD_ACTIONFB_LITCHEMLIGHT					= 504,		// pne
+	CMD_ACTIONFB_UNPINGRENAGE					= 505,		// pne
+	CMD_ACTIONFB_ITEM_ON						= 506,		// pne
+	CMD_ACTIONFB_ITEM_OFF						= 507,		// pne
+	CMD_ACTIONFB_HANDCUFFTARGET					= 508,		// erc,cro
+	CMD_ACTIONFB_MORPHINE						= 509,		// cro
+	CMD_ACTIONFB_INJECTION						= 510,		// cro
+	CMD_ACTIONFB_INJECTIONTARGET				= 511,		// erc,cro
+	CMD_ACTIONFB_DRINKSIP						= 512,		// cro
+	CMD_ACTIONFB_CLEANHANDSBOTTLE				= 513,		// pne
+	CMD_ACTIONFB_OPENITEM_ONCE					= 514,		// pne
+	CMD_ACTIONFB_POKE							= 515,		// cro
+	CMD_ACTIONFB_ATTACHSCOPE					= 516,		// pne
+	CMD_ACTIONFB_ATTACHBARREL					= 517,		// pne
+	CMD_ACTIONFB_RESTRAIN						= 518,		// erc,cro,pne
+	CMD_ACTIONFB_PICKUP_HEAVY					= 519,		// erc
+	CMD_ACTIONFB_PRESS_TRIGGER					= 526,		// pne
+	CMD_ACTIONFB_RAISE_FLAG						= 600,		// erc?
+	CMD_ACTIONFB_LOWER_FLAG						= 601,		// erc?
+	CMD_ACTIONFB_STOP_ALARM						= 251,
+	CMD_ACTIONFB_EAT_PILL						= 527,      // pne
+	CMD_ACTIONFB_EAT_TABLET						= 528,      // pne
+	CMD_ACTIONFB_HEATPACK			    		= 529,      // pne
+
+	CMD_ACTIONFB_DROPITEM_HANDS					= 900,			// pne, pne back
+	
+	    //! ---------------------------------------------------------
+    //! ---------------------- TRAILER --------------------------
+    //! ---------------------------------------------------------
+    CMD_TRAILER_MASK 	 						= 3006,
+	CMD_TRAILER_MASK_02 	 					= 3007,
+	CMD_TRAILER_MASK_CHAINS 	 		= 3008,
+	CMD_TRAILER_MASK_DALLAS 	 		= 3009,
+	CMD_TRAILER_MASK_HOXTON 	 		= 3010,
+	CMD_TRAILER_MASK_WOLF 	 			= 3011,
+	
+    
+    //! ---------------------------------------------------------
+    //! ---------------------- VEHICLES -------------------------
+    //! ---------------------------------------------------------
+	
+	// looping actions
+	CMD_ACTIONMOD_STARTENGINE					= 300,    		// [end]
+	CMD_ACTIONMOD_TOOTHORN						= 301,    		// [end]
+	
+	// onetime actions
+	CMD_ACTIONMOD_DRIVER_DOOR_OPEN				= 400,
+	CMD_ACTIONMOD_DRIVER_DOOR_CLOSE				= 401,
+	CMD_ACTIONMOD_CODRIVER_DOOROPEN				= 402,
+	CMD_ACTIONMOD_CODRIVER_DOORCLOSE			= 403,
+	CMD_ACTIONMOD_STOPENGINE					= 404,
+	CMD_ACTIONMOD_SHIFTGEAR						= 405,
+	CMD_ACTIONMOD_HEADLIGHT						= 406,
+	
+	
+	
+    
+    //! ---------------------------------------------------------
+    //! ---------------------- GESTURES -------------------------
+    //! ---------------------------------------------------------
+    //! modifier (differential animation)
+    CMD_GESTUREMOD_GREETING						= 1000,			// erc,cro	 	    [end]
+    CMD_GESTUREMOD_POINT						= 1001,			// erc,cro	 	    [end]
+    CMD_GESTUREMOD_THUMB						= 1002,			// erc,cro	 	    [end, CMD_ACTIONINT_ACTION to switch to THUMB DOWN]
+    CMD_GESTUREMOD_THUMBDOWN					= 1003,			// erc,cro	 	    [end, CMD_ACTIONINT_ACTION to switch to THUMB UP]
+    CMD_GESTUREMOD_SILENCE						= 1004,			// erc,cro	 	    [end]
+    CMD_GESTUREMOD_TAUNT						= 1005,			// erc,cro	 	    [end]
+    CMD_GESTUREMOD_TIMEOUT						= 1006,			// erc,cro	 	    [end]
+    CMD_GESTUREMOD_HEART						= 1007,			// erc,cro	 	    [end]
+    CMD_GESTUREMOD_FACEPALM						= 1008,			// erc,cro   	    [end]
+    CMD_GESTUREMOD_WATCHING						= 1009,			// erc,cro	 	    [end]
+    CMD_GESTUREMOD_HOLD							= 1010,			// erc,cro	 	    [end]
+    CMD_GESTUREMOD_LISTENING					= 1011,			// erc,cro	 	    [end]
+    CMD_GESTUREMOD_POINTSELF					= 1012,			// erc,cro	 	    [end]
+    CMD_GESTUREMOD_LOOKATME						= 1013,			// erc,cro	 	    [end]
+    CMD_GESTUREMOD_OKAY							= 1014,			// erc,cro	 	    [end]
+
+    CMD_GESTUREMOD_RPS							= 10000,		// erc 	            [SPECIAL, SEE BELOW]
+
+    CMD_ACTIONINT_RPS_ROCK						= 10,	    	// RPS Internal Gesture
+    CMD_ACTIONINT_RPS_PAPER						= 11,			// RPS Internal Gesture
+    CMD_ACTIONINT_RPS_SCISSORS					= 12,			// RPS Internal Gesture
+	
+	
+    // onetime 		
+    CMD_GESTUREMOD_THROAT						= 1100,			// erc,cro
+    CMD_GESTUREMOD_CLAP							= 1101,			// erc,cro
+    CMD_GESTUREMOD_DABBING						= 1102,			// erc,cro
+    CMD_GESTUREMOD_MOVE							= 1103,			// erc,cro
+    CMD_GESTUREMOD_DOWN							= 1104,			// erc,cro
+    CMD_GESTUREMOD_COME							= 1105,			// erc,cro
+    CMD_GESTUREMOD_TAUNTKISS					= 1106,			// erc,cro
+    CMD_GESTUREMOD_TAUNTELBOW					= 1107,			// erc,cro
+    CMD_GESTUREMOD_TAUNTTHINK					= 1108,			// erc,cro
+    CMD_GESTUREMOD_NODHEAD						= 1109,			// erc,cro
+    CMD_GESTUREMOD_SHAKEHEAD					= 1110,			// erc,cro
+    CMD_GESTUREMOD_SHRUG						= 1111,			// erc,cro
+    CMD_GESTUREMOD_SURRENDER					= 1112,			// erc
+    CMD_GESTUREMOD_SURRENDERIN					= 1112,			// erc
+    CMD_GESTUREMOD_SURRENDEROUT					= 1113,			// erc
+	
+    //! --------------------------
+    //! fb (full body)
+    CMD_GESTUREFB_GREETING						= 1000,			// pne 	    [end]
+    CMD_GESTUREFB_POINT							= 1001,			// pne 	    [end]
+    CMD_GESTUREFB_THUMB							= 1002,			// pne 	    [end, CMD_ACTIONINT_ACTION to switch to THUMB DOWN]
+    CMD_GESTUREFB_THUMBDOWN						= 1003,			// pne 	    [end, CMD_ACTIONINT_ACTION to switch to THUMB UP]
+    CMD_GESTUREFB_SILENCE						= 1004,			// pne 	    [end]
+    CMD_GESTUREFB_TAUNT							= 1005,			// pne 	    [end]
+    CMD_GESTUREFB_TIMEOUT						= 1006,			// pne 	    [end]
+    CMD_GESTUREFB_HEART							= 1007,			// pne 	    [end]
+    CMD_GESTUREFB_WATCHING						= 1009,			// pne 	    [end]
+    CMD_GESTUREFB_HOLD							= 1010,			// pne 	    [end]
+    CMD_GESTUREFB_LISTENING						= 1011,			// pne 	    [end]
+    CMD_GESTUREFB_POINTSELF						= 1012,			// pne 	    [end]
+    CMD_GESTUREFB_LOOKATME						= 1013,			// pne 	    [end]
+    CMD_GESTUREFB_OKAY							= 1014,			// pne 	    [end]
+	
+    CMD_GESTUREFB_SALUTE						= 1050,			// erc              [end]
+    CMD_GESTUREFB_CAMPFIRE						= 1051,			// cro              [end]
+    CMD_GESTUREFB_LYINGDOWN						= 1052,			// cro              [end]
+    CMD_GESTUREFB_SOS							= 1053,			// erc              [end]
+    CMD_GESTUREFB_SITA							= 1054,			// cro              [end]
+    CMD_GESTUREFB_SITB							= 1055,			// cro              [end]
+    CMD_GESTUREFB_DABBING						= 1056,			// erc, cro         [end]
+    CMD_GESTUREFB_KNEEL							= 1057,			// cro   			[end]
+
+    // onetime 
+    CMD_GESTUREFB_THROAT						= 1100,			// pne
+    CMD_GESTUREFB_MOVE							= 1103,			// pne
+    CMD_GESTUREFB_DOWN							= 1104,			// pne
+    CMD_GESTUREFB_COME							= 1105,			// pne
+    CMD_GESTUREFB_TAUNTKISS						= 1106,			// pne
+    CMD_GESTUREFB_TAUNTTHINK					= 1108,			// pne
+    CMD_GESTUREFB_DANCE							= 1109,			// erc
+	CMD_GESTUREFB_NODHEAD						= 1110,			// pne
+	CMD_GESTUREFB_SHAKEHEAD						= 1111,			// pne
+    CMD_GESTUREFB_SHRUG							= 1112,			// pne
+    CMD_GESTUREFB_SURRENDER						= 1113,			// cro,pne
+    CMD_GESTUREFB_SURRENDERIN					= 1113,			// cro,pne
+    CMD_GESTUREFB_SURRENDEROUT					= 1114,			// cro,pne
+	
+
+    //! ---------------------------------------------------------
+    //! ---------------------- TRAILER --------------------------
+    //! ---------------------------------------------------------
+	CMD_TRAILER_WAKE_UP 						= 3000,
+	CMD_TRAILER_DEAD_BODY 						= 3001,
+	CMD_TRAILER_WALKIE_TALKIE 					= 3002,
+	CMD_TRAILER_WOUNDED 						= 3003,
+	CMD_TRAILER_WALK_AWAY 						= 3004,
+	CMD_TRAILER_DEAD 	 						= 3005,
+	
+    
+    //! ---------------------------------------------------------
+    //! ---------------------- SUICIDE --------------------------
+    //! ---------------------------------------------------------
+    //! fb (full body)
+    CMD_SUICIDEFB_1HD							= 2000,			// cro              [end (cancel), end2 (commit)]
+    CMD_SUICIDEFB_FIREAXE						= 2001,			// erc              [end (cancel), end2 (commit)]
+    CMD_SUICIDEFB_PITCHFORK						= 2002,			// erc              [end (cancel), end2 (commit)]
+    CMD_SUICIDEFB_PISTOL						= 2003,			// cro              [end (cancel), end2 (commit)]
+    CMD_SUICIDEFB_RIFLE							= 2004,			// cro              [end (cancel), end2 (commit)]
+    CMD_SUICIDEFB_SWORD							= 2005,			// erc              [end (cancel), end2 (commit)]
+    CMD_SUICIDEFB_UNARMED						= 2006,			// cro              [end (cancel), end2 (commit)]
+    CMD_SUICIDEFB_WOODAXE						= 2007,			// erc              [end (cancel), end2 (commit)]
+    CMD_SUICIDEFB_SPEAR							= 2008,			// erc              [end (cancel), end2 (commit)]
+	CMD_SUICIDEFB_SICKLE						= 2009,			// cro              [end (cancel), end2 (commit)]
+	CMD_SUICIDEFB_HOE							= 2010,			// erc              [end (cancel), end2 (commit)]
+
+	// 32767 is totaly MAXIMAL index !!!!!
+
+};
+
+//! defined in C++
+enum DayZPlayerInstanceType
+{
+	INSTANCETYPE_SERVER,		//! server instance 
+	INSTANCETYPE_CLIENT,		//! client instance && controlled
+	INSTANCETYPE_REMOTE,		//! client instance && other player 
+	
+	INSTANCETYPE_AI_SERVER,				//! temporary!
+	INSTANCETYPE_AI_REMOTE,				//! temporary!
+	INSTANCETYPE_AI_SINGLEPLAYER,	//! temporary!
+}
+
+// *************************************************************************************
+// ! DayZPlayer - mainly for logic and camera 
+// *************************************************************************************
+class SDayZPlayerHeadingModel
+{
+	int 	m_iCamMode;				//[in]		- DayZPlayerConstants.CAMERAMODE_...
+	int 	m_iCurrentCommandID;    //[in]		- Current Main Command ID 
+	float 	m_fOrientationAngle;	//[in/out] 	- horizontal model orientation (where you face) - in rad
+	float 	m_fHeadingAngle;		//[in/out] 	- horizontal aim angle (where you aim) - in rad
+
+	//! cannot be created from script	
+	private void SDayZPlayerHeadingModel() {}
+	private void ~SDayZPlayerHeadingModel() {}
+}
+
+
+// *************************************************************************************
+// ! DayZPlayer - mainly for logic and camera 
+// *************************************************************************************
+class SDayZPlayerAimingModel
+{
+	int 	m_iCamMode;				//[in]		- DayZPlayerConstants.CAMERAMODE_... HEAD,EXTERNAL,WEAPON...
+	int 	m_iCurrentCommandID;    //[in]		- Current Main Command ID 
+	float	m_fCurrentAimX;			//[in]		- horizontal aim angle - in degrees
+	float	m_fCurrentAimY;			//[in]		- vertical aim angle - in degrees
+
+	float	m_fAimXCamOffset;		//[out] 	- camera (angle) offset modifier
+	float	m_fAimYCamOffset;		//[out] 	- camera (angle) offset modifier
+	float	m_fAimXHandsOffset;		//[out] 	- hands offset modifier
+	float	m_fAimYHandsOffset;		//[out] 	- hands offset modifier
+	float	m_fAimXMouseShift;		//[out]		- shift like mouse does
+	float	m_fAimYMouseShift;		//[out]		- shift like mouse does
+	float 	m_fCamPosOffsetX;		//[out]		- camera (position) offset modifier
+	float 	m_fCamPosOffsetY;		//[out]		- camera (position) offset modifier
+	float 	m_fCamPosOffsetZ;		//[out]		- camera (position) offset modifier
+
+	//! cannot be created from script
+	private void SDayZPlayerAimingModel() {}
+	private void ~SDayZPlayerAimingModel() {}
+}
+
+#ifdef FEATURE_NETWORK_RECONCILIATION
+
+class DayZPlayerOwnerState : AnimPhysOwnerState
+{
+	proto native void	SetHeading(float value);
+	proto native float	GetHeading();
+
+	proto native void	SetHeadingVelocity(float value);
+	proto native float	GetHeadingVelocity();
+
+	proto native void	SetHeadingVelocityAlign(float value);
+	proto native float	GetHeadingVelocityAlign();
+
+	proto native void	SetHeadingTargetAlignVelocity(vector value);
+	proto native void	GetHeadingTargetAlignVelocity(out vector value);
+
+};
+
+class DayZPlayerMove : AnimPhysMove
+{
+	proto native void	SetHeading(float value);
+	proto native float	GetHeading();
+
+	//! Appropriately calls 'SetParent' and 'SetParentTransform' with the correct data
+	proto native void	UpdateParent(DayZPlayer player);
+
+	//! For use within 'DayZPlayer.ReplayAdditiveMove' on the 'other' move to signal if the base move had its parent changed
+	proto native bool	WasParentUpdated();
+	
+};
+
+#endif
+
+// *************************************************************************************
+// ! DayZPlayer - mainly for logic and camera 
+// *************************************************************************************
+class DayZPlayer extends Human
+{
+	const int 						SIMPLE_SELECTION_MELEE_RIFLE = 0;
+	const int 						SIMPLE_SELECTION_MELEE_MELEE = 1;
+	const int 						SIMPLE_SELECTION_SHOULDER_RIFLE = 2;
+	const int 						SIMPLE_SELECTION_SHOULDER_MELEE = 3;
+	
+	//! invokers
+	protected ref ScriptInvoker		m_OnDeathStart;
+	
+	//! returns appropriate DayZPlayerType
+	proto native DayZPlayerType		GetDayZPlayerType();
+	
+	proto native DayZPlayerInstanceType 	GetInstanceType();
+
+	override string GetDebugName()
+	{
+		string res = super.GetDebugName();
+		res += ":" + typename.EnumToString(DayZPlayerInstanceType, GetInstanceType());
+		return res;
+	}
+
+	//! ---------------- heading model -------------------------
+	//! updated each tick
+	//! this can limit / extend player's heading (orientation) behaviour in game 
+	
+	bool			HeadingModel(float pDt, SDayZPlayerHeadingModel pModel);	
+
+
+	//! ---------------- aiming model -------------------------
+
+	//! updated each tick - this takes care about aiming 
+	
+	bool			AimingModel(float pDt, SDayZPlayerAimingModel pModel);
+
+	
+	
+	//! ---------------- command handling -------------------------
+
+	//! updated each tick 
+	//! handles: starting new commands, canceling, interruption 
+	//! pDt 						- delta time 
+	//! pCurrentCommandID 			- actually running command's ID 
+	//! pCurrentCommandFinished		- is current command finished 
+	
+	void 			CommandHandler(float pDt, int pCurrentCommandID, bool pCurrentCommandFinished);	
+
+	//! ---------------- camera handling -------------------------
+
+	//! virtual 
+	//! returns registered camera type
+	//! pCameraMode - DayZPlayerConstants.CAMERAMODE_ ... 
+	int 			CameraHandler(int pCameraMode);
+
+
+	//! ---------------- camera additional functions -------------------------
+
+	//! gets current camera 
+	proto native 	DayZPlayerCamera		GetCurrentCamera();
+	
+	//! gets transform of current player camera
+	proto native 	void 					GetCurrentCameraTransform(out vector position, out vector direction, out vector rotation);
+
+	//! gets current camera 
+	proto native 	int 					GetCurrentPerItemCameraUD();
+	
+	proto native	bool					IsCameraBlending();
+
+
+	//! ---------------- animation graph functions -------------------------
+
+	//! functions usable only from CommandHandler
+	proto native void AnimCallCommand(int pCommand, int pParamInt, float pParamFloat);
+	proto native void AnimSetFloat(int pVar, float pFlt);
+	proto native void AnimSetInt(int pVar, int pInt);
+	proto native void AnimSetBool(int pVar, bool pBool);
+
+	//! ---------------- deterministic random numbers ------------------------
+
+	/**
+	\brief Random number in range of <0,0xffffffff> - !!! use this only during deterministic simulation (CommandHandler)
+	\return int value in range of <0,0xffffffff>
+	*/
+	proto native	int						Random();
+	
+	/**
+	\brief Random number in range of <0,pRange-1> - !!! use this only during deterministic simulation (CommandHandler)
+	@param pRange upper bounds of random number
+	\return int value in range of <0,pRange-1>
+	*/
+	proto native	float					RandomRange(int pRange);
+
+	/**
+	\brief Random number in range of <0,1> - !!! use this only during deterministic simulation (CommandHandler)
+	\return float value in range of <0,1>
+	*/
+	proto native	float					Random01();
+	
+	//! DEPRICATED(use GetEyeZoomLevel())  returns true if player is using EyeZoom, otherwise false
+	bool									IsEyeZoom();
+	//! returns eye zoom level, uses ECameraZoomType values
+	int 									GetEyeZoomLevel();
+	//! return true if shots are fired from camere, otherwise false
+	bool									IsShootingFromCamera();
+	//! return true if player is trying to hold breah, otherwise false
+	bool									IsHoldingBreath();
+	//! return true if player is currently performing FB gesture, otherwise false
+	bool									IsPerformingFBGesture();
+	//! return true if player is currently in 3pp, otherwise false
+	bool									IsInThirdPerson();
+
+	//! processes melee hit
+	proto native	MeleeCombatData			GetMeleeCombatData();
+
+	//! processes melee hit (uses component index)
+	proto native	void					ProcessMeleeHit(InventoryItem pMeleeWeapon, int pMeleeModeIndex, Object pTarget, int pComponentIndex, vector pHitWorldPos);
+	//! processes melee hit (uses component name)
+	proto native	void					ProcessMeleeHitName(InventoryItem pMeleeWeapon, int pMeleeModeIndex, Object pTarget, string pComponentName, vector pHitWorldPos);
+	
+	//! get reason for kickoff if available (server only)
+	proto native	EClientKicked			GetKickOffReason();
+	
+	//! ---------------- release controls -------------------------
+	proto native	void					ReleaseNetworkControls();
+	
+	//! ---------------- sync stuff -------------------------
+	
+	proto native	void					SendSyncJuncture(int pJunctureID, ParamsWriteContext ctx);
+	proto native	void					StoreInputForRemotes(ParamsWriteContext ctx);
+	
+	//! ---------------- sync shadow -------------------------
+
+
+	//! test if entity is DayZPlayer 
+	//static proto native bool				IsEntityDayZPlayer(IEntity pEntity);
+
+	//! 
+	proto native 	bool					DebugSyncShadowSetup(DayZPlayer pPlayer);
+	
+	//! sets look limits for a player
+	proto native 	void SetLookLimits(float pDown, float pUp, float pLeft, float pRight);
+	
+	//! returns look limits for a player
+	proto		 	void GetLookLimits(out float pDown, out float pUp, out float pLeft, out float pRight);
+
+	//! sets aim limits for a player
+	proto native 	void SetAimLimits(float pDown, float pUp, float pLeft, float pRight);
+	
+	//! returns aim limits for a player
+	proto			void GetAimLimits(out float pDown, out float pUp, out float pLeft, out float pRight);
+	
+	//! sets aim lower limit for a player
+	proto native 	void SetVerticalMinimumAimLimit(float value);
+	
+	void SetCurrentWaterLevel(float pWaterLevel);
+	float GetCurrentWaterLevel();
+
+
+	//! ---------------- camera additiona functions -------------------------
+	
+	
+	//! returns true if player is currently in one of the stances specified by stance mask 
+	//! IsPlayerInStance(STANCEMASK_ERECT | STANCEMASK_CROUCH) returns true if player is standing or crouching and not raised (aimed)
+	//! IsPlayerInStance(STANCEMASK_PRONE | STANCEIDX_RAISEDPRONE) returns true if player is in or in prone (both raised or nonraised)
+	//! IsPlayerInStance(STANCEMASK_ALL) returns true always 
+	//! IsPlayerInStance(STANCEMASK_RAISEDERECT | STANCEMASK_RAISEDCROUCH | STANCEMASK_RAISEDPRONE) returns true if player has raised hands
+	
+	// PSOVIS - move to native
+	bool		IsPlayerInStance(int pStanceMask)		// STANCEMASK_ERECT | STANCEMASK_CROUCH 
+	{
+		HumanMovementState		state = new HumanMovementState;
+		GetMovementState(state);
+		
+		bool ret = ((1 << state.m_iStanceIdx) & pStanceMask) != 0;
+		return ret;
+	}
+	
+	void OnInputForRemote (ParamsReadContext ctx) { }
+	void OnInputFromServer (ParamsReadContext ctx) { }
+	
+	//! ---------------- speaking anim -------------------------
+	
+	//! Check if player is using VoN to speak and return max amplitude from current samples
+	proto native	float	IsPlayerSpeaking();
+	
+	void UpdateDummyPlayerProxyVisibility(EntityAI shoulder, EntityAI melee)
+	{
+		/*EntityAI shoulder_item = FindAttachmentBySlotName("Shoulder");
+		EntityAI melee_item = FindAttachmentBySlotName("Melee");*/
+		bool boo;
+		
+		if ( melee )
+		{
+			boo = melee.IsWeapon();
+			SetSimpleHiddenSelectionState(SIMPLE_SELECTION_MELEE_RIFLE,boo);
+			SetSimpleHiddenSelectionState(SIMPLE_SELECTION_MELEE_MELEE,!boo);
+		}
+		if ( shoulder )
+		{
+			boo = shoulder.IsWeapon();
+			SetSimpleHiddenSelectionState(SIMPLE_SELECTION_SHOULDER_RIFLE,boo);
+			SetSimpleHiddenSelectionState(SIMPLE_SELECTION_SHOULDER_MELEE,!boo);
+		}
+	}
+	
+	//! ---------------- Forces player to stand up when swapping to heavy item -------------------------
+	void ForceStandUpForHeavyItems(notnull EntityAI item)
+	{
+		InventoryLocation il = new InventoryLocation;
+		if ( item.IsHeavyBehaviour() && IsPlayerInStance(DayZPlayerConstants.STANCEMASK_PRONE | DayZPlayerConstants.STANCEMASK_CROUCH))
+		{
+			HumanCommandMove cm = GetCommand_Move();
+			if (cm)
+			{
+				cm.ForceStance(DayZPlayerConstants.STANCEIDX_ERECT);
+			}
+		}
+	}
+	
+	void ForceStandUpForHeavyItemsSwap(notnull EntityAI item1, notnull EntityAI item2)
+	{
+		ForceStandUpForHeavyItems(item1);
+		ForceStandUpForHeavyItems(item2);
+	}
+	
+	void OnThrowingModeChange(bool change_to_enabled){}
+	
+	ScriptInvoker GetOnDeathStart()
+	{
+		if (!m_OnDeathStart)
+			m_OnDeathStart = new ScriptInvoker();
+
+		return m_OnDeathStart;
+	}
+	
+	override void OnCommandDeathStart()
+	{
+		if (m_OnDeathStart)
+			m_OnDeathStart.Invoke(this);
+	}
+}
+

+ 17 - 0
Scripts/3_game/debugweatherrpcdata.c

@@ -0,0 +1,17 @@
+class DebugWeatherRPCData
+{
+	float m_FogValue 				= -1;
+	float m_OvercastValue 			= -1;
+	float m_RainValue 				= -1;
+	float m_SnowfallValue			= -1;
+	
+	float m_FogInterpolation 		= 0;
+	float m_OvercastInterpolation 	= -1;
+	float m_RainInterpolation 		= -1;
+	float m_SnowfallInterpolation	= -1;
+	
+	float m_FogDuration 			= -1;
+	float m_OvercastDuration		= -1;
+	float m_RainDuration 			= -1;
+	float m_SnowfallDuration		= -1;
+}

+ 9 - 0
Scripts/3_game/econtrolschemestate.c

@@ -0,0 +1,9 @@
+enum EControlSchemeState
+{
+	None,
+	WeaponIronSight,
+	WeaponGun,
+	WeaponMelee,
+	VehicleDriver,
+	UI
+}

+ 619 - 0
Scripts/3_game/effect.c

@@ -0,0 +1,619 @@
+//! Enum to determine what type of effect the Effect is
+enum EffectType
+{
+	//! Plain Effect base
+	NONE,
+	//! EffectSound
+	SOUND,
+	//! EffectParticle
+	PARTICLE,
+}
+
+/**
+\brief Base wrapper class for managing effects (Particles, Sound) through SEffectManager
+	\note This is just a base class, not intended for direct usage
+*/
+class Effect : Managed
+{
+	/** \name Event invokers
+	*	ScriptInvonkers for certain events
+	*/
+	//@{
+	ref ScriptInvoker Event_OnStarted		= new ScriptInvoker();
+	ref ScriptInvoker Event_OnStopped		= new ScriptInvoker();
+	ref ScriptInvoker Event_OnEffectStarted		= new ScriptInvoker();
+	ref ScriptInvoker Event_OnEffectEnded		= new ScriptInvoker();
+	//@}
+	
+	/** \name Generic data
+	*	Generic data for the Effect
+	*/
+	//@{
+	//! Whether the Effect cleans up after itself when stopped
+	protected bool				m_IsAutodestroy;
+	//! Whether the Destroy process has already been called
+	protected bool				m_IsPendingDeletion;
+	//! Whether the Effect is currently playing
+	protected bool				m_IsPlaying;
+	//! Cached parent
+	protected Object 			m_ParentObject;
+	//! Cached world position
+	protected vector    		m_Position;
+	//@}
+	
+	/** \name SEffectManager data
+	*	Data filled in by SEffectManager to identify it when it is registered
+	*/
+	//@{
+	//! ID of effect, given by SEffectManager when registered (automatically done when playing through it)
+	protected int				m_ID;
+	//! Whether the effect is registered in SEffectManager
+	protected bool				m_IsRegistered;
+	//@}
+	
+	/** \name Attachment data
+	*	Cached settings set through 'SetAttachment...' methods
+	*	Does not necessarily reflect the current state when EffectParticle
+	*/
+	//@{	
+	//! Cached local pos
+	protected vector    		m_LocalPos;
+	//! Local orientation set by SetAttachedLocalOri, only used by EffectParticle
+	protected vector    		m_LocalOri;
+	//@}
+	
+	
+	
+	/**
+	\brief ctor
+	*/
+	void Effect()
+	{
+		if (GetGame().IsDedicatedServer())
+		{
+			ErrorEx("Created Effect on server.", ErrorExSeverity.WARNING);
+		}
+		
+		m_IsPlaying = false;
+		
+		InitEffect();
+	}
+	
+	/**
+	\brief dtor
+	*/
+	void ~Effect()
+	{
+		// Safety
+		if ( IsRegistered() )
+			SEffectManager.EffectUnregister(GetID());
+		
+		// Certain effects need to be stopped to clean up properly
+		Stop();
+		
+		// Another safety
+		SetEnableEventFrame(false);
+	}
+	
+	/**
+	\brief init
+	*/
+	void InitEffect()
+	{
+		Event_OnStarted.Insert(Event_OnEffectStarted);
+		Event_OnStarted.Insert(ValidateStart);
+		Event_OnStopped.Insert(Event_OnEffectEnded);
+	}
+	
+	
+	/** \name EffectType
+		Information about what type of effect the Effect is, without the need for casting
+	*/
+	//@{
+	
+	/**
+	\brief Get what type of effect the Effect is
+		\return \p EffectType What type of effect the Effect is
+	*/
+	EffectType GetEffectType()
+	{
+		return EffectType.NONE;
+	}
+	
+	/**
+	\brief Check whether the Effect is EffectSound without casting
+		\return \p bool Whether the Effect is EffectSound
+	*/
+	bool IsSound()
+	{
+		return false;
+	}
+	
+	/**
+	\brief Check whether the Effect is EffectParticle without casting
+		\return \p bool Whether the Effect is EffectParticle
+	*/
+	bool IsParticle()
+	{
+		return false;
+	}
+	
+	//@}
+	
+	
+	
+	/** \name Playback
+	*	Methods to Play/Stop Effect
+	*	Generally, SEffectManager.Play methods are used instead of Start
+	*/
+	//@{
+	
+	/**
+	\brief Plays all elements this effects consists of
+		\note Is called by SEffectManager.Play methods
+	*/
+    void Start()
+    {
+		// It is already playing!
+		if (IsPlaying())
+			return;
+		
+		Event_OnStarted();
+		// I can't call this from inside the method with same name
+		// because that method is often overriden without super......
+		Event_OnStarted.Invoke(this);		
+	}
+	
+	/**
+	\brief Validation whether an effect truly started playing or if the Effect should stop as none is present
+		\note Override this when inheriting to create own validation check
+		\note Is called from Event_OnStarted invoker after Event_OnStarted has been performed
+	*/
+	void ValidateStart()
+	{
+		
+	}
+	
+	/**
+	\brief Stops all elements this effect consists of
+		\note Alternatively use SEffectManager.Stop( effect_id )
+	*/
+    void Stop()
+    {
+		// It is not playing!
+		if (!IsPlaying())
+			return;
+		
+		Event_OnStopped();
+		// Yes, that event is new, but let's keep up some consistency
+		Event_OnStopped.Invoke(this);		
+    }
+	
+	/**
+	\brief Returns true when the Effect is playing, false otherwise
+	*/
+	bool IsPlaying()
+	{
+		return m_IsPlaying;
+	}
+	
+	//@}
+	
+	
+	
+	/** \name Destroy
+		Methods regarding automatic cleanup
+	*/
+	//@{
+	
+	/**
+	\brief Cleans up the Effect, including unregistering if needed
+		\note Will stop the Effect and queue up the deletion in the callqueue
+		\note Is intended for usage from within the Effect itself, use SEffectManager.DestroyEffect when working from a pointer
+	*/
+	protected void Destroy()
+	{
+		// Already queued
+		if (IsPendingDeletion())
+			return;
+		
+		// Mark it to prevent queuing it up multiple times or get stuck in a call loop
+		m_IsPendingDeletion = true;
+		
+		// Stop it, so that the effects can clean up themselves
+		// Since if for example this is EffectParticle and the particle is looping
+		// It NEEDS to be stopped to clean up the Particle
+		Stop();
+		
+		// Queue up the destroying, as we should not do it while we are accessing it here
+		if (GetGame())
+		{
+			GetGame().GetCallQueue(CALL_CATEGORY_GAMEPLAY).Call(SEffectManager.DestroyEffect, this);
+		}
+	}
+	
+	/**
+	\brief Sets whether Effect automatically cleans up when it stops
+		\note This means that it will be unregistered from SEffectManager as well
+		\param auto_destroy \p bool Whether Effect automatically cleans up when it stops
+	*/
+	void SetAutodestroy(bool auto_destroy)
+	{
+		m_IsAutodestroy = auto_destroy;
+	}
+	
+	/**
+	\brief Get whether Effect automatically cleans up when it stops
+		\return \p bool Whether Effect automatically cleans up when it stops
+	*/
+	bool IsAutodestroy()
+	{
+		return m_IsAutodestroy;
+	}
+	
+	/**
+	\brief Get whether the Effect is queued up for being cleaned up
+		\return \p bool Whether the Effect is queued up for being cleaned up
+	*/
+	bool IsPendingDeletion()
+	{
+		return m_IsPendingDeletion;
+	}
+	
+	/**
+	\brief Get whether the Effect can be destroyed right now
+		\return \p bool Whether the Effect can be destroyed right now
+	*/
+	bool CanDestroy()
+	{
+		return true;
+	}
+	
+	//@}
+	
+	
+	
+	/**
+	\brief Enable Event_OnFrameUpdate for the effect
+		\note Read SEffectManager.Event_OnFrameUpdate for more info
+	*/
+	void SetEnableEventFrame(bool enable)
+	{
+		if ( enable )
+		{
+			SEffectManager.Event_OnFrameUpdate.Insert(Event_OnFrameUpdate);			
+		}
+		else
+		{
+			SEffectManager.Event_OnFrameUpdate.Remove(Event_OnFrameUpdate);
+		}
+	}
+	
+	
+	
+	/** \name Events
+		Various events that can be overriden for custom behaviour
+	*/
+	//@{
+	
+	/**
+	\brief Event used when Start was called
+	*/
+	void Event_OnStarted()
+	{
+		// Override this method for own use
+	}
+	
+	/**
+	\brief Event used when Stop was called
+	*/
+	void Event_OnStopped()
+	{
+		// Override this method for own use
+	}
+	
+	/**
+	\brief Event used when the actual effect started playing
+	*/
+	void Event_OnEffectStarted()
+	{
+		m_IsPlaying = true;
+		
+		Event_OnEffectStarted.Invoke(this);
+	}
+	
+	/**
+	\brief Event used when the actual effect stopped playing
+	*/
+	void Event_OnEffectEnded()
+	{
+		m_IsPlaying = false;
+		
+		Event_OnEffectEnded.Invoke(this);
+		
+		if ( IsAutodestroy() )
+		{
+			Destroy();
+		}
+	}
+	
+	/**
+	\brief Event called on frame when enabled by SetEnableEventFrame(true)
+		\note Called from SEffectManager.Event_OnFrameUpdate in MissionGameplay.OnUpdate
+		\param time_delta \p float Time passed since the previous frame
+	*/
+	void Event_OnFrameUpdate(float time_delta)
+	{
+		// Override this method for own use
+	}
+	
+	/**
+	\brief Event called from SEffectManager when the Effect is registered
+		\note Should only ever be called by SEffectManager!
+		\param id \p int ID registered in SEffectManager
+	*/
+	void Event_OnRegistered(int id)
+	{
+		SetID(id);
+		m_IsRegistered = true;
+	}
+	
+	/**
+	\brief Event called from SEffectManager when the Effect is unregistered
+		\note Should only ever be called by SEffectManager!
+	*/
+	void Event_OnUnregistered()
+	{
+		SetID(SEffectManager.INVALID_ID);
+		m_IsRegistered = false;
+	}
+	
+	/**
+	\brief Event used when EffectParticle.CheckLifeSpan was called (DEPRECATED)
+		\note So this is EffectParticle specific...
+		\note EffectParticle.CheckLifeSpan is currently not in use
+	*/
+	void OnCheckUpdate()
+	{
+
+	}
+	
+	//@}
+	
+	
+	
+	/** \name Generic API
+		Setters and getters for generic data and properties
+	*/
+	//@{
+	
+	/**
+	\brief Set parent of the Effect
+		\note Same as SetAttachmentParent, but more generic name
+		\warning Only sets the cached variable, for immediate effect use SetCurrent variant
+		\param parent_obj \p Object The parent for the Effect
+	*/
+	void SetParent(Object parent_obj)
+	{
+		m_ParentObject = parent_obj;
+	}
+	
+	/**
+	\brief Get parent of the Effect
+		\note Same as GetAttachmentParent, but more generic name
+		\warning Only gets the cached variable, for immediate effect use GetCurrent variant
+		\return \p Object The parent of the Effect
+	*/
+	Object GetParent()
+	{
+		return m_ParentObject;
+	}
+	
+	/**
+	\brief Set current parent of the managed effect
+		\note Same as SetAttachmentParent, but more generic name
+		\param parent_obj \p Object The parent for the Effect
+		\param updateCached \p bool Whether to update the cached variable
+	*/
+	void SetCurrentParent( Object parent_obj, bool updateCached = true )
+	{
+		if (updateCached)
+			SetParent(parent_obj);
+	}
+	
+	/**
+	\brief Get the current parent of the managed Effect
+		\return \p Object The current parent of the managed Effect
+	*/
+	Object GetCurrentParent()
+	{
+		return null;
+	}
+	
+	/**
+	\brief Set the world position of the Effect
+		\warning Only sets the cached variable, for immediate effect use SetCurrent variant
+		\param pos \p vector The world position for the Effect
+	*/
+	void SetPosition( vector pos )
+    {
+        m_Position = pos;
+    }
+
+	/**
+	\brief Get the world position of the Effect
+		\warning Only gets the cached variable, for immediate effect use GetCurrent variant
+		\return \p vector The world position of the Effect
+	*/
+	vector GetPosition()
+	{
+		return m_Position;
+	}
+	
+	/**
+	\brief Set the current world position of the managed effect
+		\param pos \p vector The current world position for the Effect
+		\param updateCached \p bool Whether to update the cached variable
+	*/
+	void SetCurrentPosition( vector pos, bool updateCached = true )
+    {
+		if (updateCached)
+        	SetPosition(pos);
+    }
+	
+	/**
+	\brief Get the current world position of the managed effect
+		\return \p vector The current world position of the managed effect
+	*/
+	vector GetCurrentPosition()
+	{
+		return vector.Zero;
+	}
+	
+	/**
+	\brief Set the local position of the Effect
+		\warning Only sets the cached variable, for immediate effect use SetCurrent variant
+		\param pos \p vector The local position for the Effect
+	*/
+	void SetLocalPosition( vector pos )
+    {
+		m_LocalPos = pos;
+    }
+
+	/**
+	\brief Get the local position of the Effect
+		\warning Only gets the cached variable, for immediate effect use GetCurrent variant
+		\return \p vector The lcoal position of the Effect
+	*/
+	vector GetLocalPosition()
+	{
+		return m_LocalPos;
+	}
+	
+	/**
+	\brief Set the current local position of the managed effect
+		\param pos \p vector The current local position for the managed effect
+		\param updateCached \p bool Whether to update the cached variable
+	*/
+	void SetCurrentLocalPosition( vector pos, bool updateCached = true )
+    {
+		if (updateCached)
+        	SetLocalPosition(pos);
+    }
+
+	/**
+	\brief Get the current local position of the managed effect
+		\return \p vector The current local position of the managed effect
+	*/
+	vector GetCurrentLocalPosition()
+	{
+		return vector.Zero;
+	}
+	
+	//@}
+	
+	
+	
+	/** \name Effect ID
+		The ID of the effect when registered in SEffectManager
+	*/
+	//@{
+	
+	/**
+	\brief Set the ID registered in SEffectManager
+		\note Should only ever be called by Event_OnRegistered!
+		\param id \p int ID registered in SEffectManager
+	*/
+	protected void SetID(int id)
+	{
+		m_ID = id;
+	}
+	
+	/**
+	\brief Get the ID registered in SEffectManager
+		\return \p int ID registered in SEffectManager, or 0 (SEffectManager.INVALID_ID) when not registered
+	*/
+	int GetID()
+	{
+		return m_ID;
+	}
+	
+	/**
+	\brief Get whether this Effect is registered in SEffectManager
+		\return \p bool Whether this Effect is registered in SEffectManager
+	*/
+	bool IsRegistered()
+	{
+		return m_IsRegistered;
+	}
+	
+	//@}
+	
+	
+	
+	/** \name Attachment API
+	*	Data to attach an Effect to a parent
+	*	Mostly replaced by equivalents without 'Attachment' in name
+	*	Mildly deprecated, exist for backwards compatibility
+	*/
+	//@{
+	
+	/**
+	\brief Set parent for the Effect
+		\param obj \p Object The parent for the Effect
+	*/
+	void SetAttachmentParent(Object obj)
+	{
+		SetParent(obj);
+	}
+		
+	/**
+	\brief Get the parent set by SetAttachmentParent
+		\return \p Object The parent set by SetAttachmentParent
+	*/
+	Object GetAttachmentParent()
+	{
+		return GetParent();
+	}
+	
+	/**
+	\brief Set local pos for the Effect relative to the parent
+		\param pos \p vector The local pos relative to the parent
+	*/
+	void SetAttachedLocalPos(vector pos)
+	{
+		SetLocalPosition(pos);
+	}
+	
+	/**
+	\brief Get the local pos set by SetAttachedLocalPos
+		\return \p vector The local pos set by SetAttachedLocalPos
+	*/
+	vector GetAttachedLocalPos()
+	{
+		return GetLocalPosition();
+	}
+	
+	/**
+	\brief Set local orientation for the Effectparticle to attach to when the Effect is started
+		\warning Only caches it into a variable to be used by Start, does not live update when called afterwards
+		\note Overrides the orientation set by EffectParticle.SetOrientation
+		\param ori \p vector The local orientation to use on Start
+	*/
+	void SetAttachedLocalOri(vector ori)
+	{
+		m_LocalOri = ori;
+	}
+	
+	/**
+	\brief Get the local orientation set by SetAttachedLocalOri
+		\warning Is not necessarily the current local orientation
+		\return \p vector The local orientation set by SetAttachedLocalOri
+	*/
+	vector GetAttachedLocalOri()
+	{
+		return m_LocalOri;
+	}
+	
+	//@}
+}

+ 875 - 0
Scripts/3_game/effectmanager.c

@@ -0,0 +1,875 @@
+/**
+\brief Manager class for managing Effect (EffectParticle, EffectSound)
+	\warning Keeps a ref to any Effect registered (Created/Played), make sure to perform the necessary cleanup
+*/
+class SEffectManager
+{
+	//! Static map of all registered effects <id, Effect>
+	protected static ref map<int, ref Effect> m_EffectsMap;
+	//! Static array of IDs that were previously used, but freed up by unregistering
+	protected static ref array<int> m_FreeEffectIDs;
+	//! Counter for quickly getting the next ID if FreeEffectIDs array is empty
+	protected static int m_HighestFreeEffectID = 1;
+	//! As the counter starts at 1, Effect ID can never be 0
+	static const int INVALID_ID = 0;
+	//! Bool to check whether Cleanup is happening, which means that the maps should no longer be accessed
+	protected static bool m_IsCleanup;
+	//! Bool to check whether Init was called
+	protected static bool m_IsInitialized;
+	
+	//! Static map of cached sound params, to prevent having to recreate them
+	protected static ref map<string, ref SoundParams> m_ParamsMap;
+	
+	//! Static invoker for the SEffectManager.Event_OnFrameUpdate called form MissionGameplay.OnUpdate
+	static ref ScriptInvoker Event_OnFrameUpdate;
+	
+	protected static ref map<int, EffecterBase> m_EffectersMap;
+	//! Static array of IDs that were previously used, but freed up by unregistering Effecters
+	protected static ref array<int> m_FreeEffecterIDs;
+	
+	protected static int m_HighestFreeEffecterID = 1;
+	
+	/** \name Generic playback
+ 		Methods for playing Effect
+		\note Since 1.15, these should work on EffectSound as well
+	*/
+	//@{
+	
+	/**
+	*\brief Play an Effect
+	*	\warning As the Effect is automatically registered, it will not be freed automatically (because of the ref)
+	*				Unless 'SetAutodestroy(true)' is called on the created 'Effect', which will clean it up when the sound stop
+	*				Alternatively, SEffectManager.DestroyEffect can be called manually, which will also unregister and cleanup
+	*	\param eff \p Effect The Effect to play
+	*	\param pos \p vector The position to play the Effect
+	*	\return \p int The registered ID of the Effect
+	*/
+	static int PlayInWorld(notnull Effect eff, vector pos)
+	{
+		// Stop the effect first, just in case
+		eff.Stop();
+		
+		int id = EffectRegister(eff);
+		
+		eff.SetPosition( pos );
+		eff.Start();	
+		
+		return id;
+	}
+	
+	/**
+	*\brief Play an Effect
+	*	\warning Read PlayInWorld warning
+	*	\param eff \p Effect The Effect to play
+	*	\param obj \p Object The parent of the Effect
+	*	\param local_pos \p vector The local position to play the Effect in relation to the parent (Optional)
+	*	\param local_ori \p vector The local orientation to play the Effect in relation to the parent (Optional)
+	*	\param force_rotation_relative_to_world \p bool Whether to force the orientation to stay in WS (Optional)
+	*	\return \p int The registered ID of the Effect
+	*/
+	static int PlayOnObject(notnull Effect eff, Object obj, vector local_pos = "0 0 0", vector local_ori = "0 0 0", bool force_rotation_relative_to_world = false)
+	{
+		// Stop the effect first, just in case
+		eff.Stop();
+		
+		int id = EffectRegister(eff);
+		
+		if (!obj)
+		{
+			ErrorEx("Parent object is null.", ErrorExSeverity.WARNING);
+			eff.SetPosition(local_pos);
+		}
+		else
+		{
+			eff.SetPosition(obj.GetPosition());
+		}
+			
+		eff.SetParent(obj);
+		eff.SetLocalPosition(local_pos);
+		eff.SetAttachedLocalOri(local_ori);
+		
+		if (force_rotation_relative_to_world)
+		{
+			EffectParticle eff_particle = EffectParticle.Cast(eff);
+			
+			if (eff_particle)
+			{
+				eff_particle.ForceParticleRotationRelativeToWorld(force_rotation_relative_to_world);
+			}
+		}
+		
+		eff.Start();
+		
+		return id;
+	}
+	
+	/**
+	\brief Stops the Effect
+		\param effect_id \p int The ID of the Effect to Stop
+	*/
+	static void Stop(int effect_id)
+	{
+		Effect eff = m_EffectsMap.Get(effect_id);
+		
+		if (eff)
+		{
+			eff.Stop();
+		}
+		else
+		{
+			ErrorEx(string.Format("Failed to stop Effect with ID %1. The ID is not registered in m_EffectsMap!", effect_id));
+		}
+	}
+	
+	//@}
+	
+
+	
+	/** \name Create/Play sound
+ 		Methods for playing/creating sound
+	*/
+	//@{
+	
+	/**
+	*\brief Create an EffectSound
+	*	\warning Read PlayInWorld warning
+	*	\param sound_set \p string The sound set name of the sound
+	*	\param position \p vector The position to play the sound
+	*	\param play_fade_in \p float The fade in duration of the sound (Optional)
+	*	\param stop_fade_out \p float The fade out duration of the sound (Optional)
+	*	\param loop \p bool Whether the sound should loop (Optional)
+	*	\param enviroment \p bool Whether to set environment variables (Optional)
+	*	\return \p EffectSound The created EffectSound
+	*/
+	static EffectSound CreateSound(string sound_set, vector position, float play_fade_in = 0, float stop_fade_out = 0, bool loop = false, bool enviroment = false)
+	{
+		EffectSound effect_sound = new EffectSound();
+		effect_sound.SetSoundSet(sound_set);
+		effect_sound.SetPosition(position);
+		effect_sound.SetSoundFadeIn(play_fade_in);
+		effect_sound.SetSoundFadeOut(stop_fade_out);
+		effect_sound.SetSoundLoop(loop);
+		effect_sound.SetEnviromentVariables(enviroment);
+		
+		EffectRegister( effect_sound );
+		
+		return effect_sound;
+	}
+	
+	/**
+	*\brief Create and play an EffectSound
+	*	\warning Calls CreateSound, read CreateSound warning
+	*	\param sound_set \p string The sound set name of the sound
+	*	\param position \p vector The position to play the sound
+	*	\param play_fade_in \p float The fade in duration of the sound (Optional)
+	*	\param stop_fade_out \p float The fade out duration of the sound (Optional)
+	*	\param loop \p bool Whether the sound should loop (Optional)
+	*	\return \p EffectSound The created EffectSound
+	*/
+	static EffectSound PlaySound(string sound_set, vector position, float play_fade_in = 0, float stop_fade_out = 0, bool loop = false)
+	{
+		EffectSound effect_sound = CreateSound(sound_set, position, play_fade_in, stop_fade_out, loop, false);
+				
+		effect_sound.SoundPlay();
+		
+		return effect_sound;
+	}
+	
+	/**
+	*\brief Create and play an EffectSound
+	*	\warning Calls CreateSound, read CreateSound warning
+	*	\param params \p SoundParams Params to create the sound with
+	*	\param position \p vector The position to play the sound
+	*	\param play_fade_in \p float The fade in duration of the sound (Optional)
+	*	\param stop_fade_out \p float The fade out duration of the sound (Optional)
+	*	\param loop \p bool Whether the sound should loop (Optional)
+	*	\return \p EffectSound The created EffectSound
+	*/
+	static EffectSound PlaySoundParams(notnull SoundParams params, vector position, float play_fade_in = 0, float stop_fade_out = 0, bool loop = false)
+	{
+		EffectSound effect_sound = CreateSound(params.GetName(), position, play_fade_in, stop_fade_out, loop, false);
+
+		effect_sound.SoundPlayEx(params);
+		
+		return effect_sound;
+	}
+	
+	/**
+	*\brief Create and play an EffectSound, using or creating cached SoundParams
+	*	\warning Calls CreateSound, read CreateSound warning
+	*	\param sound_set \p string The sound set name of the sound
+	*	\param position \p vector The position to play the sound
+	*	\param play_fade_in \p float The fade in duration of the sound (Optional)
+	*	\param stop_fade_out \p float The fade out duration of the sound (Optional)
+	*	\param loop \p bool Whether the sound should loop (Optional)
+	*	\return \p EffectSound The created EffectSound
+	*/
+	static EffectSound PlaySoundCachedParams(string sound_set, vector position, float play_fade_in = 0, float stop_fade_out = 0, bool loop = false)
+	{
+		SoundParams params = GetCachedSoundParam(sound_set);
+		
+		EffectSound effect_sound = CreateSound(params.GetName(), position, play_fade_in, stop_fade_out, loop, false);
+
+		effect_sound.SoundPlayEx(params);
+		
+		return effect_sound;
+	}
+	
+	/**
+	*\brief Create and play an EffectSound, updating environment variables
+	*	\warning Calls CreateSound, read CreateSound warning
+	*	\param sound_set \p string The sound set name of the sound
+	*	\param position \p vector The position to play the sound
+	*	\param play_fade_in \p float The fade in duration of the sound (Optional)
+	*	\param stop_fade_out \p float The fade out duration of the sound (Optional)
+	*	\param loop \p bool Whether the sound should loop (Optional)
+	*	\return \p EffectSound The created EffectSound
+	*/
+	static EffectSound PlaySoundEnviroment(string sound_set, vector position, float play_fade_in = 0, float stop_fade_out = 0, bool loop = false)
+	{
+		EffectSound effect_sound = CreateSound(sound_set, position, play_fade_in, stop_fade_out, loop, true);
+				
+		effect_sound.SoundPlay();
+		
+		return effect_sound;
+	}
+	
+	/**
+	*\brief Create and play an EffectSound
+	*	\warning Calls CreateSound, read CreateSound warning
+	*	\param sound_set \p string The sound set name of the sound
+	*	\param parent_object \p Object The parent Object for the sound to follow
+	*	\param play_fade_in \p float The fade in duration of the sound (Optional)
+	*	\param stop_fade_out \p float The fade out duration of the sound (Optional)
+	*	\param loop \p bool Whether the sound should loop (Optional)
+	*	\return \p EffectSound The created EffectSound
+	*/
+	static EffectSound PlaySoundOnObject(string sound_set, Object parent_object, float play_fade_in = 0, float stop_fade_out = 0, bool loop = false)
+	{
+		EffectSound effect_sound = CreateSound(sound_set, parent_object.GetPosition(), play_fade_in, stop_fade_out, loop);
+		
+		effect_sound.SetParent( parent_object );
+		effect_sound.SetLocalPosition( vector.Zero );
+		effect_sound.SoundPlay();
+		
+		return effect_sound;
+	}
+	
+	//@}
+	
+	
+	
+	/** \name Generic API
+		General methods used for SEffectManager
+	*/
+	//@{
+	
+	/**
+	\brief Unregisters, stops and frees the Effect
+		\param effect_sound \p EffectSound The EffectSound to free
+	*/
+	static void DestroyEffect(Effect effect)
+	{
+		if (effect)
+		{
+			if (effect.CanDestroy())
+			{
+				// Functionality already happens in dtor of Effect to be safe
+				delete effect;
+			}
+			else
+			{
+				// Make it clean up itself when done
+				effect.SetAutodestroy(true);
+				effect.Stop();
+			}
+		}
+	}
+	
+	/**
+	\brief Checks whether an Effect ID is registered in SEffectManager
+		\param effect_id \p int The Effect ID to check
+		\return \p bool Whether there is an Effect registered for this ID
+	*/
+	static bool IsEffectExist( int effect_id )
+	{
+		if (!m_IsCleanup)
+			return m_EffectsMap[effect_id] != null;
+		else
+			return false;
+	}
+			
+	/**
+	\brief Gets the Effect with the given registered Effect ID
+		\param effect_id \p int The Effect ID
+		\return \p Effect The Effect registered to the ID or null
+	*/
+	static Effect GetEffectByID(int effect_id)
+	{
+		if (!m_IsCleanup)
+			return m_EffectsMap[effect_id];
+		else
+			return null;
+	}
+	
+	/**
+	\brief Registers Effect in SEffectManager
+		\note Already handled in SEffectManager Create/Play methods
+		\note This will make SEffectManager hold a strong ref for the Effect
+		\param effect \p Effect The Effect to register
+		\return \p int The Effect ID
+	*/
+	static int EffectRegister(Effect effect)
+	{
+		if (effect.IsRegistered())
+		{
+			ErrorEx(string.Format("Attempted to register Effect '%1' which was already registered.", effect.GetDebugName()), ErrorExSeverity.INFO);			
+			return effect.GetID();
+		}
+		
+		int id;
+		
+		if (!m_IsCleanup)
+		{
+			id = GetFreeEffectID();
+			m_EffectsMap.Insert(id, effect);
+			effect.Event_OnRegistered(id);
+		}
+		else
+			ErrorEx("Attempted to register Effect while SEffectManager is cleaning up, request ignored.", ErrorExSeverity.WARNING);
+		
+		return id;
+	}
+	
+	protected static int GetFreeEffecterID()
+	{
+		int return_id;
+		
+		if (m_FreeEffecterIDs.Count() > 0)
+		{
+			return_id = m_FreeEffecterIDs.Get(0);
+			m_FreeEffecterIDs.Remove(0);
+		}
+		else
+		{
+			return_id = m_HighestFreeEffecterID;
+			++m_HighestFreeEffecterID;
+		}
+		
+		return return_id;		
+	}
+	
+	/**
+	\brief Unregisters Effect in SEffectManager
+		\note Will automatically occur on stop when the Effect is AutoDestroy
+		\note ID can be gotten from the Effect by calling Effect.GetID
+		\note Generic Play methods will also return the ID
+		\param id \p int The ID of the Effect to unregister
+	*/
+	static void EffectUnregister(int id)
+    {
+		if (m_IsCleanup)
+			return; // No error needed, since it will have been unregistered anyways after cleanup is finished
+		
+		Effect effect;
+		if ( m_EffectsMap.Find(id, effect) )
+		{
+			effect.Event_OnUnregistered();
+			m_EffectsMap.Remove(id);
+		}		
+		
+		if ( m_FreeEffectIDs.Find(id) == -1 )
+		{
+			m_FreeEffectIDs.Insert(id);
+		}
+    }
+	
+	/**
+	\brief Unregisters Effect in SEffectManager
+		\param effect \p Effect The Effect to unregister
+	*/
+	static void EffectUnregisterEx(Effect effect)
+    {
+		EffectUnregister(effect.GetID());
+    }
+	
+	/**
+	\brief Helper function for EffectRegister to decide an Effect ID
+		\return \p int A currently unused Effect ID
+	*/
+	protected static int GetFreeEffectID()
+	{
+		int return_id;
+		
+		if (m_FreeEffectIDs.Count() > 0)
+		{
+			return_id = m_FreeEffectIDs.Get(0);
+			m_FreeEffectIDs.Remove(0);
+		}
+		else
+		{
+			return_id = m_HighestFreeEffectID;
+			++m_HighestFreeEffectID;
+		}
+		
+		return return_id;		
+	}
+	
+	//@}
+	
+	
+	
+	/** \name Sound helpers
+ 		Sound specific helper methods
+	*/
+	//@{
+	
+	/**
+	\brief Legacy, backwards compatibility
+		\param sound_effect \p EffectSound The EffectSound to free
+		\return \p bool A bool which is always true
+	*/
+	static bool DestroySound(EffectSound sound_effect)
+	{
+		DestroyEffect(sound_effect);		
+		return true;
+	}
+	
+	/**
+	\brief Get or create a cached SoundParams object
+		\param soundset \p string The sound set name of the sound
+		\return \p SoundParams The cached SoundParams for the given soundset
+	*/
+	static SoundParams GetCachedSoundParam(string soundset)
+	{
+		SoundParams params;
+		if (!m_ParamsMap.Find(soundset, params))
+		{
+			params = new SoundParams(soundset);
+			m_ParamsMap.Insert(soundset, params);
+		}
+		return params;
+	}
+	
+	//@}
+	
+	
+	
+	/** \name Events
+		Various events that can be overriden for custom behaviour
+	*/
+	//@{
+	
+	/**
+	\brief Event called from EffectSound.Event_OnSoundWaveEnded
+		\note Every registered sound is registered to call this
+		\param effect_sound \p EffectSound The EffectSound calling the event
+	*/
+	static void Event_OnSoundWaveEnded(EffectSound effect_sound)
+	{
+		
+	}
+	
+	/**
+	\brief Event called on frame
+		\note Called from MissionGameplay.OnUpdate
+		\note Effects register themselves by Effect.SetEnableEventFrame(true)
+		\note EffectSound is automatically registered
+		\param time_delta \p float Time passed since the previous frame
+	*/
+	static void Event_OnFrameUpdate(float time_delta)
+	{
+		Event_OnFrameUpdate.Invoke(time_delta);
+	}
+	
+	//@}
+	
+	
+	
+	/** \name Lifetime
+ 		Creation and cleanup
+	*/
+	//@{
+	
+	/**
+	\brief Initialize the containers
+		\note This is done this way, to have these not exist on server
+	*/
+	static void Init()
+	{
+		m_EffectsMap = new map<int, ref Effect>;
+		m_FreeEffectIDs = new array<int>;
+		m_ParamsMap = new map<string, ref SoundParams>;
+		Event_OnFrameUpdate = new ScriptInvoker();
+		
+		m_IsInitialized = true;
+	}
+	
+	static void InitServer()
+	{
+		m_EffectersMap = new map<int, EffecterBase>;
+		m_FreeEffecterIDs = new array<int>;
+	}
+	
+	/**
+	\brief Cleanup method to properly clean up the static data
+		\note Will be called when MissionBase is destroyed
+	*/
+	static void Cleanup()
+	{
+		// Nothing to clean
+		if (!m_IsInitialized)
+			return;		
+		
+		m_IsCleanup = true;
+		
+		// There should not be anything in here on server
+		if (GetGame() && GetGame().IsDedicatedServer())
+		{
+			if (m_ParamsMap.Count() > 0)
+				ErrorEx(string.Format("SEffectManager containing SoundParams on server."), ErrorExSeverity.WARNING);
+			
+			if (m_EffectsMap.Count() > 0)
+				ErrorEx(string.Format("SEffectManager containing Effect on server."), ErrorExSeverity.WARNING);
+		}
+		
+		// These are intentionally cached, just clear them
+		m_ParamsMap.Clear();
+		
+		// These might not be intentionally still here, so log how many there are
+		#ifdef DEVELOPER
+		Print("--- SEffectManager Cleanup dump - Begin ------------------------");
+		Print(string.Format("Effect count: %1", m_EffectsMap.Count()));
+		#endif
+		
+		// Best to call the unregister event before clearing the map
+		// In case some ref is still being held elsewhere and will still be kept alive
+		foreach (int id, Effect eff : m_EffectsMap)
+		{
+			eff.Event_OnUnregistered();
+			#ifdef SFXM_DUMP
+			Print(string.Format( "%1 :: %2 :: %3", eff, typename.EnumToString(EffectType, eff.GetEffectType()), eff.GetDebugName() ));
+			#endif
+		}
+		
+		foreach (int i, EffecterBase effecter : m_EffectersMap)
+		{
+			effecter.Delete();
+		}
+		
+		#ifdef DEVELOPER
+		Print("--- SEffectManager Cleanup dump - End --------------------------");
+		#endif
+		
+		// Now we can clear it
+		m_EffectsMap.Clear();
+		m_EffectersMap.Clear();
+		
+		// Reset the state
+		m_HighestFreeEffectID = 1;		
+		Event_OnFrameUpdate.Clear();
+		m_IsCleanup = false;
+	}
+	
+	//@}
+	
+	//! returns unique effecter ID
+	static int CreateParticleServer(vector pos, EffecterParameters parameters)
+	{
+		EffecterBase eff;
+		eff = EffecterBase.Cast(GetGame().CreateObjectEx(parameters.m_EffecterType, pos, ECE_PLACE_ON_SURFACE));
+		
+		if (eff)
+		{
+			int id = GetFreeEffecterID();
+			m_EffectersMap.Insert(id, eff);
+		}
+		
+		eff.Init(id, parameters);
+		return id;
+	}
+	
+	//! allows re-initializing existing effecter with new parameters (extept m_EffecterType, obviously)
+	static void ReinitParticleServer(int effecterID, EffecterParameters parameters)
+	{
+		EffecterBase eff = m_EffectersMap.Get(effecterID);
+		if (eff)
+		{
+			eff.Init(effecterID,parameters);
+		}
+	}
+	
+	static void ReactivateParticleServer(int effecterID)
+	{
+		EffecterBase eff = m_EffectersMap.Get(effecterID);
+		if (eff)
+		{
+			eff.Reactivate();
+		}
+	}
+	
+	static void StartParticleServer(int effecterID)
+	{
+		EffecterBase eff = m_EffectersMap.Get(effecterID);
+		if (eff)
+		{
+			eff.Start();
+		}
+		
+	}
+	
+	static void StopParticleServer(int effecterID)
+	{
+		EffecterBase eff = m_EffectersMap.Get(effecterID);
+		if (eff)
+		{
+			eff.Stop();
+		}	
+	}
+	
+	static void DestroyEffecterParticleServer(int effecterID)
+	{
+		EffecterBase eff = m_EffectersMap.Get(effecterID);
+		if (eff)
+		{
+			m_EffectersMap.Remove(effecterID);
+			eff.DeleteSafe();
+		}
+	}
+	
+	static void OnUpdate(float timeslice)
+	{
+		if (m_EffectersMap)
+		{
+			foreach (int i, EffecterBase effecter : m_EffectersMap)
+			{
+				effecter.DecreaseLifespan(timeslice);
+			}
+		}
+	}
+}
+
+enum EffecterCommands
+{
+	NONE = -1,
+	START,
+	STOP,
+	REACTIVATE0,
+	REACTIVATE1
+}
+	
+class EffecterParameters
+{		
+	string m_EffecterType;
+	float m_Lifespan;
+	void EffecterParameters(string type, float lifespan)
+	{
+		m_EffecterType = type;
+		m_Lifespan = lifespan;
+	}
+}
+
+class ParticleEffecterParameters : EffecterParameters
+{
+	int m_ParticleID;
+	void ParticleEffecterParameters(string type, float lifespan, int particleID)
+	{
+		m_ParticleID = particleID;
+	}
+}
+
+
+class EffecterBase : EntityAI
+{
+	const float NOT_DEFINED_LIFESPAN = -1;
+	protected float m_Lifespan;
+	protected int m_ID;
+	protected int m_Command = EffecterCommands.NONE;
+	protected int m_CommandSync = EffecterCommands.NONE;
+	
+	void EffecterBase()
+	{
+		RegisterNetSyncVariableInt("m_CommandSync");
+	}
+	
+	void Init(int id, EffecterParameters parameters)
+	{
+		m_ID = id;
+		SetLifespan(parameters.m_Lifespan);
+	}
+	
+	void DecreaseLifespan(float timeSlice)
+	{
+		if (m_Lifespan == NOT_DEFINED_LIFESPAN)
+			return;
+		
+		m_Lifespan -= timeSlice;
+		if (m_Lifespan < 0)
+		{
+			SEffectManager.DestroyEffecterParticleServer(m_ID);
+		}
+	}
+	
+	void SetLifespan(float lifespan)
+	{
+		m_Lifespan = lifespan;
+	}
+	
+	void Start()
+	{
+		m_CommandSync = EffecterCommands.START;
+		Process();
+	}
+	
+	void Stop()
+	{
+		m_CommandSync = EffecterCommands.STOP;
+		Process();
+	}
+	
+	void Reactivate()
+	{
+		if (m_CommandSync == EffecterCommands.REACTIVATE0)
+		{
+			m_CommandSync = EffecterCommands.REACTIVATE1;
+		}
+		else
+		{
+			m_CommandSync = EffecterCommands.REACTIVATE0;
+		}
+		Process();
+	}
+	
+	void Process()
+	{
+		if (GetGame().IsMultiplayer())
+		{
+			SetSynchDirty();
+		}
+		else
+		{
+			OnVariablesSynchronized();
+		}
+	}
+	
+	override int GetHideIconMask()
+	{
+		return EInventoryIconVisibility.HIDE_VICINITY;
+	}
+}
+
+class ParticleEffecter : EffecterBase
+{
+	protected int m_ParticleEffectID = -1;
+	protected int m_ParticleEffectIDSync = -1;
+	protected ref EffectParticleGeneral m_Effect = null;
+	//protected int m_EffectID = -1;
+
+	void ParticleEffecter(int lifespan)
+	{
+		RegisterNetSyncVariableInt("m_ParticleEffectIDSync");
+	}
+
+	override void Init(int id, EffecterParameters parameters)
+	{
+		super.Init(id, parameters);
+		
+		ParticleEffecterParameters par = ParticleEffecterParameters.Cast(parameters);
+		SetParticle(par.m_ParticleID);
+	}
+	
+	void SetParticle(int particleID)
+	{
+		m_ParticleEffectIDSync = particleID;
+		Process();	
+	}
+
+	override void OnVariablesSynchronized()
+	{	
+		if (m_ParticleEffectIDSync != m_ParticleEffectID)
+		{
+			if (m_Effect)
+			{
+				m_Effect.SetParticle(m_ParticleEffectIDSync);
+			}
+			else
+			{
+				m_Effect = new EffectParticleGeneral();
+				m_Effect.SetParticle(m_ParticleEffectIDSync);
+				SEffectManager.PlayInWorld(m_Effect, GetWorldPosition());
+			}
+			m_ParticleEffectID = m_ParticleEffectIDSync;
+		}
+		
+		if (m_CommandSync != m_Command)
+		{	
+			switch (m_CommandSync)
+			{
+				case EffecterCommands.START:
+					if (m_Effect && !m_Effect.IsPlaying())
+					{
+						m_Effect.SetParticle(m_ParticleEffectID);
+						m_Effect.Start();
+					}
+					break;
+			
+				case EffecterCommands.STOP:
+					if (m_Effect && m_Effect.IsPlaying())
+					{
+						m_Effect.Stop();
+					}
+					break;
+			
+				case EffecterCommands.REACTIVATE0:
+				case EffecterCommands.REACTIVATE1:
+					if (m_Effect)
+					{
+						m_Effect.SetParticle(m_ParticleEffectID);
+					}
+					if (!m_Effect.IsPlaying())
+					{
+						m_Effect.Start();
+					}
+					break;
+			
+				default:
+					break;
+			}
+			
+			m_Command = m_CommandSync;
+		}
+	}
+	
+	void ~ParticleEffecter()
+	{
+		SEffectManager.DestroyEffect(m_Effect);
+	}
+}
+
+class EffectParticleGeneral : EffectParticle
+{
+	int m_LastParticleID;
+	void EffectParticleGeneral()
+	{
+	}
+	
+	void SetParticle( int particleID )
+	{
+		bool was_playing = IsPlaying();
+	
+		Stop();
+		
+		SetParticleID(particleID);
+		
+		if (was_playing)
+		{
+			Start();
+		}
+	}
+	
+	override void SetParticleID( int id )
+	{
+		super.SetParticleID(id);
+		m_LastParticleID = id;
+	}
+}

+ 456 - 0
Scripts/3_game/effects/backlit/backlit.c

@@ -0,0 +1,456 @@
+
+// Purpose of this file is to encapsulate Backlit Effects
+// Basic implementatoin is for Razer Chroma devices, but API is made to remain universal for future purposes
+//
+// for specific method - watch UAInputAPI/ UAInput class
+//
+//
+
+
+//-----------------------------------------------------------------------------
+//! Input layer type
+const int EUABLAYER_ALL				= 0;	// all layers
+const int EUABLAYER_HINTKEY			= 1;	// showing hints
+const int EUABLAYER_VISKEY			= 2;	// visualisation
+const int EUABLAYER_3				= 3;	// 
+const int EUABLAYER_CAR				= 4;	// 
+const int EUABLAYER_HUMAN			= 5;	// 
+const int EUABLAYER_6				= 6;	// 
+const int EUABLAYER_CUSTOM			= 7;	// custom
+const int EUABLAYER_LOADING			= 8;	// keys during loading sequence
+const int EUABLAYER_MENU			= 9;	// keys during menu
+
+
+//-----------------------------------------------------------------------------
+//! Input backlit type
+const int EUABACKLIT_NONE				= 0;	// turn off
+const int EUABACKLIT_ON					= 1;	// permanent ilumination
+const int EUABACKLIT_2					= 2;
+const int EUABACKLIT_3					= 3;
+const int EUABACKLIT_FADEOUT_SLOW		= 4;	// slow fadeout
+const int EUABACKLIT_FADEOUT_FAST		= 5;	// fast fadeout
+const int EUABACKLIT_FADEIN_SLOW		= 6;	// slow in -> then stay on
+const int EUABACKLIT_FADEIN_FAST		= 7;	// fast in -> then stay on
+
+
+// note: there should be states like:
+//
+//
+//		LOADING/ MAIN MENU/ CONNECTING/ KEYBINDING/ OPTIONS - continuous
+//		CHARACTER/ CAR/ "HELI"/ SPECTATOR/ INFECTED - continuous BASE
+//		SWIMMING/ CRAWLING/ SPRINTING/ FIGHTING/ FLARE/ FLASHLIGHT - continuous CHARACTER
+//
+//	DoorOpen/ HitTaken/ CarCrashed/ etc. - event based
+//
+
+
+const int EUAB_OFF						= 0;	// all off
+
+// logos :: anims
+const int EUAB_LOGO_DAYZ				= 10;
+const int EUAB_LOGO_CONNECTING			= 11;
+
+// menus :: anims
+const int EUAB_MENU_BROWSER				= 20;
+const int EUAB_MENU_MAIN				= 21;
+const int EUAB_MENU_KEYBINDING			= 22;
+const int EUAB_MENU_OPTIONS				= 23;
+
+// car :: basic background colour + overlay + transition anims
+const int EUAB_CAR_OFF					= 100;	// sitting in car with engine off
+const int EUAB_CAR_ON_NOLIGHTS			= 101;	// driving w/o lights (day)
+const int EUAB_CAR_ON_LIGHTS			= 102;	// driving with headlights (night)
+const int EUAB_CAR_STARTING				= 103;	// short starting animation
+const int EUAB_CAR_ENTER				= 104;	// entering car
+const int EUAB_CAR_LEAVE				= 105;	// leaving car
+const int EUAB_CAR_CRASH				= 106;	// crashed
+
+// character :: basic background colour + overlay + transition anims
+const int EUAB_PLR_WALK					= 200;
+const int EUAB_PLR_RUN					= 201;
+const int EUAB_PLR_SPRINT				= 202;
+const int EUAB_PLR_SWIM					= 203;
+const int EUAB_PLR_HITBY				= 204;
+const int EUAB_PLR_CONSUME				= 205;
+const int EUAB_PLR_CRAFTING				= 206;
+const int EUAB_PLR_EMOTE				= 207;	// playing emote
+const int EUAB_PLR_UNCONSCIOUS			= 208;
+const int EUAB_PLR_DEAD					= 209;
+
+// modes :: these are set of background colours
+const int EUAB_MODE_NIGHT				= 300;
+const int EUAB_MODE_MORNING_BAD			= 301;
+const int EUAB_MODE_MORNING_GOOD		= 302;
+const int EUAB_MODE_DAY_FOGGY			= 303;
+const int EUAB_MODE_DAY_OVERCAST		= 304;
+const int EUAB_MODE_DAY_NICE			= 305;
+const int EUAB_MODE_EVENING_BAD			= 306;
+const int EUAB_MODE_EVENING_GOOD		= 307;
+
+const int EUAB_MODE_FLASHLIGHT			= 320;
+const int EUAB_MODE_CHEMLIGHT			= 321;
+
+
+// overlay types
+const int EUAB_OVERLAY_NONE				= 400;	// no overlay
+const int EUAB_OVERLAY_CONTROLS			= 401;	// highlighted controls
+const int EUAB_OVERLAY_STATUS			= 402;	// numpad + mouse used for health/ blood level visualisation
+const int EUAB_OVERLAY_VON				= 403;	// VON status
+
+
+//-----------------------------------------------------------------------------
+//! Backlit effect class
+
+class Backlit
+{
+//	private void ~Backlit(); // raist todo: turn lights off there?
+
+	bool m_BacklitActive;
+
+	void OnInit( DayZGame game )
+	{
+		// enable only on client/ standalone!
+		if( game.IsClient() || !game.IsMultiplayer() )
+			m_BacklitActive = true;
+			
+		if( m_BacklitActive )
+			Print("... Backlit Effects Enabled");
+	}
+
+	// start infinite loading animation
+	void LoadingAnim()
+	{
+		if( !m_BacklitActive )
+			return;	// always return when backlit not present!
+	
+		// lighten up your desktop
+		GetUApi().Backlit_KeyByName("kD",EUABLAYER_LOADING,EUABACKLIT_ON,0xffff0000);
+		GetUApi().Backlit_KeyByName("kA",EUABLAYER_LOADING,EUABACKLIT_ON,0xffcf0000);
+		GetUApi().Backlit_KeyByName("kY",EUABLAYER_LOADING,EUABACKLIT_ON,0xffaf0000);
+		GetUApi().Backlit_KeyByName("kZ",EUABLAYER_LOADING,EUABACKLIT_ON,0xff8f0000);
+		GetUApi().Backlit_Animation("Loading/",2,0xffc8c8c8,0xff080808);
+		GetUApi().Backlit_ForceUpdate();
+	}
+
+	// ...
+	void MainMenu_OnShow()
+	{
+		if( !m_BacklitActive )
+			return;	// always return when backlit not present!
+	
+		// lighten up your desktop
+		GetUApi().Backlit_Remove(EUABLAYER_ALL);
+		GetUApi().Backlit_Animation("MainMenu/",2,0xffff0000,0xff080000);
+		GetUApi().Backlit_ForceUpdate();
+	}
+	
+	// ...
+	void MainMenu_OnHide()
+	{
+		if( !m_BacklitActive )
+			return;	// always return when backlit not present!
+	
+		GetUApi().Backlit_Remove(EUABLAYER_ALL);	
+		GetUApi().Backlit_Background(0,0xff220000,0xff222222);		
+	}
+
+	// ...
+	void OnEnterCar()
+	{
+		if( !m_BacklitActive )
+			return;	// always return when backlit not present!
+	
+		GetUApi().Backlit_Remove(EUABLAYER_ALL);
+		GetUApi().Backlit_Background(0,0xff211202,0xff110800);
+	}
+
+	// ...
+	void OnLeaveCar()
+	{
+		if( !m_BacklitActive )
+			return;	// always return when backlit not present!
+	
+		// force update player
+		if( GetGame().GetMission().GetHud() )
+		{
+			GetUApi().Backlit_Remove(EUABLAYER_ALL);
+			GetUApi().Backlit_Background(0,0xff220000,0xff222222);
+
+			UpdatePlayer(true);
+		}
+	}
+
+	// ...
+	void OnSwimmingStart()
+	{
+		if( !m_BacklitActive )
+			return;	// always return when backlit not present!
+	
+		// reset queue
+		GetUApi().Backlit_EmptyQueue();
+		// play hit animation
+		GetUApi().Backlit_Animation("Water/",0,0xff00ffff,0xffffffff);
+	}
+
+	// ...
+	void OnSwimmingStop()
+	{
+		if( !m_BacklitActive )
+			return;	// always return when backlit not present!
+	
+		if( GetGame().GetMission().GetHud() )
+		{		
+			// enqueue background
+			GetUApi().Backlit_Background(0,0xff220000,0xff222222);
+			// force update player
+			UpdatePlayer(true);
+		}
+	}
+
+	// clear tutorial/ hint keys
+	void HintClear()
+	{
+		if( !m_BacklitActive )
+			return;	// always return when backlit not present!
+	
+		// remove previous backlit
+		GetUApi().Backlit_Remove(EUABLAYER_HINTKEY);				
+	}
+
+	// highlight tutorial/ hint keys
+	void HintShow( UAInput action )
+	{
+		if( !m_BacklitActive )
+			return;	// always return when backlit not present!
+	
+		action.Backlit_Override(EUABLAYER_HINTKEY,0xffafafff);
+	}
+
+	// clear keybinding keys
+	void KeybindingClear( )
+	{
+		if( !m_BacklitActive )
+			return;	// always return when backlit not present!
+	
+		GetUApi().Backlit_Remove(EUABLAYER_ALL);
+	}
+
+	// clear keybinding keys
+	void KeybindingShow( int keyHash )
+	{
+		if( !m_BacklitActive )
+			return;	// always return when backlit not present!
+	
+		GetUApi().Backlit_KeyByHash(keyHash,EUABLAYER_VISKEY,EUABACKLIT_FADEOUT_SLOW,0xff0000ff);
+	}
+
+
+	void VisualiseHealth( int iLevel )
+	{
+		UAInputAPI ua_api = GetUApi();
+			
+		int aColor = 0xff1fff1f;
+		int dColor = 0xff001f00;
+				
+		if( iLevel > 0 )
+			ua_api.Backlit_KeyByName("kF1",EUABLAYER_HUMAN,EUABACKLIT_ON,aColor);
+		else
+			ua_api.Backlit_KeyByName("kF1",EUABLAYER_HUMAN,EUABACKLIT_ON,dColor );
+		if( iLevel > 1 )
+			ua_api.Backlit_KeyByName("kF2",EUABLAYER_HUMAN,EUABACKLIT_ON,aColor);
+		else
+			ua_api.Backlit_KeyByName("kF2",EUABLAYER_HUMAN,EUABACKLIT_ON,dColor );
+		if( iLevel> 2 )
+			ua_api.Backlit_KeyByName("kF3",EUABLAYER_HUMAN,EUABACKLIT_ON,aColor);
+		else
+			ua_api.Backlit_KeyByName("kF3",EUABLAYER_HUMAN,EUABACKLIT_ON,dColor );
+		if( iLevel > 3 )
+			ua_api.Backlit_KeyByName("kF4",EUABLAYER_HUMAN,EUABACKLIT_ON,aColor);
+		else
+			ua_api.Backlit_KeyByName("kF4",EUABLAYER_HUMAN,EUABACKLIT_ON,dColor );
+
+/*		int lc = 0xff001f00;
+		if( iLevel > 0 )
+			lc = 0xff003f00;
+		else if( iLevel > 1 )
+			lc = 0xff007f00;
+		else if( iLevel > 2 )
+			lc = 0xff00af00;
+		else if( iLevel > 3 )
+			lc = 0xff00ff00;
+			
+		ua_api.Backlit_KeyByName("mBMiddle",EUABLAYER_HUMAN,EUABACKLIT_ON,lc);*/
+		
+	}
+	
+	void VisualiseBlood( int iLevel )
+	{
+		UAInputAPI ua_api = GetUApi();
+				
+		int aColor = 0xffff1f1f;
+		int dColor = 0xff1f0000;
+				
+		if( iLevel > 0 )
+			ua_api.Backlit_KeyByName("kF5",EUABLAYER_HUMAN,EUABACKLIT_ON,aColor);
+		else
+			ua_api.Backlit_KeyByName("kF5",EUABLAYER_HUMAN,EUABACKLIT_ON,dColor );
+		if( iLevel > 1 )
+			ua_api.Backlit_KeyByName("kF6",EUABLAYER_HUMAN,EUABACKLIT_ON,aColor);
+		else
+			ua_api.Backlit_KeyByName("kF6",EUABLAYER_HUMAN,EUABACKLIT_ON,dColor );
+		if( iLevel > 2 )
+			ua_api.Backlit_KeyByName("kF7",EUABLAYER_HUMAN,EUABACKLIT_ON,aColor);
+		else
+			ua_api.Backlit_KeyByName("kF7",EUABLAYER_HUMAN,EUABACKLIT_ON,dColor );
+		if( iLevel > 3 )
+			ua_api.Backlit_KeyByName("kF8",EUABLAYER_HUMAN,EUABACKLIT_ON,aColor);
+		else
+			ua_api.Backlit_KeyByName("kF8",EUABLAYER_HUMAN,EUABACKLIT_ON,dColor );
+				
+/*		int lc = 0xff1f0000;
+		if( iLevel > 0 )
+			lc = 0xff3f0000;
+		else if( iLevel > 1 )
+			lc = 0xff7f0000;
+		else if( iLevel > 2 )
+			lc = 0xffaf0000;
+		else if( iLevel > 3 )
+			lc = iLevel;
+				
+		ua_api.Backlit_KeyByName("mBRight",EUABLAYER_HUMAN,EUABACKLIT_ON,lc);*/
+		
+	}
+
+	int m_HealthBefore = -1;
+	int m_BloodBefore = -1;
+
+	int m_HealthNew = 0;
+	int m_BloodNew = 0;
+
+	void SetHealth( float fHealth ) // range 0 .. 100
+	{
+		float health = fHealth * 0.01; // div 100
+		m_HealthNew = health*4; // 4 stages
+	}
+
+	void SetBlood( float fBlood ) // range 0 .. 5000
+	{
+		float blood = fBlood * 0.0002; // div 5000
+		m_BloodNew = blood*4; // 4 stages
+	}
+
+	void UpdatePlayer( bool bForce )
+	{
+		if( !m_BacklitActive )
+			return;	// always return when backlit not present!
+	
+		// force update
+		if( bForce )
+		{
+			m_HealthBefore = -1;
+			m_BloodBefore = -1;
+		}
+	
+		// do not update
+		if( m_HealthNew == m_HealthBefore && m_BloodNew == m_BloodBefore )
+			return;
+
+		// remove previous layers
+		GetUApi().Backlit_Remove(EUABLAYER_ALL);
+
+		// set keys to layer CUSTOM
+		GetUApi().Backlit_KeyByName("kW",EUABLAYER_CUSTOM,EUABACKLIT_ON,0xff0000ff);
+		GetUApi().Backlit_KeyByName("kA",EUABLAYER_CUSTOM,EUABACKLIT_ON,0xff0000cf);
+		GetUApi().Backlit_KeyByName("kS",EUABLAYER_CUSTOM,EUABACKLIT_ON,0xff0000af);
+		GetUApi().Backlit_KeyByName("kD",EUABLAYER_CUSTOM,EUABACKLIT_ON,0xff00008f);
+
+		GetUApi().Backlit_KeyByName("kX",EUABLAYER_CUSTOM,EUABACKLIT_ON,0xff3f3f3f);
+		GetUApi().Backlit_KeyByName("kC",EUABLAYER_CUSTOM,EUABACKLIT_ON,0xff3f3f3f);
+
+		GetUApi().Backlit_KeyByName("kQ",EUABLAYER_CUSTOM,EUABACKLIT_ON,0xff7f7f0f);
+		GetUApi().Backlit_KeyByName("kE",EUABLAYER_CUSTOM,EUABACKLIT_ON,0xff7f7f0f);
+
+		// health
+		VisualiseHealth(m_HealthNew);
+		// blood
+		VisualiseBlood(m_BloodNew);
+
+		// animation
+		GetUApi().Backlit_Background(0,0xff220000,0xff222222);
+		
+		// save level
+		m_BloodBefore = m_BloodNew;
+		m_HealthBefore = m_HealthNew;
+	}
+
+
+	int m_GearBefore = 0;
+	bool m_CELBefore = false;
+
+	void RefreshVehicleLayout( int iGear, bool bCEL )
+	{
+		if( !m_BacklitActive )
+			return;	// always return when backlit not present!
+	
+		UAInputAPI ua_api = GetUApi();
+
+		if( m_GearBefore != iGear )
+		{
+			m_GearBefore = iGear;
+			
+			int activeColor = 0xff3fff3f;
+			int dimmColor = 0xff0f3f0f;
+				
+			if( iGear == CarGear.REVERSE )
+				ua_api.Backlit_KeyByName("kR",EUABLAYER_CAR,EUABACKLIT_ON,activeColor);
+			else
+				ua_api.Backlit_KeyByName("kR",EUABLAYER_CAR,EUABACKLIT_ON,dimmColor);
+
+			if( iGear == CarGear.NEUTRAL )
+				ua_api.Backlit_KeyByName("kN",EUABLAYER_CAR,EUABACKLIT_ON,activeColor);
+			else
+				ua_api.Backlit_KeyByName("kN",EUABLAYER_CAR,EUABACKLIT_ON,dimmColor);
+
+			if( iGear == CarGear.FIRST )
+				ua_api.Backlit_KeyByName("k1",EUABLAYER_CAR,EUABACKLIT_ON,activeColor);
+			else
+				ua_api.Backlit_KeyByName("k1",EUABLAYER_CAR,EUABACKLIT_ON,dimmColor);
+
+			if( iGear == CarGear.SECOND )
+				ua_api.Backlit_KeyByName("k2",EUABLAYER_CAR,EUABACKLIT_ON,activeColor);
+			else
+				ua_api.Backlit_KeyByName("k2",EUABLAYER_CAR,EUABACKLIT_ON,dimmColor);
+
+			if( iGear == CarGear.THIRD )
+				ua_api.Backlit_KeyByName("k3",EUABLAYER_CAR,EUABACKLIT_ON,activeColor);
+			else
+				ua_api.Backlit_KeyByName("k3",EUABLAYER_CAR,EUABACKLIT_ON,dimmColor);
+
+			if( iGear == CarGear.FOURTH )
+				ua_api.Backlit_KeyByName("k4",EUABLAYER_CAR,EUABACKLIT_ON,activeColor);
+			else
+				ua_api.Backlit_KeyByName("k4",EUABLAYER_CAR,EUABACKLIT_ON,dimmColor);
+
+			if( iGear == CarGear.FIFTH )
+				ua_api.Backlit_KeyByName("k5",EUABLAYER_CAR,EUABACKLIT_ON,activeColor);
+			else
+				ua_api.Backlit_KeyByName("k5",EUABLAYER_CAR,EUABACKLIT_ON,dimmColor);
+
+		}
+
+		if( bCEL != m_CELBefore )
+		{		
+			m_CELBefore = bCEL;
+
+			if( bCEL )
+				ua_api.Backlit_KeyByName("kC",EUABLAYER_CAR,EUABACKLIT_ON,0xffff0f0f);
+			else
+				ua_api.Backlit_KeyByName("kC",EUABLAYER_CAR,EUABACKLIT_NONE,0xff000000);
+		}
+
+	}
+
+};
+
+
+

+ 160 - 0
Scripts/3_game/effects/destructioneffects/destructioneffectbase.c

@@ -0,0 +1,160 @@
+class DestructionEffectBase
+{
+	EntityAI 		m_Entity;
+	
+	bool 			m_EntityIsTakeable;
+	
+	ParticleSource 	m_POneTime;
+	ParticleSource 	m_PPersistent;
+	
+	int 			m_ParticleOneTime;
+	int 			m_ParticlePersistent;
+	
+	EffectSound 	m_SOneTime;
+	EffectSound 	m_SPersistent;
+	
+	string 			m_SoundSetOneTime;
+	string 			m_SoundSetPersistent;
+
+	bool 			m_KeepHealthOnReplace;
+	string 			m_ReplaceWithEntity;
+	int 			m_ReplaceDelay;
+		
+	bool 			m_HasExplosionDamage;
+	DamageType		m_DamageType;
+	string 			m_AmmoType;
+	
+	
+	void ~DestructionEffectBase()
+	{
+		if (m_POneTime)
+		{
+			m_POneTime.Stop();
+		}
+		if (m_PPersistent)
+		{
+			m_PPersistent.Stop();
+		}
+		
+		SEffectManager.DestroyEffect(m_SOneTime);
+		SEffectManager.DestroyEffect(m_SPersistent);
+	}
+	
+	private void Init();
+	
+	bool HasExplosionDamage()
+	{
+		return (m_HasExplosionDamage && m_AmmoType);
+	}
+	
+	private void DealExplosionDamage()
+	{
+		DamageSystem.ExplosionDamage(m_Entity, null, m_AmmoType, m_Entity.GetPosition(), m_DamageType);
+	}
+	
+	void OnHealthLevelChanged(notnull EntityAI entity, int oldLevel, int newLevel, string zone)
+	{
+		m_Entity = entity;
+		Init();
+		
+		if (GetGame().IsServer())
+		{
+			entity.SetTakeable(m_EntityIsTakeable);
+			
+			if (oldLevel != -1 || entity.m_Initialized)
+			{
+				if (m_ReplaceWithEntity)
+				{
+					GetGame().GetCallQueue(CALL_CATEGORY_SYSTEM).CallLater(ReplaceEntityServer, m_ReplaceDelay, false);
+				}
+				if (HasExplosionDamage())
+				{
+					DealExplosionDamage();
+				}
+				OnEntityDestroyedOneTimeServer(entity, oldLevel, zone);
+			}
+			OnEntityDestroyedPersistentServer(entity, zone);
+		}
+		#ifndef SERVER//client OR single
+		{
+			if (oldLevel != -1 || entity.m_Initialized)//one time
+			{
+				m_POneTime = PlayParticle(m_ParticleOneTime);
+				
+				if (m_POneTime)
+				{
+					m_POneTime.SetOwner(this);
+				}
+								
+				OnEntityDestroyedOneTimeClient(entity, oldLevel, zone);
+				
+				m_Entity.PlaySoundSet(m_SOneTime, m_SoundSetOneTime, 0, 0 );
+				m_Entity.PlaySoundSetLoop(m_SPersistent, m_SoundSetPersistent, 0, 0 );
+			}
+			else//Persistent
+			{
+				OnEntityDestroyedPersistentClient(entity, zone);
+				m_Entity.PlaySoundSetLoop(m_SPersistent, m_SoundSetPersistent, 0, 0 );
+			}
+			
+			m_PPersistent = PlayParticle(m_ParticlePersistent, true);
+			
+			if (m_PPersistent)
+			{
+				m_PPersistent.SetOwner(this);
+			}
+		}
+		#endif
+	}
+	
+	private void ReplaceEntityServer()
+	{
+		EntityAI dead_entity = EntityAI.Cast(GetGame().CreateObjectEx(m_ReplaceWithEntity, m_Entity.GetPosition(), ECE_OBJECT_SWAP, RF_ORIGINAL));
+		dead_entity.SetOrientation(m_Entity.GetOrientation());
+		if (m_KeepHealthOnReplace)
+		{
+			dead_entity.SetHealth(m_Entity.GetHealth());
+		}
+		m_Entity.Delete();
+	}
+	
+	private ParticleSource PlayParticle(int particleType, bool attach = false)
+	{
+		if (!m_Entity)
+		{
+			ErrorEx("Missing entity - something went wrong");
+			return null;
+		}
+		if (particleType)
+		{
+			ParticleSource p = ParticleManager.GetInstance().PlayInWorld(particleType, m_Entity.GetPosition());
+			if (attach && p)
+			{
+				p.AddAsChild(m_Entity);//Note: it's also possible to directly play on object: Particle.PlayOnObject
+			}
+			return p;
+		}
+		return null;
+	}
+	
+	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+	// !!!!!!!!!! Override methods bellow !!!!!!!!!!!!!
+	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+	
+	// ! Client Event called the moment the entity is destroyed, best for explosion and other one-time effects
+	void OnEntityDestroyedOneTimeClient(EntityAI entity, int oldLevel,string zone);
+
+	// ! Server Event called the moment the entity is destroyed
+	void OnEntityDestroyedOneTimeServer(EntityAI entity, int oldLevel, string zone);
+
+	// ! Client Event called at the same moment as the one-time event, but also when the entity is loaded/spawned on client, typically as the player connects to the server or moves close enough so that previously non-existent client entity is now spawned in
+	void OnEntityDestroyedPersistentClient(EntityAI entity, string zone);
+
+	// ! Server Event called at the same moment as the one time event, but also when the entity is loaded/spawned on Server, typically as the server is starting up
+	void OnEntityDestroyedPersistentServer(EntityAI entity, string zone);
+
+	// !Relayed from entity when explosion happens
+	void OnExplosionEffects(Object source, Object directHit, int componentIndex, string surface, vector pos, vector surfNormal, float energyFactor, float explosionFactor, bool isWater, string ammoType);
+
+}
+

+ 568 - 0
Scripts/3_game/effects/effectparticle.c

@@ -0,0 +1,568 @@
+/**
+\brief Wrapper class for managing particles through SEffectManager
+*/
+class EffectParticle : Effect
+{
+	//! The main Particle effect that this Effect wrapper manages
+	protected Particle 			m_ParticleObj;
+	
+	/** \name Generic data
+	*	Generic data for the particle
+	*/
+	//@{
+	//! The ID in the ParticleList to create Particle from
+	protected int				m_ParticleID;
+	//! Orientation set by SetOrientation
+	protected vector			m_Orientation;
+	//! Orientation setting to be used by the effect when the Effect starts
+	protected bool    			m_ForceRotationRelativeToWorld;
+	//@}
+		
+	/** \name DEPRECATED
+	*	Simply exist because of backwards compatibility, might have never been used
+	*/
+	//@{
+	protected vector    		m_ParticleOrientation;
+	protected Object 			m_Object;
+	//@}
+	
+	
+	
+	/**
+	\brief ctor
+	*/
+	void EffectParticle()
+	{
+		
+	}
+	
+	/**
+	\brief dtor
+	*/
+	void ~EffectParticle()
+	{
+
+	}
+		
+	/**
+	\brief init
+	*/
+	override void InitEffect()
+	{
+		super.InitEffect();
+		
+		// Would be neat, but since particles are often already playing
+		// BEFORE they are even registered as the particle for the Effect
+		// Better to just keep that one I guess..
+		// Event_OnStarted.Remove(Event_OnEffectStarted);
+		
+		// Will be called by the particle events
+		Event_OnStopped.Remove(Event_OnEffectEnded);
+	}
+	
+	
+	/**
+	\brief Override when getting debug information
+	*/
+	override string GetDebugName()
+	{
+		string identifier;
+		if (GetParticle())
+		{
+			identifier = GetParticle().GetDebugNameNative();
+		}
+		else
+		{
+			identifier = "NO_PARTICLE";
+		}
+		
+		return string.Format("%1:%2:%3", super.GetDebugName(), m_ParticleID, identifier);
+	}
+	
+	/**
+	\brief Validation whether an effect truly started playing or if the Effect should stop as none is present
+		\note Override this when inheriting to create own validation check
+		\note Is called from Event_OnStarted invoker after Event_OnStarted has been performed
+	*/
+	override void ValidateStart()
+	{
+		if (!GetParticle())
+		{
+			//ErrorEx(string.Format("No Particle started playing, stopping EffectParticle: %1", GetDebugName()), ErrorExSeverity.WARNING);
+			Stop();
+		}
+	}
+	
+	
+	
+	/** \name EffectType
+		Information about what type of effect the Effect is, without the need for casting
+	*/
+	//@{
+	
+	/**
+	\brief Get what type of effect the Effect is
+		\return \p EffectType What type of effect the Effect is
+	*/
+	override EffectType GetEffectType()
+	{
+		return EffectType.PARTICLE;
+	}
+	
+	/**
+	\brief Check whether the Effect is EffectParticle without casting
+		\return \p bool Whether the Effect is EffectParticle
+	*/
+	override bool IsParticle()
+	{
+		return true;
+	}
+	
+	//@}
+	
+	
+	
+	/** \name Main particle
+		Set or get the main particle which this Effect will manage
+	*/
+	//@{
+	
+	/**
+	\brief Sets the main particle which this Effect will manage
+		\param p \p Particle Main particle which this Effect will manage
+	*/
+	void SetParticle(Particle p)
+	{
+		// Unregister the events on the old
+		if (m_ParticleObj)
+		{
+			ParticleEvents ope = m_ParticleObj.GetEvents();
+			ope.Event_OnParticleStart.Remove(Event_OnEffectStarted);
+			ope.Event_OnParticleStop.Remove(Event_OnEffectEnded);
+		}
+		
+		// Assign the new main Particle
+		m_ParticleObj = p;
+		
+		// Register the events on the new
+		if (m_ParticleObj)
+		{
+			ParticleEvents npe = m_ParticleObj.GetEvents();
+			npe.Event_OnParticleStart.Insert(Event_OnEffectStarted);
+			// We will use Stop instead of End, as old particles were destroyed when they stopped
+			// And this system kinda relies on that
+			npe.Event_OnParticleStop.Insert(Event_OnEffectEnded);
+		}
+	}
+	
+	/**
+	\brief Gets the main particle which this Effect is managing
+		\return \p Particle Main particle which this Effect is managing
+	*/
+	Particle GetParticle()
+	{
+		return m_ParticleObj;
+	}
+	
+	//@}
+	
+	
+	
+	/** \name Playback
+	*	Methods to Play/Stop Effect
+	*	Generally, SEffectManager.Play methods are used instead of Start
+	*/
+	//@{
+	
+	/**
+	\brief Plays all elements this effect consists of
+		\note Is called by SEffectManager.Play methods
+	*/
+    override void Start()
+    {		
+		if (m_ParticleID > 0)
+		{
+			vector pos = GetPosition();			
+			vector ori = GetOrientation();
+			
+			if (m_ParentObject)
+			{
+				pos = GetLocalPosition();
+				ori = GetAttachedLocalOri();
+			}		
+			
+			SetParticle(ParticleManager.GetInstance().CreateParticle(m_ParticleID, pos, true, GetParent(), ori, IsParticleRotationRelativeToWorld()));
+		}
+
+		super.Start();
+	}
+	
+	/**
+	\brief Stops all elements this effect consists of
+		\note Alternatively use SEffectManager.Stop( effect_id )
+	*/
+    override void Stop()
+    {
+		if ( GetParticle() )
+		{
+			GetParticle().Stop();
+			SetParticle(null);
+		}
+		
+		super.Stop();
+    }
+	
+	//@}
+	
+	
+	
+	/** \name Attach
+		Helper methods for attaching to prent
+	*/
+	//@{
+	
+	/**
+	\brief Read Particle.AddAsChild
+	*/
+	void AttachTo(Object obj, vector local_pos = "0 0 0", vector local_ori = "0 0 0", bool force_rotation_to_world = false)
+	{
+		// Update the cached variables...
+		SetParent(obj);
+		SetLocalPosition(local_pos);
+		SetAttachedLocalOri(local_ori);
+		ForceParticleRotationRelativeToWorld(force_rotation_to_world);
+		
+		// Now attach it
+		AddAsChild(obj, local_pos, local_ori, force_rotation_to_world);
+	}
+	
+	/**
+	\brief Helper method to attach to parent using stored settings
+	*/
+	void ReAttach()
+	{
+		// Skip the updating, as we are going to reuse what was set before
+		AddAsChild( GetParent(), GetLocalPosition(), GetAttachedLocalOri(), IsParticleRotationRelativeToWorld());
+	}
+	
+	/**
+	\brief Helper method to attach to parent
+	*/
+	protected void AddAsChild(Object obj, vector local_pos, vector local_ori, bool force_rotation_to_world)
+	{
+		Particle p = GetParticle();		
+		if (p)
+		{
+			p.AddAsChild(obj, local_pos, local_ori, force_rotation_to_world);
+		}
+	}
+	
+	//@}
+	
+	
+	
+	/** \name Events
+		Various events that can be overriden for custom behaviour
+	*/
+	//@{
+	
+	/**
+	\brief Event which just simply exists (DEPRECATED)
+		\warning Never called or used
+		\note Use Event_OnStarted instead
+	*/
+	void Event_OnPlayStart()
+	{
+		
+	}
+	
+	/**
+	\brief Event which just simply exists (DEPRECATED)
+		\warning Never called or used
+		\note Use Event_OnStarted instead
+	*/
+	void Event_OnPlayStarted()
+	{
+
+	}
+
+	//@}
+	
+	
+	
+	/** \name Generic API
+		Setters and getters for generic data and properties
+	*/
+	//@{
+	
+	/**
+	\brief Sets the id of the particle to be used
+		\note Only changes the cached variable, for immediate, use SetCurrentParticleID
+		\param id \p int Particle ID registered in ParticleList
+	*/
+	void SetParticleID( int id )
+    {
+        m_ParticleID = id;
+    }
+	
+	/**
+	\brief Gets the id of the particle to be used
+		\warning Only gets the cached variable, for immediate effect use GetCurrent variant
+		\return \p int Particle ID registered in ParticleList
+	*/
+	int GetParticleID()
+    {
+        return m_ParticleID;
+    }
+	
+	/**
+	\brief Sets the id of the particle to be used
+		\note Particle will not update immediately, but ParticleSource will
+		\param id \p int Particle ID registered in ParticleList
+	*/
+	void SetCurrentParticleID( int id )
+    {
+        m_ParticleID = id;
+		
+		Particle p = GetParticle();
+		if (p)
+		{
+			p.SetSource(id);
+		}
+    }
+	
+	/**
+	\brief Gets the current id of the managed Particle
+		\return \p int Particle ID registered in ParticleList
+	*/
+	int GetCurrentParticleID()
+    {
+		Particle p = GetParticle();
+		if (p)
+		{
+			return p.GetParticleID();
+		}
+		else
+		{
+			return ParticleList.INVALID;
+		}
+    }
+	
+	/**
+	\brief Set current parent of the managed Particle
+		\param parent_obj \p Object The parent for the Particle
+		\param updateCached \p bool Whether to update the cached variable
+	*/
+	override void SetCurrentParent( Object parent_obj, bool updateCached = true )
+	{
+		super.SetCurrentParent(parent_obj, updateCached);
+		
+		ReAttach();
+	}
+	
+	/**
+	\brief Get the current parent of the managed Particle
+		\return \p Object The currrent parent of the Particle
+	*/
+	override Object GetCurrentParent()
+	{
+		Particle p = GetParticle();
+			
+		if (p)
+			return Object.Cast(p.GetParent());
+		else
+			return super.GetParent();
+	}
+	
+	/**
+	\brief Set the current world position of the managed Particle
+		\param pos \p vector The current world position for the Particle
+		\param updateCached \p bool Whether to update the cached variable
+	*/
+	override void SetCurrentPosition( vector pos, bool updateCached = true )
+	{
+		super.SetCurrentPosition(pos, updateCached);
+		
+		Particle p = GetParticle();
+		
+		if (p)
+			p.SetPosition(pos);
+	}
+	
+	/**
+	\brief Get the current world position of the managed Particle
+		\return \p vector The current world position of the managed Particle
+	*/
+	override vector GetCurrentPosition()
+	{
+		Particle p = GetParticle();	
+		
+		if (p)
+			return p.GetPosition();
+		else
+			return super.GetPosition();
+	}
+	
+	/**
+	\brief Set the current local position of the managed Particle
+		\param pos \p vector The current local position for the managed Particle
+		\param updateCached \p bool Whether to update the cached variable
+	*/
+	override void SetCurrentLocalPosition( vector pos, bool updateCached = true )
+    {
+		super.SetCurrentLocalPosition(pos, updateCached);
+		
+		Particle p = GetParticle();			
+		if (p)
+		{
+			Object parent = GetParent();
+			
+			if (parent)
+				ReAttach();
+			else
+				p.SetPosition(pos);
+		}
+    }
+
+	/**
+	\brief Get the current local position of the managed Particle
+		\return \p vector The current local position of the managed Particle
+	*/
+	override vector GetCurrentLocalPosition()
+	{
+		Particle p = GetParticle(); 
+		
+		if (p)
+		{
+			Object parent = GetParent();
+			
+			if (parent)
+				return parent.WorldToModel(p.GetPosition());
+			else
+				return p.GetPosition();
+		}
+		else
+			return super.GetLocalPosition();
+	}
+	
+	/**
+	\brief Set orientation of the EffectParticle
+		\warning Only sets the cached variable, for immediate effect use SetCurrent variant
+		\param ori \p vector Orientation in degrees (yaw, pitch, roll)
+	*/
+	void SetOrientation( vector ori )
+	{
+		m_Orientation = ori;
+	}
+	
+	/**
+	\brief Get the orientation of the EffectParticle
+		\warning Only gets the cached variable, for immediate effect use GetCurrent variant
+		\return \p vector The orientation of EffectParticle
+	*/
+	vector GetOrientation()
+	{
+		return m_Orientation;
+	}
+	
+	/**
+	\brief Set the current orientation of the managed Particle
+		\param ori \p vector Orientation in degrees (yaw, pitch, roll)
+	*/
+	void SetCurrentOrientation( vector ori, bool updateCached = true )
+	{
+		if ( updateCached)
+			SetOrientation(ori);
+		
+		Particle p = GetParticle();	
+				
+		if (p)
+			p.SetOrientation(ori);
+	}
+	
+	/**
+	\brief Get the current orientation of the managed Particle
+		\return \p vector The current orientation of the managed Particle
+	*/
+	vector GetCurrentOrientation()
+	{
+		Particle p = GetParticle();	
+		
+		if (p)
+			return p.GetOrientation();
+		else
+			return vector.Zero;
+	}
+	
+	/**
+	\brief Set orientation setting to be used by the effect when the Effect starts
+		\warning Only caches it into a variable to be used by Start, does not live update when called afterwards
+		\note There is no way to update this immediately
+		\param state \p bool Whether to keep WS orientation when attaching it to parent
+	*/
+	void ForceParticleRotationRelativeToWorld(bool state)
+	{
+		m_ForceRotationRelativeToWorld = state;
+	}
+	
+	/**
+	\brief Get the orientation setting to be used by the effect when the Effect starts
+		\warning Only gets the cached variable, for immediate effect use IsParticleCurrentRotationRelativeToWorld
+		\return \p bool Whether to keep WS orientation when attaching it to parent
+	*/
+	bool IsParticleRotationRelativeToWorld()
+	{
+		Particle p = GetParticle();	
+		
+		if (p)
+			return p.IsHierarchyPositionOnly();
+		else
+			return m_ForceRotationRelativeToWorld;
+	}
+	
+	/**
+	\brief Get the current orientation setting to be used by the managed Particle
+		\return \p bool Whether the managed Particle is only updating position from parent
+	*/
+	bool IsParticleCurrentRotationRelativeToWorld()
+	{
+		Particle p = GetParticle();	
+		
+		if (p)
+			return p.IsHierarchyPositionOnly();
+		else
+			return false;
+	}
+	
+	//@}
+
+	
+	
+	/** \name DEPRECATED
+		Methods which exist for backwards compatibility and are no longer in use or have never been in use
+	*/
+	//@{
+	
+	/**
+	\brief Was never called and probably should never be called
+		\warning Emptied the functionality as it is relatively unsafe...
+	*/
+	void CheckLifeSpan()
+	{
+		/*
+		if ( !m_ParticleObj )
+		{
+			delete this;
+		}
+		
+		OnCheckUpdate();
+		*/
+	}
+
+	void SetDecalOwner(Object o)
+	{
+		m_Object = o;
+	}
+	
+	//@}
+}

+ 15 - 0
Scripts/3_game/effects/effectparticle/bleedingsource.c

@@ -0,0 +1,15 @@
+class BleedingSourceEffect : EffectParticle
+{
+	void BleedingSourceEffect()
+	{
+		SetParticleID(ParticleList.BLEEDING_SOURCE);
+	}
+}
+
+class BleedingSourceEffectLight : EffectParticle
+{
+	void BleedingSourceEffectLight()
+	{
+		SetParticleID(ParticleList.BLEEDING_SOURCE_LIGHT);
+	}
+}

+ 7 - 0
Scripts/3_game/effects/effectparticle/bloodsplatter.c

@@ -0,0 +1,7 @@
+class BloodSplatter : EffectParticle
+{
+	void BloodSplatter()
+	{
+		SetParticleID(ParticleList.BLOOD_SURFACE_DROPS);
+	}
+}

+ 341 - 0
Scripts/3_game/effects/effectparticle/bulletimpactbase.c

@@ -0,0 +1,341 @@
+class EffBulletImpactBase : EffectParticle
+{
+	static const int	SURVIVOR_HEAD = 0; // Head component
+	static const int	INFECTED_HEAD = 3; // Head component
+	static float		DEFAULT_PROJECTILE_WEIGHT = 0.015;
+	
+	float				MIN_SCALING_PARAM = 0.1;
+	
+	Object 				m_DirectHit;
+	float 				m_StoppingForce;
+	float 				m_Weight; // projectile weight in kg
+	int 				m_ImpactType;
+	int 				m_ComponentIndex;
+	vector 				m_Pos;
+	vector 				m_SurfNormal;
+	vector 				m_ExitPos;
+	vector 				m_InSpeed;
+	vector 				m_OutSpeed;
+	string 				m_AmmoType;
+	
+	static vector INVALID = "0 0 0";
+	
+	// Particle Effects
+	int m_ParticleEnter = -1;
+	int m_ParticleExit = -1;
+	int m_ParticleRicochet = -1;
+	
+	// Calculations
+	float m_EnterSplashCoef = 0.003;
+	float m_ExitSplashCoef = 0.002;
+	float m_RicochetSplashCoef = 0.002;
+	float m_EnterAngledSplashCoef = 0.01;
+	float m_AngledEnter = 0.40;
+	
+	void EffBulletImpactBase()
+	{
+		
+	}
+	
+	override void OnCheckUpdate()
+	{
+		//DbgUI.Text( m_ammoType );
+	}
+	
+	void SetEnterParticle(int id)
+	{
+		m_ParticleEnter = id;
+	}
+	
+	void SetExitParticle(int id)
+	{
+		m_ParticleExit = id;
+	}
+	
+	void SetRicochetParticle(int id)
+	{
+		m_ParticleRicochet = id;
+	}
+	
+	void SetSingleParticle(int id)
+	{
+		SetEnterParticle(id);
+		SetExitParticle(id);
+		SetRicochetParticle(id);
+	}
+	
+	void SetAngledEnterValue(float f)
+	{
+		m_AngledEnter = f;
+	}
+	
+	void EvaluateEffect(Object directHit, int componentIndex, vector pos, int impact_type, vector surfNormal, vector exitPos, vector inSpeed, vector outSpeed, string ammoType)
+	{
+		m_DirectHit 		= directHit;
+		m_Pos 				= pos;
+		m_ImpactType 		= impact_type;
+		m_ComponentIndex 	= componentIndex;
+		m_SurfNormal 		= surfNormal;
+		m_ExitPos 			= exitPos;
+		m_InSpeed 			= inSpeed;
+		m_OutSpeed 			= outSpeed;
+		m_AmmoType 			= ammoType;
+		m_Weight			= GetGame().ConfigGetFloat("CfgAmmo " + ammoType + " weight");
+		
+		m_StoppingForce 	= CalculateStoppingForce(m_InSpeed.Length(), m_OutSpeed.Length(), ammoType, m_Weight);
+	}
+	
+	float CalculateStoppingForce(float in_speedf, float out_speedf, string ammoType, float weight)
+	{
+		if ( m_ImpactType == ImpactTypes.MELEE )
+		{
+			return Math.RandomFloat(50, 100);
+		}
+		
+		float projectile_weight_coef = weight / DEFAULT_PROJECTILE_WEIGHT;
+		
+		float stopping_force = (in_speedf - out_speedf) * projectile_weight_coef;
+		
+		return stopping_force;
+	}
+	
+	void OnEnterCalculations( Particle p )
+	{
+		// All values represent scale
+		float velocity_min 		= (m_StoppingForce * m_EnterSplashCoef);
+		float velocity_max 		= (m_StoppingForce * m_EnterSplashCoef);
+		float size 				= (m_StoppingForce * m_EnterSplashCoef);
+		float birth_rate 		= (m_StoppingForce * m_EnterSplashCoef);
+		float air_resistance 	= velocity_min;
+		float lifetime 			= (m_StoppingForce * m_EnterSplashCoef);
+		float lifetime_rnd		= (m_StoppingForce * m_EnterSplashCoef);
+		
+		if ( m_AmmoType == "Bullet_12GaugePellets" )
+		{
+			birth_rate *= 0.5;
+			velocity_min *= 2;
+			velocity_max *= 2;
+		}
+		
+		
+		if (velocity_min < 0.75)
+			velocity_min = 0.75;
+		
+		if (size < 0.75)
+			size = 0.75;
+		
+		if (lifetime < 0.5)
+			lifetime = 0.5;
+		
+		if (lifetime_rnd < 0.5)
+			lifetime_rnd = 0.5;
+		
+		if (velocity_max < 1)
+			velocity_max = 1;
+		
+		/*Print("===============");
+		Print(velocity_min);
+		Print(velocity_max);
+		Print(size);
+		Print(birth_rate);
+		Print(air_resistance);
+		Print(lifetime);
+		Print(lifetime_rnd);*/
+		
+		p.ScaleParticleParam(EmitorParam.VELOCITY, velocity_min);
+		p.ScaleParticleParam(EmitorParam.VELOCITY_RND, velocity_max);
+		p.ScaleParticleParam(EmitorParam.SIZE, size);
+		p.ScaleParticleParam(EmitorParam.BIRTH_RATE, birth_rate);
+		p.ScaleParticleParam(EmitorParam.AIR_RESISTANCE, air_resistance);
+		p.ScaleParticleParam(EmitorParam.AIR_RESISTANCE_RND, air_resistance);
+		p.ScaleParticleParam(EmitorParam.LIFETIME, lifetime);
+		p.ScaleParticleParam(EmitorParam.LIFETIME_RND, lifetime_rnd);
+	}
+	
+	void OnExitCalculations(Particle p, float outSpeedf)
+	{
+		float velocity_min = 1 + (outSpeedf * m_ExitSplashCoef);
+		float velocity_max = 1 + (outSpeedf * m_ExitSplashCoef);
+		float size = 1 + ( outSpeedf * m_ExitSplashCoef);
+		float birth_rate = 1 + (outSpeedf * m_ExitSplashCoef);
+		
+		if (velocity_min < MIN_SCALING_PARAM)
+			velocity_min = MIN_SCALING_PARAM;
+		
+		if (size < MIN_SCALING_PARAM)
+			size = MIN_SCALING_PARAM;
+		
+		if (birth_rate < MIN_SCALING_PARAM)
+			birth_rate = MIN_SCALING_PARAM;
+		
+		p.ScaleParticleParam(EmitorParam.VELOCITY, velocity_min);
+		p.ScaleParticleParam(EmitorParam.VELOCITY_RND, velocity_max);
+		p.ScaleParticleParam(EmitorParam.SIZE, size);
+		p.ScaleParticleParam(EmitorParam.BIRTH_RATE, birth_rate);
+	}
+	
+	void OnRicochetCalculations(Particle p, float outspeedf)
+	{
+		float velocity_min = MIN_SCALING_PARAM + (m_StoppingForce * m_RicochetSplashCoef);
+		float velocity_max = MIN_SCALING_PARAM + (m_StoppingForce * m_RicochetSplashCoef);
+		float size = MIN_SCALING_PARAM + ( m_StoppingForce * m_RicochetSplashCoef);
+		float birth_rate = MIN_SCALING_PARAM + (m_StoppingForce * m_RicochetSplashCoef);
+		
+		if (velocity_min < MIN_SCALING_PARAM)
+			velocity_min = MIN_SCALING_PARAM;
+		
+		if (size < MIN_SCALING_PARAM)
+			size = MIN_SCALING_PARAM;
+		
+		if (birth_rate < MIN_SCALING_PARAM)
+			birth_rate = MIN_SCALING_PARAM;
+		
+		p.ScaleParticleParam(EmitorParam.VELOCITY, velocity_min);
+		p.ScaleParticleParam(EmitorParam.VELOCITY_RND, velocity_max);
+		p.ScaleParticleParam(EmitorParam.SIZE, size);
+		p.ScaleParticleParam(EmitorParam.BIRTH_RATE, birth_rate);
+	}
+	
+	void OnEnterAngledCalculations(Particle p)
+	{
+		float velocity_min = MIN_SCALING_PARAM + (m_StoppingForce * m_EnterAngledSplashCoef);
+		float velocity_max = MIN_SCALING_PARAM + (m_StoppingForce * m_EnterAngledSplashCoef);
+		float size = MIN_SCALING_PARAM + (m_StoppingForce * m_EnterAngledSplashCoef);
+		float birth_rate = MIN_SCALING_PARAM + (m_StoppingForce * m_EnterAngledSplashCoef);
+		
+		if (velocity_min < MIN_SCALING_PARAM)
+			velocity_min = MIN_SCALING_PARAM;
+		
+		if (size < MIN_SCALING_PARAM)
+			size = MIN_SCALING_PARAM;
+		
+		if (birth_rate < MIN_SCALING_PARAM)
+			birth_rate = MIN_SCALING_PARAM;
+		
+		p.ScaleParticleParam(EmitorParam.VELOCITY, velocity_min);
+		p.ScaleParticleParam(EmitorParam.VELOCITY_RND, velocity_max);
+		p.ScaleParticleParam(EmitorParam.SIZE, size);
+		p.ScaleParticleParam(EmitorParam.BIRTH_RATE, birth_rate);
+	}
+	
+	override void Event_OnStarted()
+	{
+		Particle p;
+		vector particle_orientation;
+		float outSpeedf = m_OutSpeed.Length();
+		
+		ParticleManager gPM = ParticleManager.GetInstance();
+		
+		if ( m_ImpactType == ImpactTypes.RICOCHET )
+		{
+			p = gPM.PlayInWorld(m_ParticleRicochet, m_Pos);
+			
+			if (p)
+			{
+				particle_orientation = m_OutSpeed.VectorToAngles();
+				particle_orientation = particle_orientation + "0 -90 0";
+				p.SetOrientation(particle_orientation);
+				
+				OnRicochetCalculations(p, outSpeedf);
+			}
+		}
+		else
+		{
+			p = gPM.PlayInWorld(m_ParticleEnter, m_Pos );
+			
+			if (p)
+			{
+				if (m_SurfNormal != INVALID)
+				{
+					particle_orientation = m_SurfNormal.VectorToAngles();
+					particle_orientation = particle_orientation + "0 270 0";
+				}
+				else
+				{
+					particle_orientation = "0 0 0"; // This vector is in angles
+				}
+				
+				p.SetOrientation(particle_orientation);
+			
+				OnEnterCalculations(p);
+			}
+			
+			if (outSpeedf > 0  &&  m_SurfNormal != INVALID)
+			{
+				p = gPM.PlayInWorld(m_ParticleExit, m_ExitPos);
+				
+				if (p)
+				{
+					particle_orientation = m_OutSpeed.VectorToAngles();
+					particle_orientation = particle_orientation + "0 -90 0";
+					p.SetOrientation(particle_orientation);
+					
+					OnExitCalculations(p, outSpeedf);
+				}
+			}
+			else
+			{
+				if (m_SurfNormal != INVALID)
+				{
+					vector surfNormalN = m_SurfNormal.Normalized();
+					vector inSpeedN = m_InSpeed.Normalized();
+					vector bounce_ori = surfNormalN + inSpeedN;
+					
+					float dot = vector.Dot(bounce_ori, surfNormalN);
+					
+					if ( dot > m_AngledEnter )
+					{
+						p = gPM.PlayInWorld(m_ParticleRicochet, m_Pos);
+			
+						if (p)
+						{
+							particle_orientation = bounce_ori.VectorToAngles();
+							particle_orientation = particle_orientation + "0 -90 0";
+							p.SetOrientation(particle_orientation);
+							
+							OnEnterAngledCalculations(p);
+						}
+					}
+				}
+			}
+		}
+		
+		if (p)
+		{
+			SetParticle(p);
+		}
+		
+		
+		// Additional impact particle over long ranges. It shows players where their bullets land
+		
+		if ( Type() != Hit_MeatBones )
+		{
+			vector camera_pos = GetGame().GetCurrentCameraPosition();
+			float distance = vector.Distance(camera_pos, m_Pos);
+						
+			// Additional size increase by distance from camera
+			float scaling_by_distance = distance * 0.01;
+			
+			// Now scale down the above size increase by player's zoom-in value
+			float current_FOV = Camera.GetCurrentFOV();
+			float config_FOV = GetDayZGame().GetUserFOVFromConfig();
+			float FOV_scale = current_FOV / config_FOV;
+			scaling_by_distance = 1 + scaling_by_distance * FOV_scale;
+			
+			if (scaling_by_distance > 1.1)
+			{
+				Particle p_distant = gPM.PlayInWorld(ParticleList.IMPACT_DISTANT_DUST, m_Pos);
+				
+				particle_orientation = m_SurfNormal.VectorToAngles();
+				particle_orientation[1] = particle_orientation[1] + 270;
+				p_distant.SetOrientation(particle_orientation);
+				
+				p_distant.ScaleParticleParam(EmitorParam.SIZE, scaling_by_distance - 0.5);
+				p_distant.ScaleParticleParam(EmitorParam.BIRTH_RATE, scaling_by_distance * 0.1);
+				p_distant.ScaleParticleParam(EmitorParam.BIRTH_RATE_RND, scaling_by_distance * 0.1);
+				p_distant.ScaleParticleParam(EmitorParam.LIFETIME, scaling_by_distance * 0.3);
+				p_distant.ScaleParticleParam(EmitorParam.LIFETIME_RND, scaling_by_distance * 0.3);
+			}
+		}
+	}
+}

+ 11 - 0
Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_concrete.c

@@ -0,0 +1,11 @@
+class Hit_Concrete : EffBulletImpactBase
+{
+	void Hit_Concrete()
+	{
+		SetEnterParticle(ParticleList.IMPACT_CONCRETE_ENTER);
+		SetExitParticle(ParticleList.IMPACT_CONCRETE_EXIT);
+		SetRicochetParticle(ParticleList.IMPACT_CONCRETE_RICOCHET);
+		
+		m_AngledEnter = 0.50;
+	}
+}

+ 9 - 0
Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_dirt.c

@@ -0,0 +1,9 @@
+class Hit_Dirt : EffBulletImpactBase
+{
+	void Hit_Dirt()
+	{
+		SetEnterParticle(ParticleList.IMPACT_DIRT_ENTER);
+		SetExitParticle(ParticleList.IMPACT_DIRT_EXIT);
+		SetRicochetParticle(ParticleList.IMPACT_DIRT_RICOCHET);
+	}
+}

+ 11 - 0
Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_error.c

@@ -0,0 +1,11 @@
+class Hit_ErrorNoMaterial : EffBulletImpactBase
+{
+	void Hit_ErrorNoMaterial()
+	{
+		#ifdef DEVELOPER
+		SetSingleParticle(ParticleList.IMPACT_TEST_NO_MATERIAL_ERROR);
+		#else
+		SetSingleParticle(ParticleList.IMPACT_TEST);
+		#endif
+	}
+}

+ 23 - 0
Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_foliage.c

@@ -0,0 +1,23 @@
+class Hit_Foliage : EffBulletImpactBase
+{
+	void Hit_Foliage()
+	{
+		SetEnterParticle(ParticleList.IMPACT_FOLIAGE_ENTER);
+		SetExitParticle(ParticleList.IMPACT_FOLIAGE_EXIT);
+		SetRicochetParticle(ParticleList.IMPACT_FOLIAGE_RICOCHET);
+	}
+	
+	override float CalculateStoppingForce(float in_speedf, float out_speedf, string ammoType, float weight)
+	{
+		if ( m_ImpactType == ImpactTypes.MELEE )
+		{
+			return 500;
+		}
+		
+		float projectile_weight_coef = weight / DEFAULT_PROJECTILE_WEIGHT;
+		
+		float stopping_force = in_speedf * projectile_weight_coef * 0.5;
+				
+		return stopping_force;
+	}
+}

+ 9 - 0
Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_glass.c

@@ -0,0 +1,9 @@
+class Hit_Glass : EffBulletImpactBase
+{
+	void Hit_Glass()
+	{
+		SetEnterParticle(ParticleList.IMPACT_GLASS_ENTER);
+		SetExitParticle(ParticleList.IMPACT_GLASS_EXIT);
+		SetRicochetParticle(ParticleList.IMPACT_GLASS_RICOCHET);
+	}
+}

+ 9 - 0
Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_glass_thin.c

@@ -0,0 +1,9 @@
+class Hit_Glass_Thin : EffBulletImpactBase
+{
+	void Hit_Glass_Thin()
+	{
+		SetEnterParticle(ParticleList.IMPACT_GLASS_ENTER);
+		SetExitParticle(ParticleList.IMPACT_GLASS_EXIT);
+		SetRicochetParticle(ParticleList.IMPACT_GLASS_RICOCHET);
+	}
+}

+ 11 - 0
Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_grass.c

@@ -0,0 +1,11 @@
+class Hit_Grass : EffBulletImpactBase
+{
+	void Hit_Grass()
+	{
+		SetEnterParticle(ParticleList.IMPACT_GRASS_ENTER);
+		SetExitParticle(ParticleList.IMPACT_GRASS_ENTER);
+		SetRicochetParticle(ParticleList.IMPACT_GRASS_RICOCHET);
+		
+		m_AngledEnter = 0.6;
+	}
+}

+ 9 - 0
Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_gravel.c

@@ -0,0 +1,9 @@
+class Hit_Gravel : EffBulletImpactBase
+{
+	void Hit_Gravel()
+	{
+		SetEnterParticle(ParticleList.IMPACT_GRAVEL_ENTER);
+		SetExitParticle(ParticleList.IMPACT_GRAVEL_EXIT);
+		SetRicochetParticle(ParticleList.IMPACT_GRAVEL_RICOCHET);
+	}
+}

+ 9 - 0
Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_ice.c

@@ -0,0 +1,9 @@
+class Hit_Ice : EffBulletImpactBase
+{
+	void Hit_Ice()
+	{
+		SetEnterParticle(ParticleList.IMPACT_ICE_ENTER);
+		SetExitParticle(ParticleList.IMPACT_ICE_EXIT);
+		SetRicochetParticle(ParticleList.IMPACT_ICE_RICOCHET);
+	}
+}

+ 201 - 0
Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_meatbones.c

@@ -0,0 +1,201 @@
+class Hit_MeatBones : EffBulletImpactBase
+{
+	float m_ScalingByDistance;
+	
+	void Hit_MeatBones()
+	{
+		SetEnterParticle(ParticleList.IMPACT_MEATBONES_ENTER);
+		SetExitParticle(ParticleList.IMPACT_MEATBONES_EXIT);
+		SetRicochetParticle(ParticleList.IMPACT_MEATBONES_RICOCHET);
+		
+		m_AngledEnter = 10;
+		m_EnterSplashCoef = 0.002;
+		m_ExitSplashCoef = 0.006;
+		m_ScalingByDistance = 0.05;
+		
+		MIN_SCALING_PARAM = 0.2;
+	}
+	
+	override float CalculateStoppingForce(float in_speedf, float out_speedf, string ammoType, float weight)
+	{
+		if ( m_ImpactType == ImpactTypes.MELEE )
+		{
+			return 400;
+		}
+		
+		float projectile_weight_coef = weight / DEFAULT_PROJECTILE_WEIGHT;
+		
+		float stopping_force = in_speedf * projectile_weight_coef;
+		
+		if (m_DirectHit)
+		{
+			/*
+			// TO DO: Doesn't work because IsAlive() is false, even when it shouldn't be.
+			if ( m_DirectHit.IsMan()  &&  m_componentIndex == SURVIVOR_HEAD  &&  m_DirectHit.IsAlive() ) // Is the victim a survivor?
+			{
+				stopping_force = stopping_force * 2;
+			}
+			*/
+			
+			/*
+			// TO DO: Doesn't work. Need to recognize a zombie somehow
+			else if ( m_DirectHit.IsInherited(DayZCreatureAIType)  &&  m_componentIndex == INFECTED_HEAD ) // Is the victim a survivor that's hit in the head?
+			{
+				stopping_force = stopping_force * 2;
+			}*/
+		}
+		
+		return stopping_force;
+	}
+
+	override void Event_OnStarted()
+	{
+		super.Event_OnStarted();
+		
+		if (m_ImpactType != ImpactTypes.MELEE)
+		{
+			vector in_speed = m_InSpeed * (-1); // Compiler demands to have this variable
+			
+			BloodSplatGround( GetPosition(), in_speed , 0.5 );
+			
+			if (m_OutSpeed.Length() > 0)
+			{
+				BloodSplatGround( m_ExitPos, m_OutSpeed, 0.8  );
+			}
+		}
+	}
+	
+	void BloodSplatGround( vector start_pos, vector speed_vector, float decay_coef )
+	{
+		vector pos = start_pos;
+		float power = m_StoppingForce;
+		float upscale = 1;
+		float rnd_offset = 0.5;
+		float rnd_offset_2 = rnd_offset * 0.5;
+		
+		while (power > 200)
+		{
+			pos = pos + ( speed_vector * 0.001 );
+			pos = pos + Vector( rnd_offset_2 - Math.RandomFloat( 0, rnd_offset ), 0, rnd_offset_2 - Math.RandomFloat( 0, rnd_offset ) );
+			pos[1] = GetGame().SurfaceY(pos[0], pos[2]);
+			
+			EffectParticle eff = new BloodSplatter();
+			eff.SetAutodestroy(true);
+			SEffectManager.PlayInWorld(eff, pos);
+			
+			Particle blood = eff.GetParticle(); // TO DO: Handle particle changes inside the Effect instance itself! Not here!
+
+			vector ori = GetGame().GetSurfaceOrientation(pos[0], pos[2]);
+						
+			blood.SetOrientation(ori);
+			blood.ScaleParticleParam(EmitorParam.SIZE, upscale);
+			
+			Particle blood_chunks = ParticleManager.GetInstance().PlayInWorld(ParticleList.BLOOD_SURFACE_CHUNKS, pos);
+			blood_chunks.SetOrientation(ori);
+			
+			power = power * decay_coef;
+			upscale = upscale + Math.RandomFloat(0.1, 1);			
+			
+			BloodSplatWall();
+		}
+	}
+	
+	void BloodSplatWall()
+	{
+		// Commented out due to age rating process :(
+		
+		/*
+		if (m_OutSpeed.Length() > 0)
+		{
+			Object projected_surface;
+			vector hit_pos;
+			vector hit_normal;
+			float hit_fraction; 
+			DayZPhysics.RayCastBullet(m_ExitPos, m_ExitPos + m_OutSpeed, PhxInteractionLayers.BUILDING, m_Object, projected_surface, hit_pos, hit_normal, hit_fraction);
+			
+			hit_normal = hit_normal.VectorToAngles();
+			hit_normal[1] = hit_normal[1] + 90;
+			
+			EffectParticle eff = new BloodSplatter();
+			eff.SetAutodestroy(true);
+			SEffectManager.PlayInWorld(eff, hit_pos);
+			Particle blood = eff.GetParticle();
+			blood.SetOrientation(hit_normal);
+		}
+		*/
+	}
+	
+	override void OnEnterCalculations( Particle p )
+	{
+		// Calculate particle's size based on bullet's speed
+		float velocity_min = MIN_SCALING_PARAM + (m_StoppingForce * m_EnterSplashCoef);
+		float velocity_max = MIN_SCALING_PARAM + (m_StoppingForce * m_EnterSplashCoef);
+		float size = MIN_SCALING_PARAM + ( m_StoppingForce * m_EnterSplashCoef);
+		float birth_rate = MIN_SCALING_PARAM + (m_StoppingForce * m_EnterSplashCoef/2);
+		
+		if ( m_AmmoType == "Bullet_12GaugePellets" )
+		{
+			birth_rate *= 0.5;
+			velocity_min *= 2;
+			velocity_max *= 2;
+		}
+		
+		// Additional size increase by distance from camera
+		vector camera_pos = GetGame().GetCurrentCameraPosition();
+		float distance = vector.Distance(camera_pos, m_Pos);
+		float scaling_by_distance = (distance*1.2) * m_ScalingByDistance;
+		
+		// Now scale down the above size increase by player's zoom-in value
+		float current_FOV = Camera.GetCurrentFOV();
+		float config_FOV = GetDayZGame().GetUserFOVFromConfig();
+		float FOV_scale = current_FOV / config_FOV;
+		scaling_by_distance = scaling_by_distance * FOV_scale;
+
+		if (scaling_by_distance > 5)
+			scaling_by_distance = 5;
+		
+		size = size + scaling_by_distance;
+		velocity_min = velocity_min + scaling_by_distance;
+		velocity_max = velocity_max + scaling_by_distance;
+		
+		if (velocity_min < MIN_SCALING_PARAM)
+			velocity_min = MIN_SCALING_PARAM;
+		
+		if (velocity_max < MIN_SCALING_PARAM * 2)
+			velocity_max = MIN_SCALING_PARAM * 2;
+		
+		if (size < MIN_SCALING_PARAM)
+			size = MIN_SCALING_PARAM;
+		
+		if (birth_rate < MIN_SCALING_PARAM)
+			birth_rate = MIN_SCALING_PARAM;
+		
+		p.ScaleParticleParam(EmitorParam.VELOCITY, velocity_min);
+		p.ScaleParticleParam(EmitorParam.VELOCITY_RND, velocity_max);
+		p.ScaleParticleParam(EmitorParam.SIZE, size);
+		p.ScaleParticleParam(EmitorParam.BIRTH_RATE, birth_rate);
+	}
+	
+	override void OnExitCalculations(Particle p, float outSpeedf)
+	{
+		float velocity_rnd = outSpeedf * m_ExitSplashCoef;
+		float birth_rate_rnd_def = outSpeedf * m_ExitSplashCoef;
+		float size = outSpeedf * m_ExitSplashCoef;
+		
+		if (velocity_rnd < MIN_SCALING_PARAM)
+			velocity_rnd = MIN_SCALING_PARAM;
+		
+		if (size < MIN_SCALING_PARAM)
+			size = MIN_SCALING_PARAM;
+		
+		if (size > 1)
+			size = 1;
+		
+		if (birth_rate_rnd_def < MIN_SCALING_PARAM)
+			birth_rate_rnd_def = MIN_SCALING_PARAM;
+		
+		p.ScaleParticleParam(EmitorParam.VELOCITY_RND, velocity_rnd);
+		p.ScaleParticleParam(EmitorParam.BIRTH_RATE, birth_rate_rnd_def);
+		p.ScaleParticleParam(EmitorParam.SIZE, size);
+	}
+}

+ 7 - 0
Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_meatbones/hit_meatbones_meleefist.c

@@ -0,0 +1,7 @@
+class Hit_MeatBones_MeleeFist : Hit_MeatBones
+{
+	void Hit_MeatBones_MeleeFist()
+	{
+		SetSingleParticle(ParticleList.INVALID);
+	}
+}

+ 7 - 0
Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_meatbones/hit_meatbones_meleepipewrench.c

@@ -0,0 +1,7 @@
+class Hit_MeatBones_MeleePipeWrench : Hit_MeatBones
+{
+	void Hit_MeatBones_MeleePipeWrench()
+	{
+
+	}
+}

+ 7 - 0
Scripts/3_game/effects/effectparticle/bulletimpactbase/hit_meatbones/hit_meatbones_meleeshovel.c

@@ -0,0 +1,7 @@
+class Hit_MeatBones_MeleeShovel : Hit_MeatBones
+{
+	void Hit_MeatBones_MeleeShovel()
+	{
+
+	}
+}

Some files were not shown because too many files changed in this diff