diff --git a/addons/sourcemod/plugins/fixes/l4d2_tank_flying_incap.smx b/addons/sourcemod/plugins/fixes/l4d2_tank_flying_incap.smx index 918d56de2..ac0e5838f 100644 Binary files a/addons/sourcemod/plugins/fixes/l4d2_tank_flying_incap.smx and b/addons/sourcemod/plugins/fixes/l4d2_tank_flying_incap.smx differ diff --git a/addons/sourcemod/scripting/l4d2_tank_flying_incap.sp b/addons/sourcemod/scripting/l4d2_tank_flying_incap.sp index db3697afd..16f2c3528 100644 --- a/addons/sourcemod/scripting/l4d2_tank_flying_incap.sp +++ b/addons/sourcemod/scripting/l4d2_tank_flying_incap.sp @@ -2,141 +2,143 @@ #pragma newdecls required #include -#include -#define L4D2UTIL_STOCKS_ONLY 1 -#include - -int iSurvivorIncapHealth = 300; +#include bool - bLateLoad, - bDebug = false; + bDebug = false, + bAnim = false; ConVar convarDebug, - convarSurvivorIncapHealth = null; + convarAnim = null; + +float + g_flIncapTime[MAXPLAYERS+1]; public Plugin myinfo = { name = "[L4D2] Flying Incap - Tank Punch", - author = "Sir", + author = "Sir, Forgetest", description = "Sends Survivors flying on the incapping punch.", - version = "1.0", + version = "2.0", url = "https://github.com/SirPlease/L4D2-Competitive-Rework" }; -public APLRes AskPluginLoad2(Handle plugin, bool late, char[] error, int errMax) +public void OnPluginStart() { - bLateLoad = late; - return APLRes_Success; + convarDebug = CreateConVar("l4d2_tank_flying_incap_debug", "0", "Are we debugging?"); + convarAnim = CreateConVar("l4d2_tank_flying_incap_anim_fix", "0", "Remove the getting-up animation at the end of fly. (NOTE: Survivors will be able to shoot as soon as they land.)"); + bDebug = convarDebug.BoolValue; + bAnim = convarAnim.BoolValue; + convarDebug.AddChangeHook(CvarsChanged); + convarAnim.AddChangeHook(CvarsChanged); + + HookEvent("player_incapacitated", Event_player_incapacitated); } -public void OnPluginStart() +// also serves as late-loader +public void OnMapStart() { - if (bLateLoad) + for (int i = 1; i <= MaxClients; ++i) { - for (int i = 1; i < MaxClients+1; i++) - { - if (IsClientInGame(i)) - { - OnClientPutInServer(i); - } - } + g_flIncapTime[i] = 0.0; } - - convarDebug = CreateConVar("l4d2_tank_flying_incap_debug", "0", "Are we debugging?"); - convarSurvivorIncapHealth = FindConVar("survivor_incap_health"); - bDebug = convarDebug.BoolValue; - iSurvivorIncapHealth = convarSurvivorIncapHealth.IntValue; - convarDebug.AddChangeHook(CvarsChanged); - convarSurvivorIncapHealth.AddChangeHook(CvarsChanged); } -public void OnClientPutInServer(int client) +void Event_player_incapacitated(Event event, const char[] name, bool dontBroadcast) { - SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage); + int userid = event.GetInt("userid"); + + // Doesn't matter it's valid or not, has a minimum of 0. + g_flIncapTime[GetClientOfUserId(userid)] = GetGameTime(); + + // punch fly animation is applied this frame, + RequestFrame(NextFrame_HookAnimation, userid); } -public void OnClientDisconnect(int client) +void NextFrame_HookAnimation(int userid) { - SDKUnhook(client, SDKHook_OnTakeDamage, OnTakeDamage); + if (!bAnim) + return; + + int client = GetClientOfUserId(userid); + if (!client || !IsClientInGame(client)) + return; + + if (GetClientTeam(client) != 2 || !IsPlayerAlive(client)) + return; + + if (!GetEntProp(client, Prop_Send, "m_isIncapacitated")) + return; + + AnimHookEnable(client, AnimHook_PunchFly); } -public Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype) +Action AnimHook_PunchFly(int client, int &activity) { - if (damagetype != DMG_CLUB) - return Plugin_Continue; + static int last = 0; - if (!IsValidSurvivor(victim) || !IsValidTank(attacker)) - return Plugin_Continue; + if (bDebug && last != activity) + { + if (activity < 0) activity = 0; - if (inflictor <= MaxClients || !IsValidEdict(inflictor)) - return Plugin_Continue; + char curActName[64], lastActName[64]; + AnimGetActivity(activity, curActName, sizeof(curActName)); + AnimGetActivity(last, lastActName, sizeof(lastActName)); + PrintToChatAll("\x01[FlyingIncap]: (%.1f) (%N) [\x05%s\x01] [\x04%s\x01]", GetGameTime(), client, curActName, lastActName); - char sClassName[ENTITY_MAX_NAME_LENGTH]; - GetEdictClassname(inflictor, sClassName, sizeof(sClassName)); - - if (strcmp("weapon_tank_claw", sClassName) == 0) + last = activity; + } + + switch (activity) { - if (!IsIncapacitated(victim)) + case L4D2_ACT_TERROR_HIT_BY_TANKPUNCH, + L4D2_ACT_TERROR_IDLE_FALL_FROM_TANKPUNCH, + L4D2_ACT_TERROR_JUMP_LANDING, + L4D2_ACT_TERROR_JUMP_LANDING_HARD, + L4D2_ACT_DEPLOY_PISTOL: + { + return Plugin_Continue; + } + + // Skip the getting up from ground animation + case L4D2_ACT_TERROR_TANKPUNCH_LAND: { - int iTotalHealth = GetSurvivorPermanentHealth(victim) + GetSurvivorTemporaryHealth(victim); - - if (iTotalHealth <= damage) - { - if (bDebug) - PrintToChatAll("[FlyingIncap]: %N got hit by Tank and has %i HP on incapping punch", victim, iTotalHealth); - - DataPack dp; - CreateDataTimer(0.4, Timer_ApplyDamageLater, dp, TIMER_FLAG_NO_MAPCHANGE); - dp.WriteCell(GetClientUserId(victim)); - dp.WriteCell(GetClientUserId(attacker)); - dp.WriteCell(inflictor); - dp.WriteCell(iTotalHealth); - - SetEntityHealth(victim, 1); - SetTempHealth(victim, 0.0); - damage = 0.0; - return Plugin_Changed; - } + PlayerAnimState.FromPlayer(client).m_bIsPunchedByTank = false; // no longer in punched animation + + activity = L4D2_ACT_DIESIMPLE; // incap animation intro } } - return Plugin_Continue; + + AnimHookDisable(client, AnimHook_PunchFly); + return Plugin_Changed; } -Action Timer_ApplyDamageLater(Handle timer, DataPack dp) +int g_iIncap; +public Action L4D_TankClaw_OnPlayerHit_Pre(int tank, int claw, int player) { - dp.Reset(); - int iSurvivor = GetClientOfUserId(dp.ReadCell()); - int iTank = GetClientOfUserId(dp.ReadCell()); - int iInflictor = dp.ReadCell(); - float damage = float(dp.ReadCell()); - damage = damage >= 1.0 ? damage : 1.0; - - if (iSurvivor > 0) - { - iTank = iTank > 0 ? iTank : 0; - - if (bDebug) - PrintToChatAll("[FlyingIncap]: Applied %0.2f damage to %N", damage, iSurvivor); + g_iIncap = GetEntProp(player, Prop_Send, "m_isIncapacitated"); - SDKHooks_TakeDamage(iSurvivor, iInflictor, iTank, damage, DMG_CLUB, WEPID_TANK_CLAW); - - if (IsIncapacitated(iSurvivor)) - SetEntityHealth(iSurvivor, iSurvivorIncapHealth); + if (GetGameTime() == g_flIncapTime[player]) + { + SetEntProp(player, Prop_Send, "m_isIncapacitated", 0); } - return Plugin_Stop; + return Plugin_Continue; } -void CvarsChanged(ConVar convar, const char[] oldValue, const char[] newValue) +public void L4D_TankClaw_OnPlayerHit_Post(int tank, int claw, int player) { - bDebug = convarDebug.BoolValue; - iSurvivorIncapHealth = convarSurvivorIncapHealth.IntValue; + SetEntProp(player, Prop_Send, "m_isIncapacitated", g_iIncap); } -void SetTempHealth(int client, float fHealth) +public void L4D_TankClaw_OnPlayerHit_PostHandled(int tank, int claw, int player) { - SetEntPropFloat(client, Prop_Send, "m_healthBufferTime", GetGameTime()); - SetEntPropFloat(client, Prop_Send, "m_healthBuffer", fHealth); + SetEntProp(player, Prop_Send, "m_isIncapacitated", g_iIncap); +} + +void CvarsChanged(ConVar convar, const char[] oldValue, const char[] newValue) +{ + bDebug = convarDebug.BoolValue; + bAnim = convarAnim.BoolValue; } \ No newline at end of file