diff --git a/src/clientobject.h b/src/clientobject.h
index 2e1b850c74f51b271adb43c07e7ab05c2b7d5b0a..946858404af7040cd07fd39b68c47139b01c7b35 100644
--- a/src/clientobject.h
+++ b/src/clientobject.h
@@ -38,6 +38,8 @@ Some planning
 class ClientEnvironment;
 class ITextureSource;
 class IGameDef;
+class LocalPlayer;
+struct ItemStack;
 
 class ClientActiveObject : public ActiveObject
 {
@@ -75,7 +77,8 @@ class ClientActiveObject : public ActiveObject
 			ClientEnvironment *env);
 
 	// If returns true, punch will not be sent to the server
-	virtual bool directReportPunch(const std::string &toolname, v3f dir)
+	virtual bool directReportPunch(v3f dir, const ItemStack *punchitem=NULL,
+			float time_from_last_punch=1000000)
 	{ return false; }
 
 protected:
diff --git a/src/content_cao.cpp b/src/content_cao.cpp
index d6289a1b92e1d0ea8e72daa95603852afa747a35..836f719a3352bafb9ee6f63ddc39cb10b0624265 100644
--- a/src/content_cao.cpp
+++ b/src/content_cao.cpp
@@ -31,7 +31,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "content_object.h"
 #include "mesh.h"
 #include "utility.h" // For IntervalLimiter
+#include "itemdef.h"
+#include "tool.h"
 class Settings;
+struct ToolCapabilities;
 
 core::map<u16, ClientActiveObject::Factory> ClientActiveObject::m_types;
 
@@ -585,13 +588,41 @@ class LuaEntityCAO : public ClientActiveObject
 		}
 		else if(cmd == LUAENTITY_CMD_PUNCHED)
 		{
-			s16 damage = readS16(is);
+			/*s16 damage =*/ readS16(is);
 			s16 result_hp = readS16(is);
 			
 			m_hp = result_hp;
 			// TODO: Execute defined fast response
 		}
 	}
+	
+	bool directReportPunch(v3f dir, const ItemStack *punchitem=NULL,
+			float time_from_last_punch=1000000)
+	{
+		// TODO: Transfer this from the server
+		ItemGroupList m_armor_groups;
+		
+		assert(punchitem);
+		const ToolCapabilities *toolcap =
+				&punchitem->getToolCapabilities(m_gamedef->idef());
+		PunchDamageResult result = getPunchDamage(
+				m_armor_groups,
+				toolcap,
+				punchitem,
+				time_from_last_punch);
+		
+		if(result.did_punch)
+		{
+			// TODO: Decrease hp by 
+			if(result.damage < m_hp)
+				m_hp -= result.damage;
+			else
+				m_hp = 0;
+			// TODO: Execute defined fast response
+		}
+		
+		return false;
+	}
 };
 
 // Prototype
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index 5c03c90539d9db0832760d12b2db2cdc3d8613eb..0c105bb0f69d4ff4f270e8a520adb3f08d2e4d4a 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -531,33 +531,47 @@ int LuaEntitySAO::punch(v3f dir,
 		m_removed = true;
 		return 0;
 	}
-	lua_State *L = m_env->getLua();
-	scriptapi_luaentity_punch(L, m_id, puncher,
-			time_from_last_punch, toolcap, dir);
+	
+	ItemStack *punchitem = NULL;
+	ItemStack punchitem_static;
+	if(puncher){
+		punchitem_static = puncher->getWieldedItem();
+		punchitem = &punchitem_static;
+	}
 
