#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; }