diff --git a/AntiLagSwitch/scripting/AntiLagSwitch.sp b/AntiLagSwitch/scripting/AntiLagSwitch.sp index 169ea9ea..719545a2 100644 --- a/AntiLagSwitch/scripting/AntiLagSwitch.sp +++ b/AntiLagSwitch/scripting/AntiLagSwitch.sp @@ -17,6 +17,8 @@ public Plugin myinfo = Handle g_hProcessUsercmds; Handle g_hRunNullCommand; +int g_LastProcessed[MAXPLAYERS + 1]; + public void OnPluginStart() { Handle hGameConf = LoadGameConfigFile("AntiLagSwitch.games"); @@ -59,11 +61,29 @@ public void OnPluginStart() public void OnClientPutInServer(int client) { DHookEntity(g_hProcessUsercmds, true, client); + g_LastProcessed[client] = GetGameTickCount(); +} + +public void OnClientDisconnect(int client) +{ + g_LastProcessed[client] = 0; +} + +public void OnGameFrame() +{ + int minimum = GetGameTickCount() - 33; + for(int client = 1; client <= MaxClients; client++) + { + if(IsClientInGame(client) && (IsFakeClient(client) || g_LastProcessed[client] < minimum)) + { + RunNullCommand(client); + } + } } public MRESReturn Hook_ProcessUsercmds(int client, Handle hParams) { - + g_LastProcessed[client] = GetGameTickCount(); } int RunNullCommand(int client) diff --git a/DamageProxy/configs/damageproxy/ze_tesv_skyrim_v4fix.cfg b/DamageProxy/configs/damageproxy/ze_tesv_skyrim_v4fix.cfg new file mode 100644 index 00000000..53fd59b2 --- /dev/null +++ b/DamageProxy/configs/damageproxy/ze_tesv_skyrim_v4fix.cfg @@ -0,0 +1,33 @@ +"items" +{ + "1551382" // Werewolf + { + "KnockbackMaxVel" "500" + "KnockbackScale" "0.40" + "NoSlowDown" "0" + "KillPush" "1" + + "ww_push" "1" + "ww_push2" "1" + "ww_push3" "1" + "ww_push4" "1" + } + + "1551093" // Troll + { + "KnockbackMaxVel" "250" + "KnockbackScale" "0.33" + } + + "1551122" // Giant + { + "KnockbackMaxVel" "200" + "KnockbackScale" "0.33" + } + + "1551162" // Dragonpriest + { + "KnockbackMaxVel" "100" + "KnockbackScale" "0.20" + } +} diff --git a/_ZItemKnockback/gamedata/ZItemKnockback.games.txt b/DamageProxy/gamedata/DamageProxy.games.txt similarity index 100% rename from _ZItemKnockback/gamedata/ZItemKnockback.games.txt rename to DamageProxy/gamedata/DamageProxy.games.txt diff --git a/DamageProxy/scripting/DamageProxy.sp b/DamageProxy/scripting/DamageProxy.sp new file mode 100644 index 00000000..1c5d574f --- /dev/null +++ b/DamageProxy/scripting/DamageProxy.sp @@ -0,0 +1,279 @@ +#pragma semicolon 1 +#pragma newdecls required + +#include +#include +#include +#include +#include +#include + +public Plugin myinfo = +{ + name = "DamageProxy", + author = "BotoX", + description = "", + version = "0.0", + url = "" +}; + +bool g_bLateLoad = false; + +Handle g_hFireBulletDetour; +int g_hVelocityModifier; + +int g_LastAttacker = 0; +int g_LastVictim = 0; + +char g_iPhysboxToClient[2048]; + +int g_iSpecialKnife[MAXPLAYERS + 1]; +bool g_bNoSlowdown[MAXPLAYERS + 1]; + +KeyValues g_Config; + +public void OnPluginStart() +{ + Handle hGameData = LoadGameConfigFile("DamageProxy.games"); + if(!hGameData) + SetFailState("Failed to load DamageProxy gamedata."); + + g_hFireBulletDetour = DHookCreateFromConf(hGameData, "CCSPlayer__FireBullet"); + if(!g_hFireBulletDetour) + SetFailState("Failed to setup detour for CCSPlayer__FireBullet"); + delete hGameData; + + if(!DHookEnableDetour(g_hFireBulletDetour, false, Detour_OnFireBullet)) + SetFailState("Failed to detour CCSPlayer__FireBullet."); + + g_hVelocityModifier = FindSendPropInfo("CCSPlayer", "m_flVelocityModifier"); + if(g_hVelocityModifier == -1) + SetFailState("Couldn't find CCSPlayer::m_flVelocityModifier"); +} + +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) +{ + g_bLateLoad = late; + return APLRes_Success; +} + +public void OnMapStart() +{ + bool bLate = g_bLateLoad; + g_bLateLoad = false; + + if(g_Config) + delete g_Config; + + char sMapName[PLATFORM_MAX_PATH]; + GetCurrentMap(sMapName, sizeof(sMapName)); + + char sConfigFile[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), "configs/damageproxy/%s.cfg", sMapName); + if(!FileExists(sConfigFile)) + { + LogMessage("Could not find mapconfig: \"%s\"", sConfigFile); + return; + } + LogMessage("Found mapconfig: \"%s\"", sConfigFile); + + g_Config = new KeyValues("items"); + if(!g_Config.ImportFromFile(sConfigFile)) + { + delete g_Config; + LogError("ImportFromFile() failed!"); + return; + } + g_Config.Rewind(); + + if(!bLate) + return; + + /* Late Load */ + PrintToChatAll("late!"); + for(int client = 1; client <= MaxClients; client++) + { + if(!IsClientInGame(client)) + continue; + + OnClientPutInServer(client); + + int iKnife = GetPlayerWeaponSlot(client, CS_SLOT_KNIFE); + if(iKnife > 0) + OnWeaponEquipped(client, iKnife); + } +} + +public void OnClientPutInServer(int client) +{ + g_iSpecialKnife[client] = 0; + g_bNoSlowdown[client] = false; + + if(g_Config) + { + SDKHook(client, SDKHook_WeaponEquipPost, OnWeaponEquipped); + SDKHook(client, SDKHook_WeaponDropPost, OnWeaponDropped); + } +} + +public void OnWeaponEquipped(int client, int entity) +{ + if(!g_Config) + return; + + if(!IsValidEntity(entity)) + return; + + char sClassname[64]; + GetEntityClassname(entity, sClassname, sizeof(sClassname)); + if(strcmp(sClassname, "weapon_knife", false) != 0) + return; + + int iHammerID = GetEntProp(entity, Prop_Data, "m_iHammerID"); + if(!iHammerID) + return; + + char sHammerID[16]; + IntToString(iHammerID, sHammerID, sizeof(sHammerID)); + + g_Config.Rewind(); + if(!g_Config.JumpToKey(sHammerID)) + return; + + float fKnockbackMaxVel = g_Config.GetFloat("KnockbackMaxVel", -1.0); + if(fKnockbackMaxVel > 0.0) + ZR_SetClientKnockbackMaxVelocity(client, fKnockbackMaxVel); + + float fKnockbackScale = g_Config.GetFloat("KnockbackScale", -1.0); + if(fKnockbackScale > 0.0) + ZR_SetClientKnockbackScale(client, fKnockbackScale); + + g_bNoSlowdown[client] = view_as(g_Config.GetNum("NoSlowDown", 0)); + + g_iSpecialKnife[client] = entity; + + CheckChildren(client, entity); +} + +public void OnWeaponDropped(int client, int entity) +{ + if(entity == g_iSpecialKnife[client]) + { + ZR_SetClientKnockbackMaxVelocity(client, 0.0); + ZR_SetClientKnockbackScale(client, 1.0); + g_iSpecialKnife[client] = 0; + g_bNoSlowdown[client] = false; + } +} + +public void OnEntityDestroyed(int entity) +{ + if(entity >= 0 && entity < sizeof(g_iPhysboxToClient)) + g_iPhysboxToClient[entity] = 0; +} + +void CheckChildren(int client, int parent) +{ + bool bKillPush = view_as(g_Config.GetNum("KillPush", 1)); + + int entity = INVALID_ENT_REFERENCE; + while((entity = FindEntityByClassname(entity, "*")) != INVALID_ENT_REFERENCE) + { + if(GetEntPropEnt(entity, Prop_Data, "m_pParent") != parent) + continue; + + char sClassname[64]; + GetEntityClassname(entity, sClassname, sizeof(sClassname)); + + char sTargetname[64]; + GetEntPropString(entity, Prop_Data, "m_iName", sTargetname, sizeof(sTargetname)); + + int iTemplateLoc = FindCharInString(sTargetname, '&', true); + if(iTemplateLoc != -1) + sTargetname[iTemplateLoc] = 0; + + // -1 = Never kill + // 0 = Default + // 1 = Always kill + int iKill = 0; + if(sTargetname[0]) + iKill = g_Config.GetNum(sTargetname, 0); + + PrintToConsoleAll("%d child: \"%s\" %d (%s) kill:%d", client, sClassname, entity, sTargetname, iKill); + + if(!strncmp(sClassname, "func_physbox", 12, false) || !strcmp(sClassname, "func_breakable", false)) + { + g_iPhysboxToClient[entity] = client; + SDKHook(entity, SDKHook_OnTakeDamage, OnTakeDamage); + + PrintToConsoleAll("Hooking \"%s\" %d (%s) OnTakeDamage", sClassname, entity, sTargetname); + } + else if((bKillPush && !strcmp(sClassname, "trigger_push", false)) || iKill > 0) + { + if((bKillPush || iKill > 0) && iKill >= 0) + { + AcceptEntityInput(entity, "Kill"); + PrintToConsoleAll("Killing \"%s\" %d (%s)", sClassname, entity, sTargetname); + } + } + else + { + CheckChildren(client, entity); + } + } +} + +public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2]) +{ + // because knifes don't call FireBullet we reset it here too + g_LastAttacker = 0; + g_LastVictim = 0; +} + +public MRESReturn Detour_OnFireBullet(int pThis, Handle hReturn, Handle hParams) +{ + // need to reset it per fired bullet else only one of the shotgun pellets would be able to hit the same player + g_LastAttacker = 0; + g_LastVictim = 0; + return MRES_Handled; +} + +public Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float damageForce[3], float damagePosition[3], int damagecustom) +{ + if(attacker <= 0 || attacker > MAXPLAYERS) + return Plugin_Continue; + + int client = g_iPhysboxToClient[victim]; + if(client <= 0) + { + PrintToConsoleAll("!!! %d client = %d no physbox !!!", victim, client); + return Plugin_Continue; + } + + int knife = g_iSpecialKnife[client]; + if(knife <= 0) + { + PrintToConsoleAll("!!! %d client = %d no knife !!!", victim, client); + return Plugin_Continue; + } + + // fix multiple penetration + if(g_LastAttacker == attacker && g_LastVictim == client) + return Plugin_Handled; + + victim = client; + + g_LastAttacker = attacker; + g_LastVictim = victim; + + float flVelocityModifier = 1.0; + if(g_bNoSlowdown[client]) + flVelocityModifier = GetEntDataFloat(client, g_hVelocityModifier); + + SDKHooks_TakeDamage(victim, inflictor, attacker, damage, damagetype, weapon, damageForce, damagePosition, 1); + + if(g_bNoSlowdown[client] && flVelocityModifier >= 0.99) + SetEntDataFloat(client, g_hVelocityModifier, 1.0, true); + + return Plugin_Handled; +} diff --git a/_ZItemKnockback/scripting/ZItemKnockback.sp b/_ZItemKnockback/scripting/ZItemKnockback.sp deleted file mode 100644 index cfa12d99..00000000 --- a/_ZItemKnockback/scripting/ZItemKnockback.sp +++ /dev/null @@ -1,205 +0,0 @@ -#pragma semicolon 1 -#pragma newdecls required - -#include -#include -#include -#include -#include - -#pragma semicolon 1 -#pragma newdecls required - -public Plugin myinfo = -{ - name = "ZItemKnockback", - author = "BotoX", - description = "", - version = "0.0", - url = "" -}; - -Handle hFireBulletDetour; -bool g_bLateLoad = false; - -int g_LastAttacker = 0; -int g_LastVictim = 0; - -// maps from edict index to object index -char g_EntityIdxToItemIdx[2048]; - -enum struct SItem -{ - bool m_Test; -} -SItem g_Items[255]; - -public void OnPluginStart() -{ - Handle hGameData = LoadGameConfigFile("ZItemKnockback.games"); - if(!hGameData) - SetFailState("Failed to load ZItemKnockback gamedata."); - - hFireBulletDetour = DHookCreateFromConf(hGameData, "CCSPlayer__FireBullet"); - if(!hFireBulletDetour) - SetFailState("Failed to setup detour for CCSPlayer__FireBullet"); - delete hGameData; - - if(!DHookEnableDetour(hFireBulletDetour, false, Detour_OnFireBullet)) - SetFailState("Failed to detour CCSPlayer__FireBullet."); -} - -public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) -{ - g_bLateLoad = late; - return APLRes_Success; -} - -public void OnMapStart() -{ - bool bLate = g_bLateLoad; - g_bLateLoad = false; - - char sMapName[PLATFORM_MAX_PATH]; - GetCurrentMap(sMapName, sizeof(sMapName)); - - char sConfigFile[PLATFORM_MAX_PATH]; - BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), "configs/ZItemKnockback/%s.cfg", sMapName); - if(!FileExists(sConfigFile)) - { - LogMessage("Could not find mapconfig: \"%s\"", sConfigFile); - return; - } - LogMessage("Found mapconfig: \"%s\"", sConfigFile); - - KeyValues KvConfig = new KeyValues("items"); - if(!KvConfig.ImportFromFile(sConfigFile)) - { - delete KvConfig; - LogError("ImportFromFile() failed!"); - return; - } - KvConfig.Rewind(); - - if(!KvConfig.GotoFirstSubKey()) - { - delete KvConfig; - LogError("GotoFirstSubKey() failed!"); - return; - } - - do - { - char sSection[64]; - KvConfig.GetSectionName(sSection, sizeof(sSection)); - - } while(KvConfig.GotoNextKey(false)); - - delete KvConfig; - - /* Late Load */ - for(int client = 1; client <= MaxClients; client++) - { - if(IsClientInGame(client)) - OnClientPutInServer(client); - } -} - - -public void OnClientPutInServer(int client) -{ - SDKHook(client, SDKHook_WeaponEquipPost, OnWeaponEquip); -} - -public Action OnWeaponEquip(int client, int entity) -{ - if(!IsValidEntity(entity)) - return; - - char sClassname[64]; - GetEntityClassname(entity, sClassname, sizeof(sClassname)); - if(strcmp(sClassname, "weapon_knife", false) != 0) - return; - - int HammerID = GetEntProp(entity, Prop_Data, "m_iHammerID"); - if(!HammerID) - return; - - CheckChildren(client, entity); -} - -void CheckChildren(int client, int parent) -{ - int entity = INVALID_ENT_REFERENCE; - while((entity = FindEntityByClassname(entity, "*")) != INVALID_ENT_REFERENCE) - { - if(GetEntPropEnt(entity, Prop_Data, "m_pParent") != parent) - continue; - - char sClassname[64]; - GetEntityClassname(entity, sClassname, sizeof(sClassname)); - - char sTargetname[64]; - GetEntPropString(entity, Prop_Data, "m_iName", sTargetname, sizeof(sTargetname)); - - PrintToChatAll("%d child: \"%s\" %d (%s)", client, sClassname, entity, sTargetname); - - if(!strncmp(sClassname, "func_physbox", 12, false) || !strcmp(sClassname, "func_breakable", false)) - { - SDKHook(entity, SDKHook_OnTakeDamage, OnTakeDamage); - PrintToChatAll("Hooking \"%s\" %d (%s) OnTakeDamage", sClassname, entity, sTargetname); - } - else if(!strcmp(sClassname, "trigger_push", false)) - { - AcceptEntityInput(entity, "Kill"); - PrintToChatAll("Killing \"%s\" %d (%s)", sClassname, entity, sTargetname); - } - else - { - CheckChildren(client, entity); - } - } -} - -public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2]) -{ - // because knifes don't call FireBullet we reset it here too - g_LastAttacker = 0; - g_LastVictim = 0; -} - -public MRESReturn Detour_OnFireBullet(int pThis, Handle hReturn, Handle hParams) -{ - // need to reset it per fired bullet else only one of the shotgun pellets would be able to hit the same player - g_LastAttacker = 0; - g_LastVictim = 0; - return MRES_Handled; -} - -public Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float damageForce[3], float damagePosition[3]) -{ - if(attacker <= 0 || attacker > MAXPLAYERS) - return Plugin_Continue; - - int client = victim; - while((client = GetEntPropEnt(client, Prop_Data, "m_pParent")) != INVALID_ENT_REFERENCE) - { - if(client >= 1 && client <= MAXPLAYERS) - break; - } - - if(client <= 0) - return Plugin_Handled; - - // fix multiple penetration - if(g_LastAttacker == attacker && g_LastVictim == client) - return Plugin_Handled; - - victim = client; - - g_LastAttacker = attacker; - g_LastVictim = victim; - - SDKHooks_TakeDamage(victim, inflictor, attacker, damage, damagetype, weapon, damageForce, damagePosition); - return Plugin_Handled; -} diff --git a/includes/zombiereloaded.inc b/includes/zombiereloaded.inc index 797e831a..861a2800 100644 --- a/includes/zombiereloaded.inc +++ b/includes/zombiereloaded.inc @@ -35,6 +35,7 @@ #include #include #include +#include public SharedPlugin __pl_zombiereloaded = { @@ -64,5 +65,8 @@ public void __pl_zombiereloaded_SetNTVOptional() MarkNativeAsOptional("ZR_RespawnClient"); MarkNativeAsOptional("ZR_SetKilledByWorld"); MarkNativeAsOptional("ZR_GetKilledByWorld"); + + MarkNativeAsOptional("ZR_SetClientKnockbackMaxVelocity"); + MarkNativeAsOptional("ZR_SetClientKnockbackScale"); } #endif diff --git a/includes/zr/class.zr.inc b/includes/zr/class.zr.inc index b77089d6..ac869966 100644 --- a/includes/zr/class.zr.inc +++ b/includes/zr/class.zr.inc @@ -38,12 +38,14 @@ /** * Results when selecting a class for a player. */ +#if !defined INCLUDED_BY_ZOMBIERELOADED enum ClassSelectResult { ClassSelected_NoChange, /** No class change was necessary (class already selected). */ ClassSelected_Instant, /** Class was instantly changed. */ ClassSelected_NextSpawn /** Class will be used next spawn. */ } +#endif /** * Returns whether a class index is valid or not. diff --git a/includes/zr/infect.zr.inc b/includes/zr/infect.zr.inc index 6b16c53f..d433d2dd 100644 --- a/includes/zr/infect.zr.inc +++ b/includes/zr/infect.zr.inc @@ -30,7 +30,7 @@ * * @param client The client index. * - * @return True if zombie, false if not. + * @return True if zombie, false if not. * @error Invalid client index, not connected or not alive. */ native bool ZR_IsClientZombie(int client); @@ -40,7 +40,7 @@ native bool ZR_IsClientZombie(int client); * * @param client The client index. * - * @return True if human, false if not. + * @return True if human, false if not. * @error Invalid client index, not connected or not alive. */ native bool ZR_IsClientHuman(int client); @@ -56,9 +56,10 @@ native bool ZR_IsClientHuman(int client); * @param respawnOverride (Optional) Set to true to override respawn cvar. * @param respawn (Optional) Value to override with. * + * @return True if the client was infected, false if not. * @error Invalid client index, not connected or not alive. */ -native int ZR_InfectClient(int client, int attacker = -1, bool motherInfect = false, bool respawnOverride = false, bool respawn = false); +native bool ZR_InfectClient(int client, int attacker = -1, bool motherInfect = false, bool respawnOverride = false, bool respawn = false); /** * Turns a zombie back into a human. @@ -70,9 +71,10 @@ native int ZR_InfectClient(int client, int attacker = -1, bool motherInfect = fa * @param respawn Teleport client back to spawn. * @param protect Start spawn protection on client. * + * @return True if the client was uninfected, false if not. * @error Invalid client index, not connected or not alive. */ -native int ZR_HumanClient(int client, bool respawn = false, bool protect = false); +native bool ZR_HumanClient(int client, bool respawn = false, bool protect = false); /** * Called on infection timer to determine if timer should show. diff --git a/includes/zr/knockback.zr.inc b/includes/zr/knockback.zr.inc new file mode 100644 index 00000000..929ff7f5 --- /dev/null +++ b/includes/zr/knockback.zr.inc @@ -0,0 +1,42 @@ +/* + * ============================================================================ + * + * Zombie:Reloaded + * + * File: knockback.zr.inc + * Type: Include + * Description: Knockback-related natives/forwards. + * + * 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 . + * + * ============================================================================ + */ + +/** + * Set a maximum knockback velocity. + * + * @param client The client. + * @param fVelocity Maximum knockback velocity / force. + */ +native void ZR_SetClientKnockbackMaxVelocity(int client, float fVelocity); + +/** + * Set a custom knockback scale. + * + * @param client The client. + * @param fScale Custom knockback scale. + */ +native void ZR_SetClientKnockbackScale(int client, float fScale); diff --git a/includes/zr/napalm.zr.inc b/includes/zr/napalm.zr.inc index 7e864597..82bbc666 100644 --- a/includes/zr/napalm.zr.inc +++ b/includes/zr/napalm.zr.inc @@ -42,4 +42,4 @@ forward Action ZR_OnClientIgnite(int &client, float &duration); * @param client The client to ignite. * @param duration The burn duration. */ -forward void ZR_OnClientIgnited(int client, float duration); +forward void ZR_OnClientIgnited(int client, float duration); \ No newline at end of file