diff --git a/env/include/sdkhooks-2.2.inc b/env/include/sdkhooks-2.2.inc
new file mode 100644
index 0000000..d09c17f
--- /dev/null
+++ b/env/include/sdkhooks-2.2.inc
@@ -0,0 +1,345 @@
+#if defined _sdkhooks_included
+ #endinput
+#endif
+#define _sdkhooks_included
+
+// this is obviously _not_ a robust check, but it will solve most conflict and is clean
+#if !defined DMG_GENERIC
+#define DMG_GENERIC 0 // generic damage was done
+#define DMG_CRUSH (1 << 0) // crushed by falling or moving object.
+ // NOTE: It's assumed crush damage is occurring as a result of physics collision, so no extra physics force is generated by crush damage.
+ // DON'T use DMG_CRUSH when damaging entities unless it's the result of a physics collision. You probably want DMG_CLUB instead.
+#define DMG_BULLET (1 << 1) // shot
+#define DMG_SLASH (1 << 2) // cut, clawed, stabbed
+#define DMG_BURN (1 << 3) // heat burned
+#define DMG_VEHICLE (1 << 4) // hit by a vehicle
+#define DMG_FALL (1 << 5) // fell too far
+#define DMG_BLAST (1 << 6) // explosive blast damage
+#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt
+#define DMG_SHOCK (1 << 8) // electric shock
+#define DMG_SONIC (1 << 9) // sound pulse shockwave
+#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam
+#define DMG_PREVENT_PHYSICS_FORCE (1 << 11) // Prevent a physics force
+#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death
+#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death.
+#define DMG_DROWN (1 << 14) // Drowning
+#define DMG_PARALYZE (1 << 15) // slows affected creature down
+#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad
+#define DMG_POISON (1 << 17) // blood poisoning - heals over time like drowning damage
+#define DMG_RADIATION (1 << 18) // radiation exposure
+#define DMG_DROWNRECOVER (1 << 19) // drowning recovery
+#define DMG_ACID (1 << 20) // toxic chemicals or acid burns
+#define DMG_SLOWBURN (1 << 21) // in an oven
+#define DMG_REMOVENORAGDOLL (1 << 22) // with this bit OR'd in, no ragdoll will be created, and the target will be quietly removed.
+ // use this to kill an entity that you've already got a server-side ragdoll for
+#define DMG_PHYSGUN (1 << 23) // Hit by manipulator. Usually doesn't do any damage.
+#define DMG_PLASMA (1 << 24) // Shot by Cremator
+#define DMG_AIRBOAT (1 << 25) // Hit by the airboat's gun
+#define DMG_DISSOLVE (1 << 26) // Dissolving!
+#define DMG_BLAST_SURFACE (1 << 27) // A blast on the surface of water that cannot harm things underwater
+#define DMG_DIRECT (1 << 28)
+#define DMG_BUCKSHOT (1 << 29) // not quite a bullet. Little, rounder, different.
+#endif
+
+#if !defined DMG_CRIT
+ // TF2 crits and minicrits
+ #define DMG_CRIT DMG_ACID
+#endif
+
+enum SDKHookType
+{
+ SDKHook_EndTouch,
+ SDKHook_FireBulletsPost,
+ SDKHook_OnTakeDamage,
+ SDKHook_OnTakeDamagePost,
+ SDKHook_PreThink,
+ SDKHook_PostThink,
+ SDKHook_SetTransmit,
+ SDKHook_Spawn,
+ SDKHook_StartTouch,
+ SDKHook_Think,
+ SDKHook_Touch,
+ SDKHook_TraceAttack,
+ SDKHook_TraceAttackPost,
+ SDKHook_WeaponCanSwitchTo,
+ SDKHook_WeaponCanUse,
+ SDKHook_WeaponDrop,
+ SDKHook_WeaponEquip,
+ SDKHook_WeaponSwitch,
+ SDKHook_ShouldCollide,
+ SDKHook_PreThinkPost,
+ SDKHook_PostThinkPost,
+ SDKHook_ThinkPost,
+ SDKHook_EndTouchPost,
+ SDKHook_GroundEntChangedPost,
+ SDKHook_SpawnPost,
+ SDKHook_StartTouchPost,
+ SDKHook_TouchPost,
+ SDKHook_VPhysicsUpdate,
+ SDKHook_VPhysicsUpdatePost,
+ SDKHook_WeaponCanSwitchToPost,
+ SDKHook_WeaponCanUsePost,
+ SDKHook_WeaponDropPost,
+ SDKHook_WeaponEquipPost,
+ SDKHook_WeaponSwitchPost,
+ SDKHook_Use,
+ SDKHook_UsePost
+};
+
+/*
+ Alphabetized for easy readability
+
+ SDKHook_EndTouch,
+ SDKHook_EndTouchPost,
+
+ SDKHook_FireBulletsPost,
+
+ SDKHook_GroundEntChangedPost,
+
+ SDKHook_OnTakeDamage,
+ SDKHook_OnTakeDamagePost,
+
+ SDKHook_PreThink,
+ SDKHook_PreThinkPost,
+
+ SDKHook_PostThink,
+ SDKHook_PostThinkPost,
+
+ SDKHook_SetTransmit,
+
+ SDKHook_ShouldCollide,
+
+ SDKHook_Spawn,
+ SDKHook_SpawnPost,
+
+ SDKHook_StartTouch,
+ SDKHook_StartTouchPost,
+
+ SDKHook_Think,
+ SDKHook_ThinkPost,
+
+ SDKHook_Touch,
+ SDKHook_TouchPost,
+
+ SDKHook_TraceAttack,
+ SDKHook_TraceAttackPost,
+
+ SDKHook_Use,
+ SDKHook_UsePost,
+
+ SDKHook_VPhysicsUpdate,
+ SDKHook_VPhysicsUpdatePost,
+
+ SDKHook_WeaponCanSwitchTo,
+ SDKHook_WeaponCanSwitchToPost,
+
+ SDKHook_WeaponCanUse,
+ SDKHook_WeaponCanUsePost,
+
+ SDKHook_WeaponDrop,
+ SDKHook_WeaponDropPost,
+
+ SDKHook_WeaponEquip,
+ SDKHook_WeaponEquipPost,
+
+ SDKHook_WeaponSwitch,
+ SDKHook_WeaponSwitchPost
+*/
+
+enum UseType
+{
+ Use_Off,
+ Use_On,
+ Use_Set,
+ Use_Toggle
+};
+
+funcenum SDKHookCB
+{
+ // PreThink/Post
+ // PostThink/Post
+ public(client),
+
+ // GroundEntChanged
+ // Spawn/Post
+ // Think/Post
+ // VPhysicsUpdate/Post
+ public(entity),
+
+ // EndTouch
+ // StartTouch
+ // Touch
+ Action:public(entity, other),
+
+ // EndTouchPost
+ // StartTouchPost
+ // TouchPost
+ public(entity, other),
+
+ // SetTransmit
+ Action:public(entity, client),
+
+ // WeaponCanSwitchTo
+ // WeaponCanUse
+ // WeaponDrop
+ // WeaponEquip
+ // WeaponSwitch
+ Action:public(client, weapon),
+
+ // WeaponCanSwitchToPost
+ // WeaponCanUsePost
+ // WeaponDropPost
+ // WeaponEquipPost
+ // WeaponSwitchPost
+ public(client, weapon),
+
+ // OnTakeDamage
+ // Note: Force application is dependent on game and damage type(s)
+ Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype),
+ Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3]),
+
+ // OnTakeDamagePost
+ public(victim, attacker, inflictor, Float:damage, damagetype),
+ public(victim, attacker, inflictor, Float:damage, damagetype, weapon, const Float:damageForce[3], const Float:damagePosition[3]),
+
+ // FireBulletsPost
+ public(client, shots, const String:weaponname[]),
+
+ // TraceAttack
+ Action:public(victim, &attacker, &inflictor, &Float:damage, &damagetype, &ammotype, hitbox, hitgroup),
+
+ // TraceAttackPost
+ public(victim, attacker, inflictor, Float:damage, damagetype, ammotype, hitbox, hitgroup),
+
+ // ShouldCollide
+ bool:public(entity, collisiongroup, contentsmask, bool:originalResult),
+
+ // Use
+ Action:public(entity, activator, caller, UseType:type, Float:value),
+
+ // UsePost
+ public(entity, activator, caller, UseType:type, Float:value)
+};
+
+
+/**
+ * @brief When an entity is created
+ *
+ * @param entity Entity index
+ * @param classname Class name
+ * @noreturn
+ */
+forward OnEntityCreated(entity, const String:classname[]);
+
+/**
+ * @brief When an entity is destroyed
+ *
+ * @param entity Entity index
+ * @noreturn
+ */
+forward OnEntityDestroyed(entity);
+
+/**
+ * @brief When the game description is retrieved
+ *
+ * @param gameDesc Game description
+ * @noreturn
+ */
+forward Action:OnGetGameDescription(String:gameDesc[64]);
+
+/**
+ * @brief When the level is initialized
+ *
+ * @param mapName Name of the map
+ * @param mapEntities Entities of the map
+ * @noreturn
+ */
+forward Action:OnLevelInit(const String:mapName[], String:mapEntities[2097152]);
+
+/**
+ * @brief Hooks an entity
+ *
+ * @param entity Entity index
+ * @param type Type of function to hook
+ * @param callback Function to call when hook is called
+ * @noreturn
+ */
+native SDKHook(entity, SDKHookType:type, SDKHookCB:callback);
+
+/**
+ * @brief Hooks an entity
+ *
+ * @param entity Entity index
+ * @param type Type of function to hook
+ * @param callback Function to call when hook is called
+ * @return bool Hook Successful
+ */
+native bool:SDKHookEx(entity, SDKHookType:type, SDKHookCB:callback);
+
+/**
+ * @brief Unhooks an entity
+ *
+ * @param entity Entity index
+ * @param type Type of function to unhook
+ * @param callback Callback function to unhook
+ * @noreturn
+ */
+native SDKUnhook(entity, SDKHookType:type, SDKHookCB:callback);
+
+/**
+ * @brief Applies damage to an entity
+ *
+ * @note Force application is dependent on game and damage type(s)
+ *
+ * @param entity Entity index taking damage
+ * @param inflictor Inflictor entity index
+ * @param attacker Attacker entity index
+ * @param damage Amount of damage
+ * @param damageType Bitfield of damage types
+ * @param weapon Weapon index (orangebox and later) or -1 for unspecified
+ * @param damageForce Velocity of damage force
+ * @param damagePosition Origin of damage
+ * @noreturn
+ */
+native SDKHooks_TakeDamage(entity, inflictor, attacker, Float:damage, damageType=DMG_GENERIC, weapon=-1, const Float:damageForce[3]=NULL_VECTOR, const Float:damagePosition[3]=NULL_VECTOR);
+
+/**
+ * @brief Forces a client to drop the specified weapon
+ *
+ * @param client Client index.
+ * @param weapon Weapon entity index.
+ * @param vecTarget Location to toss weapon to, or NULL_VECTOR for default.
+ * @param vecVelocity Velocity at which to toss weapon, or NULL_VECTOR for default.
+ * @noreturn
+ * @error Invalid client or weapon entity, weapon not owned by client.
+ */
+native SDKHooks_DropWeapon(client, weapon, const Float:vecTarget[3]=NULL_VECTOR, const Float:vecVelocity[3]=NULL_VECTOR);
+
+/** Do Not Edit Below This Line **/
+
+public Extension:__ext_sdkhooks =
+{
+ name = "sdkhooks",
+ file = "sdkhooks.ext",
+#if defined AUTOLOAD_EXTENSIONS
+ autoload = 1,
+#else
+ autoload = 0,
+#endif
+#if defined REQUIRE_EXTENSIONS
+ required = 1,
+#else
+ required = 0,
+#endif
+};
+
+#if !defined REQUIRE_EXTENSIONS
+public __ext_sdkhooks_SetNTVOptional()
+{
+ MarkNativeAsOptional("SDKHook");
+ MarkNativeAsOptional("SDKHookEx");
+ MarkNativeAsOptional("SDKUnhook");
+ MarkNativeAsOptional("SDKHooks_TakeDamage");
+ MarkNativeAsOptional("SDKHooks_DropWeapon");
+}
+#endif
diff --git a/src/testsuite/zr/damageinfo.sp b/src/testsuite/zr/damageinfo.sp
new file mode 100644
index 0000000..0f8ea63
--- /dev/null
+++ b/src/testsuite/zr/damageinfo.sp
@@ -0,0 +1,164 @@
+/*
+ * ============================================================================
+ *
+ * Zombie:Reloaded
+ *
+ * File: damageinfo.sp
+ * Type: Test plugin
+ * Description: Dumps damage information.
+ *
+ * Copyright (C) 2009-2012 Greyscale, Richard Helgeby
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * ============================================================================
+ */
+
+#pragma semicolon 1
+#include
+#include
+
+public Plugin:myinfo =
+{
+ name = "Damage information",
+ author = "Greyscale | Richard Helgeby",
+ description = "Dumps damage information.",
+ version = "1.0.0",
+ url = "http://code.google.com/p/zombiereloaded/"
+};
+
+new Handle:hBlockOnTakeDamage;
+new Handle:hBlockTraceAttack;
+
+public OnPluginStart()
+{
+ hBlockOnTakeDamage = CreateConVar("zrtest_blockontakedamage", "0", "Block OnTakeDamage.");
+ hBlockTraceAttack = CreateConVar("zrtest_blocktraceattack", "0", "Block TraceAttack.");
+
+ if (!HookEventEx("player_hurt", Event_PlayerHurt))
+ {
+ LogError("Failed to hook event player_hurt.");
+ }
+}
+
+public OnClientPutInServer(client)
+{
+ SDKHook(client, SDKHook_TraceAttack, TraceAttack);
+ SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);
+}
+
+public OnClientDisconnect(client)
+{
+ SDKUnhook(client, SDKHook_TraceAttack, TraceAttack);
+ SDKUnhook(client, SDKHook_OnTakeDamage, OnTakeDamage);
+}
+
+public Action:Event_PlayerHurt(Handle:event, const String:name[], bool:dontBroadcast)
+{
+ new victim = GetClientOfUserId(GetEventInt(event, "userid"));
+ new attacker = GetClientOfUserId(GetEventInt(event, "attacker"));
+ new hitgroup = GetEventInt(event, "hitgroup");
+ new damage = GetEventInt(event, "dmg_health");
+ new damageArmor = GetEventInt(event, "dmg_armor");
+ decl String:weapon[64];
+ weapon[0] = 0;
+ GetEventString(event, "weapon", weapon, sizeof(weapon));
+
+ decl String:msg[128];
+ msg[0] = 0;
+
+ Format(msg, sizeof(msg), "victim:%d | attacker:%d | hitgroup:%d | dmg:%d | dmg armor:%d | weapon:%s", victim, attacker, hitgroup, damage, damageArmor, weapon);
+
+ PrintToChat(victim, "Receive hurt event -- %s", msg);
+ PrintToConsole(victim, "Receive hurt event -- %s", msg);
+
+ if (attacker > 0 && attacker < MaxClients)
+ {
+ PrintToChat(attacker, "Send hurt event -- %s", msg);
+ PrintToConsole(attacker, "Send hurt event -- %s", msg);
+ }
+}
+
+public Action:OnTakeDamage(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3])
+{
+ /*
+ Here we can control whether bullets or other damage that hits the
+ victim's body should be allowed.
+
+ If TraceAttack is blocked, bullets will go through the body and the
+ attacker can't deal any damage to the victim.
+
+ By blocking OnTakeDamage we can use this to allow players to actually
+ hit a player without giving damage to him. This can be used as a simple
+ trace, for example healing the victim instead of damaging him.
+ */
+
+ decl String:msg[128];
+ msg[0] = 0;
+
+ Format(msg, sizeof(msg), "victim:%d | attacker:%d | inflictor:%d | dmg:%0.2f | dmg type:%d | weapon ent:%d | force:%0.2f | dmg pos:%0.2f", victim, attacker, inflictor, damage, damagetype, weapon, damageForce, damagePosition);
+
+ PrintToChat(victim, "Damage taken -- %s", msg);
+ PrintToConsole(victim, "Damage taken -- %s", msg);
+
+ if (attacker > 0 && attacker < MaxClients)
+ {
+ PrintToChat(attacker, "Damage given -- %s", msg);
+ PrintToConsole(attacker, "Damage given -- %s", msg);
+ }
+
+ if (GetConVarBool(hBlockOnTakeDamage))
+ {
+ return Plugin_Handled;
+ }
+ else
+ {
+ return Plugin_Continue;
+ }
+}
+
+public Action:TraceAttack(victim, &attacker, &inflictor, &Float:damage, &damagetype, &ammotype, hitbox, hitgroup)
+{
+ /*
+ Here we can control whether bullets or other damage is allowed to hit
+ the player's body.
+
+ If blocked, bullets will go through the body.
+
+ OnTakeDamage decides whether damage is actually allowed.
+ */
+
+ decl String:msg[128];
+ msg[0] = 0;
+
+ Format(msg, sizeof(msg), "victim:%d | attacker:%d | inflictor:%d | dmg:%0.2f | dmg type:%d | ammo type:%d | hitbox:%d | hitgroup: %d", victim, attacker, inflictor, damage, damagetype, ammotype, hitbox, hitgroup);
+
+ PrintToChat(victim, "Receive attack -- %s", msg);
+ PrintToConsole(victim, "Receive attack -- %s", msg);
+
+ if (attacker > 0 && attacker < MaxClients)
+ {
+ PrintToChat(attacker, "Attacking -- %s", msg);
+ PrintToConsole(attacker, "Attacking -- %s", msg);
+ }
+
+ if (GetConVarBool(hBlockTraceAttack))
+ {
+ return Plugin_Handled;
+ }
+ else
+ {
+ return Plugin_Continue;
+ }
+}