From 75518ba11a2cc210fddad5d43ad638ee4e9fa86e Mon Sep 17 00:00:00 2001 From: Richard Helgeby Date: Thu, 20 Sep 2012 11:32:00 +0200 Subject: [PATCH] Added knock back boost workaround for CS: GO, with cvar to disable it: zr_classes_csgo_knockback_boost. Side effects: Weaker and flying zombies, can be compensated with lower knock back. --- .../zombiereloaded/zombiereloaded.cfg | 4 + src/testsuite/zr/knockback.sp | 205 +++++++++++++++++- src/zr/cvars.inc | 2 + src/zr/knockback.inc | 28 ++- src/zr/tools_functions.inc | 15 ++ src/zr/zombiereloaded.inc | 10 +- 6 files changed, 249 insertions(+), 15 deletions(-) diff --git a/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg b/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg index d463c9a..1ec9af0 100644 --- a/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg +++ b/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg @@ -216,6 +216,10 @@ zr_classes_admin_select "1" // Default: "lmv" zr_classes_speed_method "lmv" +// CS: GO only: Applies an upwards boost if necessary as a workaround for low knock back when standing on the ground. Side effects: Weaker and flying zombies (compensate with lower knock back). +// Default: "1" +zr_classes_csgo_knockback_boost "1" + // Overlay // Allow players to toggle class overlay. diff --git a/src/testsuite/zr/knockback.sp b/src/testsuite/zr/knockback.sp index 522d820..f25ee8c 100644 --- a/src/testsuite/zr/knockback.sp +++ b/src/testsuite/zr/knockback.sp @@ -41,15 +41,16 @@ public Plugin:myinfo = 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)) + 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]"); @@ -57,25 +58,103 @@ public OnPluginStart() { 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_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_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) +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]) +/*public Action:OnTakeDamage(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3]) { KnockbackOnClientHurt(victim, attacker, Float:damage); @@ -89,6 +168,48 @@ public OnTakeDamagePost(victim, attacker, inflictor, Float:damage, damagetype, w { 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. @@ -102,7 +223,7 @@ public OnTakeDamagePost(victim, attacker, inflictor, Float:damage, damagetype, w KnockbackOnClientHurt(client, attacker, Float:dmg_health) { // If attacker is invalid, then stop. - if (!(attacker > 0 || attacker < MaxClients)) + if (!(attacker > 0 && attacker < MaxClients)) { return; } @@ -130,6 +251,8 @@ KnockbackOnClientHurt(client, attacker, Float:dmg_health) knockback *= dmg_health; // Apply knockback. + PrintToChat(attacker, "Applying knock back: %0.2f", knockback); + VelocityMonitor[client] = true; KnockbackSetVelocity(client, attackerloc, clientloc, knockback); } @@ -150,10 +273,30 @@ KnockbackSetVelocity(client, const Float:startpoint[3], const Float:endpoint[3], // 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); } @@ -216,4 +359,48 @@ public bool:KnockbackTRFilter(entity, contentsMask) // Allow hit. return true; -} \ No newline at end of file +} + +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); +} diff --git a/src/zr/cvars.inc b/src/zr/cvars.inc index 62ecd9a..2005892 100644 --- a/src/zr/cvars.inc +++ b/src/zr/cvars.inc @@ -71,6 +71,7 @@ enum CvarsList Handle:CVAR_CLASSES_HUMAN_SELECT, Handle:CVAR_CLASSES_ADMIN_SELECT, Handle:CVAR_CLASSES_SPEED_METHOD, + Handle:CVAR_CLASSES_CSGO_KNOCKBACK_BOOST, Handle:CVAR_WEAPONS, Handle:CVAR_WEAPONS_RESTRICT, Handle:CVAR_WEAPONS_RESTRICT_ENDEQUIP, @@ -278,6 +279,7 @@ CvarsCreate() g_hCvarsList[CVAR_CLASSES_HUMAN_SELECT] = CreateConVar("zr_classes_human_select", "1", "Allow players to select human classes."); g_hCvarsList[CVAR_CLASSES_ADMIN_SELECT] = CreateConVar("zr_classes_admin_select", "1", "Allow admins to select admin mode classes. (Not to be confused by admin-only classes!)"); g_hCvarsList[CVAR_CLASSES_SPEED_METHOD] = CreateConVar("zr_classes_speed_method", "prop", "Speed method to use when applying player speed. Do not touch this if you don't know what you're doing! [\"lmv\" = Lagged movement value | \"prop\" = Player speed property"); + g_hCvarsList[CVAR_CLASSES_CSGO_KNOCKBACK_BOOST] = CreateConVar("zr_classes_csgo_knockback_boost", "1", "CS: GO only: Applies an upwards boost if necessary as a workaround for low knock back when standing on the ground. Side effects: Weaker and flying zombies (compensate with lower knock back)."); // Menu g_hCvarsList[CVAR_CLASSES_MENU_AUTOCLOSE] = CreateConVar("zr_classes_menu_autoclose", "1", "Automatically close class selection menu after selecting a class."); diff --git a/src/zr/knockback.inc b/src/zr/knockback.inc index cca1652..94de67d 100644 --- a/src/zr/knockback.inc +++ b/src/zr/knockback.inc @@ -24,7 +24,13 @@ * * ============================================================================ */ - + +/** + * Minimum upwards boost that is required to push zombies off the ground. + */ +#define CSGO_KNOCKBACK_BOOST 251.0 +#define CSGO_KNOCKBACK_BOOST_MAX 350.0 + /** Client has been hurt. * * @param client The client index. (zombie) @@ -134,6 +140,26 @@ KnockbackSetVelocity(client, const Float:startpoint[3], const Float:endpoint[3], // Apply the magnitude by scaling the vector (multiplying each of its components). ScaleVector(vector, magnitude); + // CS: GO workaround. Apply knock back boost if enabled. + if (g_Game == Game_CSGO && GetConVarBool(g_hCvarsList[CVAR_CLASSES_CSGO_KNOCKBACK_BOOST])) + { + new flags = GetEntityFlags(client); + new Float:velocity[3]; + ToolsGetClientVelocity(client, velocity); + + // Remove boost if current velocity is too high. + if (velocity[2] > CSGO_KNOCKBACK_BOOST_MAX) + { + // Don't add extra boost. + vector[2] = 0.0; + } + else if (flags & FL_ONGROUND && vector[2] < CSGO_KNOCKBACK_BOOST) + { + // Apply minimum boost required to push player off the ground. + vector[2] = CSGO_KNOCKBACK_BOOST; + } + } + // ADD the given vector to the client's current velocity. ToolsClientVelocity(client, vector); } diff --git a/src/zr/tools_functions.inc b/src/zr/tools_functions.inc index a15e194..df8cd76 100644 --- a/src/zr/tools_functions.inc +++ b/src/zr/tools_functions.inc @@ -67,6 +67,21 @@ stock ToolsClientVelocity(client, Float:vecVelocity[3], bool:apply = true, bool: TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, vecVelocity); } +/** + * Gets client's velocity. + * + * @param client The client index. + * @param vecVelocity Array to store vector in. + */ +stock ToolsGetClientVelocity(client, Float:vecVelocity[3]) +{ + // x = vector component. + for (new x = 0; x < 3; x++) + { + vecVelocity[x] = GetEntDataFloat(client, g_iToolsVelocity + (x*4)); + } +} + /** * Set a client's lagged movement value. * @param client The client index. diff --git a/src/zr/zombiereloaded.inc b/src/zr/zombiereloaded.inc index c84fd53..59f096e 100644 --- a/src/zr/zombiereloaded.inc +++ b/src/zr/zombiereloaded.inc @@ -67,8 +67,8 @@ enum Game /** * Current game. */ -new Game:g_game = Game_Unknown; -#pragma unused g_game +new Game:g_Game = Game_Unknown; +#pragma unused g_Game /** * Updates g_game. Will log a warning if a unsupported game is detected. @@ -80,19 +80,19 @@ UpdateGameFolder() if (StrEqual(gameFolder, "cstrike", false)) { - g_game = Game_CSS; + g_Game = Game_CSS; PrintToServer("Game detected: cstrike"); return; } else if (StrEqual(gameFolder, "csgo", false)) { - g_game = Game_CSGO; + g_Game = Game_CSGO; PrintToServer("Game detected: csgo"); return; } LogError("Warning: Zombie:Reloaded doesn't support this game: %s", gameFolder); - g_game = Game_Unknown; + g_Game = Game_Unknown; } /**