#pragma semicolon 1 #pragma newdecls required #include #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_hActiveWeapon; int g_LastAttacker = 0; int g_LastVictim = 0; char g_iPhysboxToClient[2048]; int g_iSpecialKnife[MAXPLAYERS + 1]; bool g_bNoSlowdown[MAXPLAYERS + 1]; bool g_bRestoreHP[MAXPLAYERS + 1]; bool g_bFullKnife[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"); g_hActiveWeapon = FindSendPropInfo("CBaseCombatCharacter", "m_hActiveWeapon"); if(g_hActiveWeapon == -1) SetFailState("Couldn't find CBaseCombatCharacter::m_hActiveWeapon"); PhysboxToClientMap(g_iPhysboxToClient, true); } public void OnPluginEnd() { PhysboxToClientMap(g_iPhysboxToClient, false); } 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 */ 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; g_bRestoreHP[client] = false; g_bFullKnife[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] = "z"; if(ZR_IsClientHuman(client)) sHammerID[0] = 'h'; IntToString(iHammerID, sHammerID[1], sizeof(sHammerID) - 1); g_Config.Rewind(); if(!g_Config.JumpToKey(sHammerID)) return; float fKnockbackScale = g_Config.GetFloat("KnockbackScale", 1.0); ZR_SetClientKnockbackScale(client, fKnockbackScale); float fKnockbackMaxForce = g_Config.GetFloat("KnockbackMaxForce", 0.0); if(fKnockbackMaxForce > 0.0) ZR_SetClientKnockbackMaxForce(client, fKnockbackMaxForce); float fKnockbackMaxVel = g_Config.GetFloat("KnockbackMaxVel", -1.0); if(fKnockbackMaxVel >= 0.0) ZR_SetClientKnockbackMaxVelocity(client, fKnockbackMaxVel); g_bNoSlowdown[client] = view_as(g_Config.GetNum("NoSlowDown", 0)); g_bRestoreHP[client] = view_as(g_Config.GetNum("RestoreHP", 1)); g_bFullKnife[client] = view_as(g_Config.GetNum("FullKnife", 0)); g_iSpecialKnife[client] = entity; CheckChildren(client, entity); } public void OnWeaponDropped(int client, int entity) { if(entity == g_iSpecialKnife[client]) { ZR_SetClientKnockbackScale(client, 1.0); ZR_SetClientKnockbackMaxForce(client, 0.0); ZR_SetClientKnockbackMaxVelocity(client, -1.0); g_iSpecialKnife[client] = 0; g_bNoSlowdown[client] = false; g_bRestoreHP[client] = false; g_bFullKnife[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; g_LastAttacker = attacker; g_LastVictim = client; int flags = ZR_KNOCKBACK_CUSTOM | ZR_KNOCKBACK_SCALE | ZR_KNOCKBACK_LIMITFORCE | ZR_KNOCKBACK_LIMITVEL; if(g_bFullKnife[client]) { char sWeaponClassname[64]; if(inflictor == attacker) { int iWeapon = GetClientActiveWeapon(attacker); if(iWeapon > 0) GetEdictClassname(iWeapon, sWeaponClassname, sizeof(sWeaponClassname)); } else GetEdictClassname(inflictor, sWeaponClassname, sizeof(sWeaponClassname)); if(StrEqual(sWeaponClassname, "weapon_knife")) flags &= ~(ZR_KNOCKBACK_SCALE | ZR_KNOCKBACK_LIMITFORCE | ZR_KNOCKBACK_LIMITVEL); } float flVelocityModifier; if(g_bNoSlowdown[client]) flVelocityModifier = GetEntDataFloat(client, g_hVelocityModifier); int iClientHealth; if(g_bRestoreHP[client]) iClientHealth = GetClientHealth(client); // Don't damage kevlar. damagetype |= DMG_RADIATION; SDKHooks_TakeDamage(client, inflictor, attacker, damage, damagetype, weapon, damageForce, damagePosition, flags); if(g_bNoSlowdown[client]) SetEntDataFloat(client, g_hVelocityModifier, flVelocityModifier, true); if(g_bRestoreHP[client]) SetEntityHealth(client, iClientHealth); return Plugin_Continue; } stock int GetClientActiveWeapon(int client) { return GetEntDataEnt2(client, g_hActiveWeapon); }