-	HitParams hitparams = getHitParams(m_armor_groups, toolcap,
+	PunchDamageResult result = getPunchDamage(
+			m_armor_groups,
+			toolcap,
+			punchitem,
 			time_from_last_punch);
 	
-	actionstream<<getDescription()<<" punched by "
-			<<puncher->getDescription()<<", damage "<<hitparams.hp
-			<<" HP"<<std::endl;
-	
-	setHP(getHP() - hitparams.hp);
-	
+	if(result.did_punch)
 	{
-		std::ostringstream os(std::ios::binary);
-		// command 
-		writeU8(os, LUAENTITY_CMD_PUNCHED);
-		// damage
-		writeS16(os, hitparams.hp);
-		// result_hp
-		writeS16(os, getHP());
-		// create message and add to list
-		ActiveObjectMessage aom(getId(), true, os.str());
-		m_messages_out.push_back(aom);
+		actionstream<<getDescription()<<" punched by "
+				<<puncher->getDescription()<<", damage "<<result.damage
+				<<" HP"<<std::endl;
+		
+		setHP(getHP() - result.damage);
+		
+		{
+			std::ostringstream os(std::ios::binary);
+			// command 
+			writeU8(os, LUAENTITY_CMD_PUNCHED);
+			// damage
+			writeS16(os, result.damage);
+			// result_hp
+			writeS16(os, getHP());
+			// create message and add to list
+			ActiveObjectMessage aom(getId(), true, os.str());
+			m_messages_out.push_back(aom);
+		}
 	}
 
-	return hitparams.wear;
+	lua_State *L = m_env->getLua();
+	scriptapi_luaentity_punch(L, m_id, puncher,
+			time_from_last_punch, toolcap, dir);
+
+	return result.wear;
 }
 
 void LuaEntitySAO::rightClick(ServerActiveObject *clicker)
diff --git a/src/game.cpp b/src/game.cpp
index 594583fdc416f9b37e50e1fff952132e57970f6e..d5a733c60e5dbfc371c02027e9cd31b071fc1938 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -2088,10 +2088,13 @@ void the_game(
 				}
 				if(do_punch_damage){
 					// Report direct punch
-                		        v3f objpos = selected_object->getPosition();
-		                        v3f dir = (objpos - player_position).normalize();
-
-					bool disable_send = selected_object->directReportPunch(playeritem.name, dir);
+					v3f objpos = selected_object->getPosition();
+					v3f dir = (objpos - player_position).normalize();
+					
+					// TODO: Get time_from_last_punch from somewhere
+					float time_from_last_punch = 1000000;
+					bool disable_send = selected_object->directReportPunch(
+							dir, &playeritem, time_from_last_punch);
 					if(!disable_send)
 						client.interact(0, pointed);
 				}
diff --git a/src/tool.cpp b/src/tool.cpp
index da7ee73dc5124fc2d05e810c05eaa1bea57ec34a..d6f994307aeb00495e5b13555821e79a547d0f42 100644
--- a/src/tool.cpp
+++ b/src/tool.cpp
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "utility.h"
 #include "itemdef.h" // For itemgroup_get()
 #include "log.h"
+#include "inventory.h"
 
 void ToolCapabilities::serialize(std::ostream &os) const
 {
@@ -153,3 +154,36 @@ HitParams getHitParams(const ItemGroupList &groups,
 	return getHitParams(groups, tp, 1000000);
 }
 
+PunchDamageResult getPunchDamage(
+		const ItemGroupList &armor_groups,
+		const ToolCapabilities *toolcap,
+		const ItemStack *punchitem,
+		float time_from_last_punch
+){
+	bool do_hit = true;
+	{
+		if(do_hit && punchitem){
+			if(itemgroup_get(armor_groups, "punch_operable") &&
+					(toolcap == NULL || punchitem->name == ""))
+				do_hit = false;
+		}
+		if(do_hit){
+			if(itemgroup_get(armor_groups, "immortal"))
+				do_hit = false;
+		}
+	}
+	
+	PunchDamageResult result;
+	if(do_hit)
+	{
+		HitParams hitparams = getHitParams(armor_groups, toolcap,
+				time_from_last_punch);
+		result.did_punch = true;
+		result.wear = hitparams.wear;
+		result.damage = hitparams.hp;
+	}
+
+	return result;
+}
+
+
diff --git a/src/tool.h b/src/tool.h
index d2a9c13c81a358d6ddbdd9b9898be60df77f1482..685dfb5f2989410cbb4b86b2ddfe9c5d20e27d0d 100644
--- a/src/tool.h
+++ b/src/tool.h
@@ -108,5 +108,27 @@ HitParams getHitParams(const ItemGroupList &groups,
 HitParams getHitParams(const ItemGroupList &groups,
 		const ToolCapabilities *tp);
 
+struct PunchDamageResult
+{
+	bool did_punch;
+	int damage;
+	int wear;
+
+	PunchDamageResult():
+		did_punch(false),
+		damage(0),
+		wear(0)
+	{}
+};
+
+struct ItemStack;
+
+PunchDamageResult getPunchDamage(
+		const ItemGroupList &armor_groups,
+		const ToolCapabilities *toolcap,
+		const ItemStack *punchitem,
+		float time_from_last_punch
+);
+
 #endif