/* * ============================================================================ * * Zombie:Reloaded * * File: knockback.sp * Type: Test plugin * Description: Tests basic knock back. * * Copyright (C) 2009-2013 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; new bool:VelocityMonitor[MAXPLAYERS]; 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."); } RegConsoleCmd("zrtest_push_player", Command_PushPlayer, "Push a player. Usage: zrtest_push_player [0|1 - base velocity]"); RegConsoleCmd("zrtest_parent", Command_Parent, "Prints your parent entity."); RegConsoleCmd("zrtest_friction", Command_Friction, "Prints your floor friction multiplier."); RegConsoleCmd("zrtest_maxspeed", Command_MaxSpeed, "Prints your max speed."); } public Action:Command_PushPlayer(client, argc) { if (argc < 3) { ReplyToCommand(client, "Push a player. Usage: zrtest_push_player [0|1 - base velocity]"); return Plugin_Handled; } new Float:velocity[3]; new String:buffer[32]; new bool:baseVelocity = false; for (new i = 0; i < 3; i++) { GetCmdArg(i + 1, buffer, sizeof(buffer)); velocity[i] = StringToFloat(buffer); } if (argc > 3) { GetCmdArg(4, buffer, sizeof(buffer)); baseVelocity = bool:StringToInt(buffer); } PrintToChatAll("Applying velocity on client %d (base: %d): %0.2f | %0.2f | %0.2f", client, baseVelocity, velocity[0], velocity[1], velocity[2]); if (baseVelocity) { SetBaseVelocity(client, velocity); } else { TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, velocity); //SetVelocity(client, velocity); } return Plugin_Handled; } public Action:Command_Parent(client, argc) { new parent = GetParent(client); ReplyToCommand(client, "Parent index: %d", parent); return Plugin_Handled; } public Action:Command_Friction(client, argc) { new Float:friction = GetFriction(client); ReplyToCommand(client, "Friction: %0.2f", friction); return Plugin_Handled; } public Action:Command_MaxSpeed(client, argc) { new Float:maxSpeed = GetMaxSpeed(client); ReplyToCommand(client, "Max speed: %0.2f", maxSpeed); return Plugin_Handled; } public OnClientPutInServer(client) { //SDKHook(client, SDKHook_OnTakeDamagePost, OnTakeDamagePost); //SDKHook(client, SDKHook_PreThink, PreThink); //SDKHook(client, SDKHook_PreThinkPost, PreThinkPost); SDKHook(client, SDKHook_PostThink, PostThink); //SDKHook(client, SDKHook_PostThinkPost, PostThinkPost); } public OnClientDisconnect(client) { //SDKUnhook(client, SDKHook_OnTakeDamagePost, OnTakeDamagePost); //SDKUnhook(client, SDKHook_PreThink, PreThink); //SDKUnhook(client, SDKHook_PreThinkPost, PreThinkPost); SDKUnhook(client, SDKHook_PostThink, PostThink); //SDKUnhook(client, SDKHook_PostThinkPost, PostThinkPost); } public Action:Event_PlayerHurt(Handle:event, const String:name[], bool:dontBroadcast) { new victim = GetClientOfUserId(GetEventInt(event, "userid")); new damage = GetEventInt(event, "dmg_health"); new attacker = GetClientOfUserId(GetEventInt(event, "attacker")); KnockbackOnClientHurt(victim, attacker, float(damage)); } /*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); } }*/ /*public PreThink(client) { //if (VelocityMonitor[client]) { PrintVelocity(client, "PreThink"); } }*/ /*public PreThinkPost(client) { //if (VelocityMonitor[client]) { PrintVelocity(client, "PreThinkPost"); } }*/ public PostThink(client) { //if (VelocityMonitor[client]) /*{ PrintVelocity(client, "PostThink"); }*/ SetMaxSpeed(client, 1000.0); } /*public PostThinkPost(client) { //if (VelocityMonitor[client]) { PrintVelocity(client, "PostThinkPost"); VelocityMonitor[client] = false; } }*/ stock PrintVelocity(client, const String:prefix[]) { new Float:velocity[3]; GetVelocity(client, velocity); PrintToChatAll("%s | client: %d | %0.2f | %0.2f | %0.2f", prefix, client, velocity[0], velocity[1], velocity[2]); } /** 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. PrintToChat(attacker, "Applying knock back: %0.2f", knockback); VelocityMonitor[client] = true; 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); // Changes by zephyrus: //new flags = GetEntityFlags(client); //if(flags & FL_ONGROUND) // vector[2]=0.5; // Apply the magnitude by scaling the vector (multiplying each of its components). ScaleVector(vector, magnitude); // Changes by zephyrus: //if(flags & FL_ONGROUND) // if(vector[2]>350.0) // vector[2]=350.0; new flags = GetEntityFlags(client); if (flags & FL_ONGROUND) { if (vector[2] < 251.0) { vector[2] = 251.0; } } // ADD the given vector to the client's current velocity. PrintToChatAll("Applying velocity on client %d: %0.2f | %0.2f | %0.2f", client, vector[0], vector[1], vector[2]); 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; } stock GetVelocity(client, Float:velocity[3]) { velocity[0] = GetEntPropFloat(client, Prop_Send, "m_vecVelocity[0]"); velocity[1] = GetEntPropFloat(client, Prop_Send, "m_vecVelocity[1]"); velocity[2] = GetEntPropFloat(client, Prop_Send, "m_vecVelocity[2]"); } stock SetVelocity(client, const Float:velocity[3]) { SetEntPropFloat(client, Prop_Send, "m_vecVelocity[0]", velocity[0]); SetEntPropFloat(client, Prop_Send, "m_vecVelocity[1]", velocity[1]); SetEntPropFloat(client, Prop_Send, "m_vecVelocity[2]", velocity[2]); } stock GetBaseVelocity(client, Float:velocity[3]) { GetEntPropVector(client, Prop_Send, "m_vecBaseVelocity", velocity); } stock SetBaseVelocity(client, const Float:velocity[3]) { SetEntPropVector(client, Prop_Send, "m_vecBaseVelocity", velocity); } stock GetParent(client) { return GetEntProp(client, Prop_Send, "moveparent"); } stock Float:GetFriction(client) { return GetEntPropFloat(client, Prop_Send, "m_flFriction"); } stock Float:GetMaxSpeed(client) { return GetEntPropFloat(client, Prop_Send, "m_flMaxspeed"); } stock SetMaxSpeed(client, Float:maxSpeed = 250.0) { SetEntPropFloat(client, Prop_Send, "m_flMaxspeed", maxSpeed); }