diff --git a/src/testsuite/zr/knockback.sp b/src/testsuite/zr/knockback.sp
new file mode 100644
index 0000000..522d820
--- /dev/null
+++ b/src/testsuite/zr/knockback.sp
@@ -0,0 +1,219 @@
+/*
+ * ============================================================================
+ *
+ * Zombie:Reloaded
+ *
+ * File: knockback.sp
+ * Type: Test plugin
+ * Description: Tests basic knock back.
+ *
+ * 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
+#include
+
+public Plugin:myinfo =
+{
+ name = "Knock back",
+ author = "Greyscale | Richard Helgeby",
+ description = "Tests basic knock back.",
+ version = "1.0.0",
+ url = "http://code.google.com/p/zombiereloaded/"
+};
+
+new Handle:hKnockBackMultiplier;
+new g_iToolsVelocity;
+
+public OnPluginStart()
+{
+ hKnockBackMultiplier = CreateConVar("zrtest_knockback", "4.0", "Knock back multiplier.");
+
+ /*if (!HookEventEx("player_hurt", Event_PlayerHurt))
+ {
+ LogError("Failed to hook event player_hurt.");
+ }*/
+
+ // If offset "m_vecVelocity[0]" can't be found, then stop the plugin.
+ g_iToolsVelocity = FindSendPropInfo("CBasePlayer", "m_vecVelocity[0]");
+ if (g_iToolsVelocity == -1)
+ {
+ LogError("Offset \"CBasePlayer::m_vecVelocity[0]\" was not found.");
+ }
+}
+
+public OnClientPutInServer(client)
+{
+ SDKHook(client, SDKHook_OnTakeDamagePost, OnTakeDamagePost);
+}
+
+public OnClientDisconnect(client)
+{
+ SDKUnhook(client, SDKHook_OnTakeDamagePost, OnTakeDamagePost);
+}
+
+/*public Action:Event_PlayerHurt(Handle:event, const String:name[], bool:dontBroadcast)
+{
+ new victim = GetClientOfUserId(GetEventInt(event, "userid"));
+ new damage = GetEventInt(event, "dmg_health");
+}*/
+
+public Action:OnTakeDamage(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3])
+{
+ KnockbackOnClientHurt(victim, attacker, Float:damage);
+
+ // Allow damage.
+ return Plugin_Continue;
+}
+
+public OnTakeDamagePost(victim, attacker, inflictor, Float:damage, damagetype, weapon, const Float:damageForce[3], const Float:damagePosition[3])
+{
+ if (attacker > 0 && attacker < MaxClients)
+ {
+ KnockbackOnClientHurt(victim, attacker, Float:damage);
+ }
+}
+
+/** Client has been hurt.
+ *
+ * @param client The client index. (zombie)
+ * @param attacker The attacker index. (human)
+ * @param weapon The weapon used.
+ * @param hitgroup Hitgroup attacker has damaged.
+ * @param dmg_health Damage done.
+ */
+KnockbackOnClientHurt(client, attacker, Float:dmg_health)
+{
+ // If attacker is invalid, then stop.
+ if (!(attacker > 0 || attacker < MaxClients))
+ {
+ return;
+ }
+
+ // Get zombie knockback value.
+ new Float:knockback = GetConVarFloat(hKnockBackMultiplier);
+
+ new Float:clientloc[3];
+ new Float:attackerloc[3];
+
+ GetClientAbsOrigin(client, clientloc);
+
+ // Get attackers eye position.
+ GetClientEyePosition(attacker, attackerloc);
+
+ // Get attackers eye angles.
+ new Float:attackerang[3];
+ GetClientEyeAngles(attacker, attackerang);
+
+ // Calculate knockback end-vector.
+ TR_TraceRayFilter(attackerloc, attackerang, MASK_ALL, RayType_Infinite, KnockbackTRFilter);
+ TR_GetEndPosition(clientloc);
+
+ // Apply damage knockback multiplier.
+ knockback *= dmg_health;
+
+ // Apply knockback.
+ KnockbackSetVelocity(client, attackerloc, clientloc, knockback);
+}
+
+/**
+ * Sets velocity on a player.
+ *
+ * @param client The client index.
+ * @param startpoint The starting coordinate to push from.
+ * @param endpoint The ending coordinate to push towards.
+ * @param magnitude Magnitude of the push.
+ */
+KnockbackSetVelocity(client, const Float:startpoint[3], const Float:endpoint[3], Float:magnitude)
+{
+ // Create vector from the given starting and ending points.
+ new Float:vector[3];
+ MakeVectorFromPoints(startpoint, endpoint, vector);
+
+ // Normalize the vector (equal magnitude at varying distances).
+ NormalizeVector(vector, vector);
+
+ // Apply the magnitude by scaling the vector (multiplying each of its components).
+ ScaleVector(vector, magnitude);
+
+ // ADD the given vector to the client's current velocity.
+ ToolsClientVelocity(client, vector);
+}
+
+/**
+ * Get or set a client's velocity.
+ * @param client The client index.
+ * @param vecVelocity Array to store vector in, or velocity to set on client.
+ * @param retrieve True to get client's velocity, false to set it.
+ * @param stack If modifying velocity, then true will stack new velocity onto the client's
+ * current velocity, false will reset it.
+ */
+stock ToolsClientVelocity(client, Float:vecVelocity[3], bool:apply = true, bool:stack = true)
+{
+ // If retrieve if true, then get client's velocity.
+ if (!apply)
+ {
+ // x = vector component.
+ for (new x = 0; x < 3; x++)
+ {
+ vecVelocity[x] = GetEntDataFloat(client, g_iToolsVelocity + (x*4));
+ }
+
+ // Stop here.
+ return;
+ }
+
+ // If stack is true, then add client's velocity.
+ if (stack)
+ {
+ // Get client's velocity.
+ new Float:vecClientVelocity[3];
+
+ // x = vector component.
+ for (new x = 0; x < 3; x++)
+ {
+ vecClientVelocity[x] = GetEntDataFloat(client, g_iToolsVelocity + (x*4));
+ }
+
+ AddVectors(vecClientVelocity, vecVelocity, vecVelocity);
+ }
+
+ // Apply velocity on client.
+ TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, vecVelocity);
+}
+
+/**
+ * Trace Ray forward, used as a filter to continue tracing if told so. (See sdktools_trace.inc)
+ *
+ * @param entity The entity index.
+ * @param contentsMask The contents mask.
+ * @return True to allow hit, false to continue tracing.
+ */
+public bool:KnockbackTRFilter(entity, contentsMask)
+{
+ // If entity is a player, continue tracing.
+ if (entity > 0 && entity < MAXPLAYERS)
+ {
+ return false;
+ }
+
+ // Allow hit.
+ return true;
+}
\ No newline at end of file