diff --git a/scripting/include/hats/hat_presets.sp b/scripting/include/hats/hat_presets.sp new file mode 100644 index 0000000..2f0e258 --- /dev/null +++ b/scripting/include/hats/hat_presets.sp @@ -0,0 +1,245 @@ +#define MODEL_LENGTH 64 +char SURVIVOR_NAMES[8][] = { "nick", "rochelle", "coach", "ellis", "bill", "zoey", "francis", "louis"}; + +enum struct PresetLocation { + int survivorSet; + float offset[3]; + float angles[3]; +} + +enum struct HatPreset { + float offset[3]; + float angles[3]; + char model[MODEL_LENGTH]; + char type[32]; + float size; + + ArrayList locations; + + int Spawn() { + PrecacheModel(this.model); + int entity = CreateEntityByName(this.type); + DispatchKeyValue(entity, "model", this.model); + if(HasEntProp(entity, Prop_Send, "m_flModelScale")) + SetEntPropFloat(entity, Prop_Send, "m_flModelScale", this.size); + if(!DispatchSpawn(entity)) { + LogError("Could not spawn entity of type %s model \"%s\"", this.type, this.model); + } + return entity; + } + + int Apply(int client) { + int entity = this.Spawn(); + float offset[3], angles[3]; + EquipHat(client, entity, this.type, HAT_PRESET); + this.GetLocation(client, offset, angles); + hatData[client].offset = offset; + hatData[client].angles = angles; + CreateTimer(0.1, Timer_RemountSimple, GetClientUserId(client)); + return entity; + } + + void GetLocation(int client, float offset[3], float angles[3]) { + if(this.locations != null) { + int survivorSet = GetEntProp(client, Prop_Send, "m_survivorCharacter"); + if(survivorSet < 0 || survivorSet > 7) survivorSet = 0; + PresetLocation location; + for(int i = 0; i < this.locations.Length; i++) { + this.locations.GetArray(i, location, sizeof(location)); + if(location.survivorSet == survivorSet) { + offset = location.offset; + angles = location.angles; + return; + } + } + } + offset = this.offset; + angles = this.angles; + } + +} + +Action Timer_RemountSimple(Handle h, int userid) { + int client = GetClientOfUserId(userid); + if(client > 0) { + int entity = GetHat(client); + if(entity > 0) + TeleportEntity(entity, hatData[client].offset, hatData[client].angles, NULL_VECTOR); + } + return Plugin_Handled; +} + +void LoadPresets() { + KeyValues kv = new KeyValues("Presets"); + + char sPath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sPath, sizeof(sPath), "data/hat_presets.cfg"); + + if(!FileExists(sPath) || !kv.ImportFromFile(sPath)) { + PrintToServer("[Hats] Missing presets list"); + delete kv; + } + StringMap presets = new StringMap(); + + kv.GotoFirstSubKey(); + // char type[32]; + int count = 0; + char name[32]; + do { + kv.GetSectionName(name, sizeof(name)); + HatPreset preset; + // kv.GetString("type", entCfg.type, sizeof(entCfg.type), "prop_physics"); + kv.GetString("model", preset.model, sizeof(preset.model), ""); + kv.GetString("type", preset.type, sizeof(preset.type), "prop_dynamic"); + preset.size = kv.GetFloat("size", 1.0); + if(preset.model[0] == '\0') { + PrintToServer("[Hats] Warn: Skipping %s, no model", name); + continue; + } + + if(kv.JumpToKey("default")) { + kv.GetVector("offset", preset.offset, NULL_VECTOR); + kv.GetVector("angles", preset.angles, NULL_VECTOR); + kv.GoBack(); + } else { + PrintToServer("[Hats] Warn: Missing default for %s", name); + continue; + } + + for(int i = 0; i < 7; i++) { + if(kv.JumpToKey(SURVIVOR_NAMES[i])) { + if(preset.locations == null) { + preset.locations = new ArrayList(sizeof(PresetLocation)); + } + PresetLocation location; + location.survivorSet = i; // TODO: confirm with l4d/l4d2 modes? + kv.GetVector("offset", location.offset, NULL_VECTOR); + kv.GetVector("angles", location.angles, NULL_VECTOR); + preset.locations.PushArray(location); + kv.GoBack(); + } + } + + count++; + presets.SetArray(name, preset, sizeof(preset)); + } while(kv.GotoNextKey(true)); + kv.GoBack(); + + PrintToServer("[Hats] Loaded %d presets", count); + + + if(g_HatPresets != null) { + HatPreset preset; + StringMapSnapshot snapshot = g_HatPresets.Snapshot(); + for(int i = 0; i <= snapshot.Length; i++) { + snapshot.GetKey(i, name, sizeof(name)); + g_HatPresets.GetArray(name, preset, sizeof(preset)); + if(preset.locations != null) { + delete preset.locations; + } + } + delete g_HatPresets; + } + g_HatPresets = presets; +} + + +Action Command_DoAHatPreset(int client, int args) { + AdminId adminId = GetUserAdmin(client); + if(cvar_sm_hats_enabled.IntValue == 1) { + if(adminId == INVALID_ADMIN_ID) { + PrintToChat(client, "[Hats] Hats are for admins only"); + return Plugin_Handled; + } else if(!adminId.HasFlag(Admin_Cheats)) { + PrintToChat(client, "[Hats] You do not have permission"); + return Plugin_Handled; + } + } else if(cvar_sm_hats_enabled.IntValue == 0) { + ReplyToCommand(client, "[Hats] Hats are disabled"); + return Plugin_Handled; + } else if(GetClientTeam(client) != 2 && ~cvar_sm_hats_flags.IntValue & view_as(HatConfig_InfectedHats)) { + PrintToChat(client, "[Hats] Hats are only available for survivors."); + return Plugin_Handled; + } + + + int entity = GetHat(client); + if(entity > 0) { + if(args > 0) { + char arg[64]; + GetCmdArg(1, arg, sizeof(arg)); + if(arg[0] == 'v') { + ReplyToCommand(client, "\t{"); + GetEntPropString(entity, Prop_Data, "m_ModelName", arg, sizeof(arg)); + ReplyToCommand(client, "\t\t\"model\"\t\"%s\"", arg); + ReplyToCommand(client, "\t\t\"default\"\n\t\t{"); + ReplyToCommand(client, "\t\t\t\"origin\"\t\"%f %f %f\"", hatData[client].offset[0], hatData[client].offset[1], hatData[client].offset[2]); + ReplyToCommand(client, "\t\t\t\"angles\"\t\"%f %f %f\"", hatData[client].angles[0], hatData[client].angles[1], hatData[client].angles[2]); + ReplyToCommand(client, "\t\t}"); + ReplyToCommand(client, "\t\t\"size\"\t\"%.1f\"", GetEntPropFloat(entity, Prop_Send, "m_flModelScale")); + GetEntityClassname(entity, arg, sizeof(arg)); + ReplyToCommand(client, "\t\t\"type\"\t\"%.1f\"", arg); + ReplyToCommand(client, "\t}"); + ReplyToCommand(client, "Flags: %d", hatData[client].flags); + } else { + ReplyToCommand(client, "Unknown option"); + } + // ReplyToCommand(client, "CurOffset: %f %f %f", ); + return Plugin_Handled; + } + if(HasFlag(client, HAT_PRESET)) { + ClearHat(client); + RemoveEntity(entity); + PrintToChat(client, "[Hats] Cleared your hat preset"); + hatPresetCookie.Set(client, ""); + ActivePreset[client][0] = '\0'; + + } else { + PrintToChat(client, "[Hats] You already have a hat. Clear your hat to apply a preset."); + } + } else { + Menu menu = new Menu(HatPresetHandler); + menu.SetTitle("Choose a Hat", client); + char id[32]; + StringMapSnapshot snapshot = g_HatPresets.Snapshot(); + if(snapshot.Length == 0) { + PrintToChat(client, "[Hats] Seems there is no presets..."); + delete snapshot; + return Plugin_Handled; + } + for(int i = 0; i < snapshot.Length; i++) { + snapshot.GetKey(i, id, sizeof(id)); + menu.AddItem(id, id); + } + menu.Display(client, 0); + delete snapshot; + } + return Plugin_Handled; +} + + +int HatPresetHandler(Menu menu, MenuAction action, int param1, int param2) { + if (action == MenuAction_Select) { + static char info[32]; + menu.GetItem(param2, info, sizeof(info)); + HatPreset preset; + if(g_HatPresets.GetArray(info, preset, sizeof(preset))) { + strcopy(ActivePreset[param1], 32, info); + hatPresetCookie.Set(param1, info); + preset.Apply(param1); + ReplyToCommand(param1, "[Hats] Hat preset \"%s\" applied, enjoy!", info); + } else { + ReplyToCommand(param1, "Unknown hat preset \"%s\"", info); + } + } else if (action == MenuAction_End) + delete menu; + return 0; +} + +void RestoreActivePreset(int client) { + if(ActivePreset[client][0] != '\0') { + HatPreset preset; + g_HatPresets.GetArray(ActivePreset[client], preset, sizeof(preset)); + preset.Apply(client); + } +} \ No newline at end of file diff --git a/scripting/include/hats/hats.sp b/scripting/include/hats/hats.sp index 6332f3a..c350525 100644 --- a/scripting/include/hats/hats.sp +++ b/scripting/include/hats/hats.sp @@ -3,7 +3,8 @@ enum hatFlags { HAT_POCKET = 1, HAT_REVERSED = 2, HAT_COMMANDABLE = 4, - HAT_RAINBOW = 8 + HAT_RAINBOW = 8, + HAT_PRESET = 16 } enum struct HatData { int entity; // The entity REFERENCE @@ -24,6 +25,7 @@ enum struct HatData { float rainbowColor[3]; int rainbowTicks; bool rainbowReverse; + char attachPoint[32]; } enum hatFeatures { HatConfig_None = 0, @@ -38,6 +40,8 @@ enum hatFeatures { } HatData hatData[MAXPLAYERS+1]; +char ActivePreset[MAXPLAYERS+1][32]; +StringMap g_HatPresets; int lastHatRequestTime[MAXPLAYERS+1]; #define MAX_FORBIDDEN_CLASSNAMES 13 @@ -61,7 +65,7 @@ char FORBIDDEN_CLASSNAMES[MAX_FORBIDDEN_CLASSNAMES][] = { #define MAX_FORBIDDEN_MODELS 1 char FORBIDDEN_MODELS[MAX_FORBIDDEN_MODELS][] = { - "models/props_vehicles/c130.mdl" + "models/props_vehicles/c130.mdl", }; #define MAX_REVERSE_CLASSNAMES 2 @@ -70,7 +74,7 @@ static char REVERSE_CLASSNAMES[MAX_REVERSE_CLASSNAMES][] = { "func_movelinear" }; -public Action Command_DoAHat(int client, int args) { +Action Command_DoAHat(int client, int args) { static char cmdName[8]; GetCmdArg(0, cmdName, sizeof(cmdName)); @@ -107,8 +111,21 @@ public Action Command_DoAHat(int client, int args) { int entity = GetHat(client); if(entity > 0) { + if(HasFlag(client, HAT_PRESET)) { + PrintToChat(client, "[Hats] Your hat is a preset, use /hatp to remove it."); + return Plugin_Handled; + } char arg[4]; GetCmdArg(1, arg, sizeof(arg)); + if(arg[0] == 'e') { + ReplyToCommand(client, "\t\t\"origin\"\t\"%f %f %f\"", hatData[client].offset[0], hatData[client].offset[1], hatData[client].offset[2]); + ReplyToCommand(client, "\t\t\"angles\"\t\"%f %f %f\"", hatData[client].angles[0], hatData[client].angles[1], hatData[client].angles[2]); + return Plugin_Handled; + } else if(arg[0] == 'v') { + ReplyToCommand(client, "Flags: %d", hatData[client].flags); + // ReplyToCommand(client, "CurOffset: %f %f %f", ); + return Plugin_Handled; + } // int orgEntity = entity; if(HasFlag(client, HAT_REVERSED)) { entity = client; @@ -421,15 +438,6 @@ public Action Command_DoAHat(int client, int args) { char classname[64]; GetEntityClassname(entity, classname, sizeof(classname)); - // Check is pretty redudant as the traceray itself shouldn't grab it, but just in case: - if(cvar_sm_hats_blacklist_enabled.BoolValue) { - for(int i = 0; i < MAX_FORBIDDEN_CLASSNAMES; i++) { - if(StrEqual(FORBIDDEN_CLASSNAMES[i], classname)) { - PrintToChat(client, "[Hats] Entity (%s) is a blacklisted entity. Naughty.", classname); - return Plugin_Handled; - } - } - } // Check for any class that should always be reversed if(~flags & view_as(HAT_REVERSED)) { @@ -446,6 +454,8 @@ public Action Command_DoAHat(int client, int args) { return Plugin_Handled; } + + // Handles consent that a person to be hatted by another player public int HatConsentHandler(Menu menu, MenuAction action, int target, int param2) { if (action == MenuAction_Select) { @@ -483,7 +493,7 @@ void ClearHats() { } } void ClearHat(int i, bool restore = false) { - + int entity = EntRefToEntIndex(hatData[i].entity); int visibleEntity = EntRefToEntIndex(hatData[i].visibleEntity); int modifyEntity = HasFlag(i, HAT_REVERSED) ? i : entity; @@ -561,6 +571,7 @@ bool CanTarget(int victim) { bool IsHatAllowedInSaferoom(int client) { if(L4D_IsMissionFinalMap()) return true; + if(HasFlag(client, HAT_PRESET)) return true; char name[32]; GetEntityClassname(hatData[client].entity, name, sizeof(name)); // Don't allow non-weapons in saferoom @@ -617,7 +628,7 @@ bool HasFlag(int client, hatFlags flag) { return hatData[client].flags & view_as(flag) != 0; } -void EquipHat(int client, int entity, const char[] classname = "", int flags = HAT_NONE) { +void EquipHat(int client, int entity, const char[] classname = "", int flags = HAT_NONE, const char[] attachPoint = "eyes") { if(HasHat(client)) ClearHat(client, true); @@ -633,12 +644,12 @@ void EquipHat(int client, int entity, const char[] classname = "", int flags = H hatData[client].collisionGroup = GetEntProp(modifyEntity, Prop_Send, "m_CollisionGroup"); hatData[client].solidType = GetEntProp(modifyEntity, Prop_Send, "m_nSolidType"); hatData[client].moveType = GetEntProp(modifyEntity, Prop_Send, "movetype"); + strcopy(hatData[client].attachPoint, 32, attachPoint); if(client <= MaxClients) SDKHook(client, SDKHook_OnTakeDamageAlive, OnTakeDamageAlive); if(entity <= MaxClients) SDKHook(entity, SDKHook_OnTakeDamageAlive, OnTakeDamageAlive); if(modifyEntity <= MaxClients) { - AcceptEntityInput(modifyEntity, "DisableLedgeHang"); } else if(cvar_sm_hats_flags.IntValue & view_as(HatConfig_FakeHat)) { return; @@ -672,6 +683,10 @@ void EquipHat(int client, int entity, const char[] classname = "", int flags = H hatData[client].offset[0] = hatData[client].offset[1] = hatData[client].offset[2] = 0.0; hatData[client].angles[0] = hatData[client].angles[1] = hatData[client].angles[2] = 0.0; + if(flags & view_as(HAT_PRESET)) { + hatData[client].flags |= view_as(HAT_PRESET); + } + if(modifyEntity <= MaxClients) { if(HasFlag(client, HAT_REVERSED)) { hatData[client].offset[2] += 7.2; @@ -732,9 +747,9 @@ void EquipHat(int client, int entity, const char[] classname = "", int flags = H TeleportEntity(modifyEntity, hatData[client].offset, hatData[client].angles, NULL_VECTOR); SetParentAttachment(modifyEntity, "head", true); } else { - SetParentAttachment(modifyEntity, "eyes", true); + SetParentAttachment(modifyEntity, attachPoint, true); TeleportEntity(modifyEntity, hatData[client].offset, hatData[client].angles, NULL_VECTOR); - SetParentAttachment(modifyEntity, "eyes", true); + SetParentAttachment(modifyEntity, attachPoint, true); } if(HasFlag(client, HAT_COMMANDABLE)) { @@ -743,17 +758,17 @@ void EquipHat(int client, int entity, const char[] classname = "", int flags = H } } else { SetParent(entity, client); - SetParentAttachment(modifyEntity, "eyes", true); + SetParentAttachment(modifyEntity, attachPoint, true); TeleportEntity(modifyEntity, hatData[client].offset, hatData[client].angles, NULL_VECTOR); - SetParentAttachment(modifyEntity, "eyes", true); + SetParentAttachment(modifyEntity, attachPoint, true); } if(visibleEntity > 0) { SetParent(visibleEntity, client); - SetParentAttachment(visibleEntity, "eyes", true); + SetParentAttachment(visibleEntity, attachPoint, true); hatData[client].offset[2] += 10.0; TeleportEntity(visibleEntity, hatData[client].offset, hatData[client].angles, NULL_VECTOR); - SetParentAttachment(visibleEntity, "eyes", true); + SetParentAttachment(visibleEntity, attachPoint, true); #if defined DEBUG_HAT_SHOW_FAKE L4D2_SetEntityGlow(visibleEntity, L4D2Glow_Constant, 0, 0, color2, false); #endif diff --git a/scripting/l4d2_hats.sp b/scripting/l4d2_hats.sp index acabe67..e868ec2 100644 --- a/scripting/l4d2_hats.sp +++ b/scripting/l4d2_hats.sp @@ -15,6 +15,7 @@ static float EMPTY_ANG[3] = { 0.0, 0.0, 0.0 }; #include #include #include +#include bool tempGod[MAXPLAYERS+1]; @@ -24,9 +25,9 @@ int g_iLaserIndex; float cmdThrottle[MAXPLAYERS+1]; static bool onLadder[MAXPLAYERS+1]; -float lastAng[MAXPLAYERS+1][3]; Cookie noHatVictimCookie; +Cookie hatPresetCookie; ConVar cvar_sm_hats_enabled; ConVar cvar_sm_hats_flags; @@ -37,6 +38,7 @@ ConVar cvar_sm_hats_max_distance; #include #include +#include public Plugin myinfo = { @@ -63,6 +65,7 @@ public void OnPluginStart() { HookEvent("player_left_checkpoint", OnLeaveSaferoom); HookEvent("player_bot_replace", Event_PlayerToIdle); HookEvent("bot_player_replace", Event_PlayerOutOfIdle); + HookEvent("player_spawn", Event_PlayerSpawn); RegConsoleCmd("sm_hat", Command_DoAHat, "Hats"); RegAdminCmd("sm_hatf", Command_DoAHat, ADMFLAG_ROOT, "Hats"); @@ -70,6 +73,7 @@ public void OnPluginStart() { RegAdminCmd("sm_walls", Command_ManageWalls, ADMFLAG_CHEATS); RegAdminCmd("sm_wall", Command_ManageWalls, ADMFLAG_CHEATS); RegAdminCmd("sm_edit", Command_ManageWalls, ADMFLAG_CHEATS); + RegConsoleCmd("sm_hatp", Command_DoAHatPreset); cvar_sm_hats_blacklist_enabled = CreateConVar("sm_hats_blacklist_enabled", "1", "Is the prop blacklist enabled", FCVAR_NONE, true, 0.0, true, 1.0); cvar_sm_hats_enabled = CreateConVar("sm_hats_enabled", "1.0", "Enable hats.\n0=OFF, 1=Admins Only, 2=Any", FCVAR_NONE, true, 0.0, true, 2.0); @@ -81,6 +85,8 @@ public void OnPluginStart() { noHatVictimCookie = new Cookie("hats_no_target", "Disables other players from making you their hat", CookieAccess_Public); noHatVictimCookie.SetPrefabMenu(CookieMenu_OnOff_Int, "Disable player hats for self", OnLocalPlayerHatCookieSelect); + hatPresetCookie = new Cookie("hats_preset", "Sets the preset hat you spawn with", CookieAccess_Public); + int entity = -1; char targetName[32]; while((entity = FindEntityByClassname(entity, "func_brush")) != INVALID_ENT_REFERENCE) { @@ -95,14 +101,10 @@ public void OnPluginStart() { WallBuilder[i].Reset(true); hatData[i].yeetGroundTimer = null; } + + LoadPresets(); } -//////////////////////////////////////////////////////////////// - - - - - /////////////////////////////////////////////////////////////////////////////////////////////// @@ -129,7 +131,7 @@ public void OnEnterSaferoom(Event event, const char[] name, bool dontBroadcast) if(client > 0 && client <= MaxClients && IsValidClient(client) && GetClientTeam(client) == 2) { inSaferoom[client] = true; if(cvar_sm_hats_flags.IntValue & view_as(HatConfig_NoSaferoomHats)) { - if(HasHat(client)) { + if(HasHat(client) && !HasFlag(client, HAT_PRESET)) { if(!IsHatAllowedInSaferoom(client)) { PrintToChat(client, "[Hats] Hat is not allowed in the saferoom and has been returned"); ClearHat(client, true); @@ -245,14 +247,14 @@ void Frame_Remount(int i) { int entity = GetHat(i); if(entity == -1) return; SetParent(entity, i); - SetParentAttachment(entity, "eyes", false); - SetParentAttachment(entity, "eyes", true); + SetParentAttachment(entity, hatData[i].attachPoint, false); + SetParentAttachment(entity, hatData[i].attachPoint, true); int visibleEntity = EntRefToEntIndex(hatData[i].visibleEntity); if(visibleEntity > 0) { SetParent(visibleEntity, i); - SetParentAttachment(visibleEntity, "eyes", false); - SetParentAttachment(visibleEntity, "eyes", true); + SetParentAttachment(visibleEntity, hatData[i].attachPoint, false); + SetParentAttachment(visibleEntity, hatData[i].attachPoint, true); } } @@ -263,7 +265,9 @@ Action Timer_PropSleep(Handle h, DataPack pack) { int ref = pack.ReadCell(); int client = GetClientOfUserId(pack.ReadCell()); if(client > 0 && IsValidEntity(ref)) { - CheckKill(ref, client); + // CheckKill(ref, client); + float vel[3]; + TeleportEntity(ref, NULL_VECTOR, NULL_VECTOR, vel); PrintToServer("Hats: Yeet delete timeout"); if(hatData[client].yeetGroundTimer != null) { delete hatData[client].yeetGroundTimer; @@ -280,7 +284,11 @@ Action Timer_GroundKill(Handle h, DataPack pack) { GetEntPropVector(ref, Prop_Data, "m_vecVelocity", vel); if(FloatAbs(vel[2]) < 0.2 || IsNearGround(ref)) { PrintToServer("Hats: Yeet ground check %b %b", FloatAbs(vel[2]) < 0.2, IsNearGround(ref)); - CheckKill(ref, client); + vel[0] = 0.0; + vel[1] = 0.0; + vel[2] = 0.0; + TeleportEntity(ref, NULL_VECTOR, NULL_VECTOR, vel); + // CheckKill(ref, client); hatData[client].yeetGroundTimer = null; return Plugin_Stop; } @@ -552,7 +560,6 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3 ClientCommand(client, "sm_hat"); } cmdThrottle[client] = tick; - lastAng[client] = angles; hatData[client].angles = angles; return Plugin_Handled; } @@ -694,6 +701,17 @@ public Action OnTakeDamageAlive(int victim, int& attacker, int& inflictor, float return Plugin_Continue; } +public void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast) { + int client = GetClientOfUserId(event.GetInt("userid")); + if(client > 0 && !HasHat(client) && !IsFakeClient(client)) { + hatPresetCookie.Get(client, ActivePreset[client], 32); + if(ActivePreset[client][0] != '\0') { + RestoreActivePreset(client); + ReplyToCommand(client, "[Hats] Applied your hat preset! Clear it with /hatp"); + } + } +} + public void OnClientDisconnect(int client) { tempGod[client] = false; WallBuilder[client].Reset(); @@ -722,9 +740,9 @@ public void OnMapStart() { tempGod[i] = false; } NavAreas = GetSpawnLocations(); - } + public void OnMapEnd() { delete NavAreas; for(int i = 1; i <= createdWalls.Length; i++) { @@ -788,15 +806,19 @@ bool Filter_ValidHats(int entity, int mask, int data) { int client = GetRealClient(data); return CanTarget(client); // Don't target if player targetting off } + return CheckBlacklist(entity); +} + +bool CheckBlacklist(int entity) { if(cvar_sm_hats_blacklist_enabled.BoolValue) { - static char buffer[32]; + static char buffer[64]; GetEntityClassname(entity, buffer, sizeof(buffer)); for(int i = 0; i < MAX_FORBIDDEN_CLASSNAMES; i++) { if(StrEqual(FORBIDDEN_CLASSNAMES[i], buffer)) { return false; } } - if(StrContains(buffer, "prop_") != -1) { + if(StrContains(buffer, "prop_") > -1) { GetEntPropString(entity, Prop_Data, "m_ModelName", buffer, sizeof(buffer)); for(int i = 0; i < MAX_FORBIDDEN_MODELS; i++) { if(StrEqual(FORBIDDEN_MODELS[i], buffer)) { @@ -804,6 +826,10 @@ bool Filter_ValidHats(int entity, int mask, int data) { } } } + GetEntPropString(entity, Prop_Data, "m_iName", buffer, sizeof(buffer)); + if(StrEqual(buffer, "l4d2_randomizer")) { + return false; + } } return true; }