#pragma semicolon 1 #pragma newdecls required #include #include #include #include public Plugin myinfo = { name = "FixGameUI", author = "hlstriker + GoD-Tony", description = "Fixes game_ui entity bug and blocks DMG_CRUSH.", version = "1.0", url = "" } Handle g_hAcceptInput; ArrayList g_hAttachedClients; public void OnPluginStart() { HookEvent("player_death", Event_PlayerDeath, EventHookMode_Post); HookEntityOutput("game_ui", "PlayerOn", GameUI_PlayerOn); HookEntityOutput("game_ui", "PlayerOff", GameUI_PlayerOff); g_hAttachedClients = new ArrayList(); // Gamedata. Handle hConfig = LoadGameConfigFile("sdktools.games"); if (hConfig == INVALID_HANDLE) SetFailState("Couldn't load sdktools game config!"); int offset = GameConfGetOffset(hConfig, "AcceptInput"); if (offset == -1) SetFailState("Failed to find AcceptInput offset"); delete hConfig; // DHooks. g_hAcceptInput = DHookCreate(offset, HookType_Entity, ReturnType_Bool, ThisPointer_CBaseEntity, Hook_AcceptInput); DHookAddParam(g_hAcceptInput, HookParamType_CharPtr); DHookAddParam(g_hAcceptInput, HookParamType_CBaseEntity); DHookAddParam(g_hAcceptInput, HookParamType_CBaseEntity); DHookAddParam(g_hAcceptInput, HookParamType_Object, 20); //varaint_t is a union of 12 (float[3]) plus two int type params 12 + 8 = 20 DHookAddParam(g_hAcceptInput, HookParamType_Int); } public Action Event_PlayerDeath(Handle hEvent, const char[] szName, bool bDontBroadcast) { int client = GetClientOfUserId(GetEventInt(hEvent, "userid")); RemoveFromGameUI(client); SetClientViewEntity(client, client); int iFlags = GetEntityFlags(client); iFlags &= ~FL_ONTRAIN; iFlags &= ~FL_FROZEN; iFlags &= ~FL_ATCONTROLS; SetEntityFlags(client, iFlags); } public void OnClientDisconnect(int client) { RemoveFromGameUI(client); } public void GameUI_PlayerOn(const char[] szOutput, int iCaller, int iActivator, float fDelay) { if(!(1 <= iActivator <= MaxClients)) return; int GameUIArray[2]; GameUIArray[0] = iCaller; GameUIArray[1] = iActivator; g_hAttachedClients.PushArray(GameUIArray); } public void GameUI_PlayerOff(const char[] szOutput, int iCaller, int iActivator, float fDelay) { if(!(1 <= iActivator <= MaxClients)) return; for(int i; i < g_hAttachedClients.Length; i++) { int GameUIArray[2]; g_hAttachedClients.GetArray(i, GameUIArray); if (GameUIArray[0] == iCaller) { g_hAttachedClients.Erase(i); break; } } } public void OnEntityDestroyed(int entity) { for(int i; i < g_hAttachedClients.Length; i++) { int GameUIArray[2]; g_hAttachedClients.GetArray(i, GameUIArray); if (GameUIArray[0] == entity) { g_hAttachedClients.Erase(i); break; } } } void RemoveFromGameUI(int client) { for(int i; i < g_hAttachedClients.Length; i++) { int GameUIArray[2]; g_hAttachedClients.GetArray(i, GameUIArray); if (GameUIArray[1] == client) { AcceptEntityInput(GameUIArray[0], "Deactivate", GameUIArray[1], GameUIArray[0]); g_hAttachedClients.Erase(i); } } } public void OnEntityCreated(int entity, const char[] classname) { if (StrEqual(classname, "game_ui")) { DHookEntity(g_hAcceptInput, false, entity); } } public MRESReturn Hook_AcceptInput(int thisptr, Handle hReturn, Handle hParams) { char sCommand[128]; DHookGetParamString(hParams, 1, sCommand, sizeof(sCommand)); if (StrEqual(sCommand, "Deactivate", false)) { int pPlayer = GetEntPropEnt(thisptr, Prop_Data, "m_player"); if (pPlayer == -1) { // Manually disable think. SetEntProp(thisptr, Prop_Data, "m_nNextThinkTick", -1); DHookSetReturn(hReturn, false); return MRES_Supercede; } } DHookSetReturn(hReturn, true); return MRES_Ignored; }