From d300d7bc9cfa4cd425061fe3f4d720f8191456bf Mon Sep 17 00:00:00 2001 From: jenz Date: Mon, 12 Oct 2026 13:58:19 +0200 Subject: [PATCH] minimal change for zr --- Hitmarker/scripting/Hitmarker_zr.sp | 674 ++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 Hitmarker/scripting/Hitmarker_zr.sp diff --git a/Hitmarker/scripting/Hitmarker_zr.sp b/Hitmarker/scripting/Hitmarker_zr.sp new file mode 100644 index 0000000..e6f481d --- /dev/null +++ b/Hitmarker/scripting/Hitmarker_zr.sp @@ -0,0 +1,674 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma newdecls required +#pragma semicolon 1 + +#define SPECMODE_NONE 0 +#define SPECMODE_FIRSTPERSON 4 +#define SPECMODE_THIRDPERSON 5 +#define SPECMODE_FREELOOK 6 + +#define MAX_EDICTS 2048 +bool g_bHasOutputs[MAX_EDICTS]; + +bool g_bShowBossHitmarker[MAXPLAYERS+1]; +bool g_bShowZombieHitmarker[MAXPLAYERS+1]; +bool g_bHitmarkerSound[MAXPLAYERS+1]; + +int g_iHitmarkerSoundVolume[MAXPLAYERS+1] = {100,...}; +int g_iHitmarkerSkin[MAXPLAYERS+1]; + +#define MAXIMUMSKINS 24 +char g_sHitmarkerSkins[MAXIMUMSKINS][PLATFORM_MAX_PATH]; +char g_sHitmarkerSkinsNames[MAXIMUMSKINS][PLATFORM_MAX_PATH]; + +Handle g_hTimer[MAXPLAYERS+1] = {null,...}; + +Handle g_hCookie_ShowBossHitmarker; +Handle g_hCookie_ShowZombieHitmarker; +Handle g_hCookie_HitmarkerSound; +Handle g_hCookie_HitmarkerSoundVolume; +Handle g_hCookie_HitmarkerSkin; + +ConVar g_hCVar_Debug; +ConVar g_hCVar_HitmarkerEnabled; + +bool g_bLate; + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public Plugin myinfo = +{ + name = "Hitmarker", + author = "Neon", + description = "Players can enable or disable their hitmarkers while shooting zombies or bosses", + version = "3.1", +}; + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public APLRes AskPluginLoad2(Handle hMyself, bool bLate, char[] sError, int errorSize) +{ + g_bLate = bLate; + return APLRes_Success; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void OnPluginStart() +{ + Handle g_hOnTakeDamageDetour; + Handle hGameData = LoadGameConfigFile("Hitmarker.games"); + if(!hGameData) + SetFailState("Failed to load Hitmarker gamedata."); + + g_hOnTakeDamageDetour = DHookCreateFromConf(hGameData, "CBaseEntity__OnTakeDamage"); + if(!g_hOnTakeDamageDetour) + SetFailState("Failed to setup detour for CBaseEntity__OnTakeDamage"); + + delete hGameData; + + if(!DHookEnableDetour(g_hOnTakeDamageDetour, true, Detour_OnTakeDamage)) + SetFailState("Failed to detour CBaseEntity__OnTakeDamage."); + + g_hCookie_ShowBossHitmarker = RegClientCookie("hitmarker_boss", "", CookieAccess_Private); + g_hCookie_ShowZombieHitmarker = RegClientCookie("hitmarker_zombie", "", CookieAccess_Private); + g_hCookie_HitmarkerSound = RegClientCookie("hitmarker_sound", "", CookieAccess_Private); + g_hCookie_HitmarkerSoundVolume = RegClientCookie("hitmarker_sound_volume", "", CookieAccess_Private); + g_hCookie_HitmarkerSkin = RegClientCookie("hitmarker_skin", "", CookieAccess_Private); + + g_hCVar_Debug = CreateConVar("sm_hitmarker_debug", "0", "", FCVAR_NONE, true, 0.0, true, 1.0); + g_hCVar_HitmarkerEnabled = CreateConVar("sm_hitmarker_enabled", "1", "", FCVAR_NONE, true, 0.0, true, 1.0); + g_hCVar_HitmarkerEnabled.AddChangeHook(OnConVarChanged); + AutoExecConfig(true); + + RegConsoleCmd("sm_hm", OnHitmarkerSettings); + RegConsoleCmd("sm_hitmarker", OnHitmarkerSettings); + RegConsoleCmd("sm_bhm", OnToggleBossHitmarker); + RegConsoleCmd("sm_zhm", OnToggleZombieHitmarker); + RegConsoleCmd("sm_hmsound", OnToggleHitmarkerSound); + + SetCookieMenuItem(MenuHandler_CookieMenu, 0, "Hitmarker"); + + HookEvent("player_hurt", OnClientHurt); + + if (g_bLate) + { + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i) && AreClientCookiesCached(i)) + OnClientCookiesCached(i); + } + } +} + +public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue) +{ + if(g_hCVar_HitmarkerEnabled.BoolValue) + CPrintToChatAll("{cyan}[Hitmarker] {white}has been allowed."); + else + CPrintToChatAll("{cyan}[Hitmarker] {white}has been disabled."); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void OnMapStart() +{ + for (int i = 0; i < MAXIMUMSKINS; i++) + { + g_sHitmarkerSkins[i] = ""; + g_sHitmarkerSkinsNames[i] = ""; + } + + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return; + } + + char sConfigFile[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), "configs/Hitmarkers.cfg"); + + if (!FileExists(sConfigFile)) + SetFailState("Could not find: \"%s\"", sConfigFile); + + KeyValues Hitmarkers = new KeyValues("Hitmarkers"); + + if (!Hitmarkers.ImportFromFile(sConfigFile)) + { + delete Hitmarkers; + SetFailState("ImportFromFile() failed!"); + } + + if (!Hitmarkers.GotoFirstSubKey()) + { + delete Hitmarkers; + SetFailState("Unable to goto first sub key in: \"%s\"", sConfigFile); + } + + int i = 0; + do + { + char sPath[PLATFORM_MAX_PATH]; + Hitmarkers.GetString("Path", sPath, sizeof(sPath), "error"); + if (StrEqual(sPath, "error")) + { + delete Hitmarkers; + SetFailState("Unable to read Path"); + } + + char sName[32]; + Hitmarkers.GetString("Name", sName, sizeof(sName), "error"); + if (StrEqual(sName, "error")) + { + delete Hitmarkers; + SetFailState("Unable to read Name"); + } + + char sBuffer[PLATFORM_MAX_PATH]; + + Format(sBuffer, sizeof(sBuffer), "materials/%s.vmt", sPath); + PrecacheGeneric(sBuffer, true); + AddFileToDownloadsTable(sBuffer); + + Format(sBuffer, sizeof(sBuffer), "materials/%s.vtf", sPath); + PrecacheGeneric(sBuffer, true); + AddFileToDownloadsTable(sBuffer); + + g_sHitmarkerSkins[i] = sPath; + g_sHitmarkerSkinsNames[i] = sName; + i++; + } while(Hitmarkers.GotoNextKey()); + delete Hitmarkers; + + PrecacheSound("unloze/hm_v3.mp3"); + AddFileToDownloadsTable("sound/unloze/hm_v3.mp3"); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void OnClientCookiesCached(int client) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return; + } + + char sBuffer[PLATFORM_MAX_PATH]; + + GetClientCookie(client, g_hCookie_ShowBossHitmarker, sBuffer, sizeof(sBuffer)); + if (sBuffer[0]) + g_bShowBossHitmarker[client] = true; + else + g_bShowBossHitmarker[client] = false; + + GetClientCookie(client, g_hCookie_ShowZombieHitmarker, sBuffer, sizeof(sBuffer)); + if (sBuffer[0]) + g_bShowZombieHitmarker[client] = true; + else + g_bShowZombieHitmarker[client] = false; + + GetClientCookie(client, g_hCookie_HitmarkerSound, sBuffer, sizeof(sBuffer)); + if (sBuffer[0]) + g_bHitmarkerSound[client] = true; + else + g_bHitmarkerSound[client] = false; + + GetClientCookie(client, g_hCookie_HitmarkerSoundVolume, sBuffer, sizeof(sBuffer)); + if (sBuffer[0]) + g_iHitmarkerSoundVolume[client] = StringToInt(sBuffer); + else + g_iHitmarkerSoundVolume[client] = 100; + + GetClientCookie(client, g_hCookie_HitmarkerSkin, sBuffer, sizeof(sBuffer)); + if (sBuffer[0]) + { + for (int i = 0; i < MAXIMUMSKINS; i++) + { + if (StrEqual(g_sHitmarkerSkins[i], sBuffer)) + { + g_iHitmarkerSkin[client] = i; + break; + } + } + } + else + g_iHitmarkerSkin[client] = 0; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void OnClientDisconnect(int client) +{ + g_bShowBossHitmarker[client] = false; + g_bShowZombieHitmarker[client] = false; + g_bHitmarkerSound[client] = false; + g_iHitmarkerSoundVolume[client] = 100; + g_iHitmarkerSkin[client] = 0; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public Action OnHitmarkerSettings(int client, int args) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return Plugin_Handled; + } + ShowSettingsMenu(client); + return Plugin_Handled; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public Action OnToggleBossHitmarker(int client, int args) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return Plugin_Handled; + } + ToggleBossHitmarker(client); + return Plugin_Handled; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void ToggleBossHitmarker(int client) +{ + g_bShowBossHitmarker[client] = !g_bShowBossHitmarker[client]; + SetClientCookie(client, g_hCookie_ShowBossHitmarker, g_bShowBossHitmarker[client] ? "1" : ""); + + CPrintToChat(client, "{cyan}[Hitmarker] {white}%s.", g_bShowBossHitmarker[client] ? "Boss Hitmarker Enabled" : "Boss Hitmarker Disabled"); + + if (g_bShowBossHitmarker[client]) + ShowOverlay(client, 2.0); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public Action OnToggleZombieHitmarker(int client, int args) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return Plugin_Handled; + } + ToggleZombieHitmarker(client); + return Plugin_Handled; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void ToggleZombieHitmarker(int client) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return; + } + g_bShowZombieHitmarker[client] = !g_bShowZombieHitmarker[client]; + SetClientCookie(client, g_hCookie_ShowZombieHitmarker, g_bShowZombieHitmarker[client] ? "1" : ""); + + CPrintToChat(client, "{cyan}[Hitmarker] {white}%s.", g_bShowZombieHitmarker[client] ? "Zombie Hitmarker Enabled" : "Zombie Hitmarker Disabled"); + + if (g_bShowZombieHitmarker[client]) + ShowOverlay(client, 2.0); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public Action OnToggleHitmarkerSound(int client, int args) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return Plugin_Handled; + } + ToggleHitmarkerSound(client); + return Plugin_Handled; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void ToggleHitmarkerSound(int client) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return; + } + g_bHitmarkerSound[client] = !g_bHitmarkerSound[client]; + SetClientCookie(client, g_hCookie_HitmarkerSound, g_bHitmarkerSound[client] ? "1" : ""); + + CPrintToChat(client, "{cyan}[Hitmarker] {white}%s.", g_bHitmarkerSound[client] ? "Hitmarker Sound Enabled" : "Hitmarker Sound Disabled"); + + if (g_bHitmarkerSound[client]) + ShowOverlay(client, 2.0); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void ToggleHitmarkerSoundVolume(int client) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return; + } + g_iHitmarkerSoundVolume[client] += 25; + + if(g_iHitmarkerSoundVolume[client] > 100) + g_iHitmarkerSoundVolume[client] = 25; + + char sBuffer[16]; + IntToString(g_iHitmarkerSoundVolume[client], sBuffer, sizeof(sBuffer)); + + SetClientCookie(client, g_hCookie_HitmarkerSoundVolume, sBuffer); + + ShowOverlay(client, 2.0); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void ToggleHitmarkerSkin(int client) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return; + } + g_iHitmarkerSkin[client]++; + + if (StrEqual(g_sHitmarkerSkins[g_iHitmarkerSkin[client]], "")) + g_iHitmarkerSkin[client] = 0; + + SetClientCookie(client, g_hCookie_HitmarkerSkin, g_sHitmarkerSkins[g_iHitmarkerSkin[client]]); + + ShowOverlay(client, 2.0); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void ShowSettingsMenu(int client) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return; + } + Menu menu = new Menu(MenuHandler_MainMenu); + + menu.SetTitle("Hitmarker Settings", client); + + char sBuffer[128]; + + Format(sBuffer, sizeof(sBuffer), "Boss Hitmarker: %s", g_bShowBossHitmarker[client] ? "Enabled" : "Disabled"); + menu.AddItem("0", sBuffer); + + Format(sBuffer, sizeof(sBuffer), "Zombie Hitmarker: %s", g_bShowZombieHitmarker[client] ? "Enabled" : "Disabled"); + menu.AddItem("1", sBuffer); + + Format(sBuffer, sizeof(sBuffer), "Hitmarker Sound: %s", g_bHitmarkerSound[client] ? "Enabled" : "Disabled"); + menu.AddItem("2", sBuffer); + + Format(sBuffer, sizeof(sBuffer), "Hitmarker Sound Volume: %d\%", g_iHitmarkerSoundVolume[client]); + menu.AddItem("3", sBuffer); + + Format(sBuffer, sizeof(sBuffer), "Hitmarker Skin: %s", g_sHitmarkerSkinsNames[g_iHitmarkerSkin[client]]); + menu.AddItem("4", sBuffer); + + menu.ExitBackButton = true; + + menu.Display(client, MENU_TIME_FOREVER); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void MenuHandler_CookieMenu(int client, CookieMenuAction action, any info, char[] buffer, int maxlen) +{ + switch(action) + { + case(CookieMenuAction_DisplayOption): + { + Format(buffer, maxlen, "Hitmarker", client); + } + case(CookieMenuAction_SelectOption): + { + ShowSettingsMenu(client); + } + } +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public int MenuHandler_MainMenu(Menu menu, MenuAction action, int client, int selection) +{ + switch(action) + { + case(MenuAction_Select): + { + switch(selection) + { + case(0): ToggleBossHitmarker(client); + case(1): ToggleZombieHitmarker(client); + case(2): ToggleHitmarkerSound(client); + case(3): ToggleHitmarkerSoundVolume(client); + case(4): ToggleHitmarkerSkin(client); + } + + ShowSettingsMenu(client); + } + case(MenuAction_Cancel): + { + ShowCookieMenu(client); + } + case(MenuAction_End): + { + delete menu; + } + } +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void OnEntitySpawned(int Entity, const char[] sClassname) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return; + } + int ent = EntRefToEntIndex(Entity); + + if (0 < ent < MAX_EDICTS) + { + if ((GetOutputCount(ent, "m_OnDamaged") > 0) || (GetOutputCount(ent, "m_OnHealthChanged") > 0)) + g_bHasOutputs[ent] = true; + else + g_bHasOutputs[ent] = false; + } +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +/* +public void OnBossDamaged(CBoss Boss, CConfig Config, int client, float damage) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return; + } + if (!IsValidClient(client)) + return; + + if (g_bShowBossHitmarker[client]) + ShowOverlay(client); + + for (int spec = 1; spec <= MaxClients; spec++) + { + if (!IsClientInGame(spec) || !IsClientObserver(spec) || !g_bShowBossHitmarker[spec]) + continue; + + int specMode = GetClientSpectatorMode(spec); + int specTarget = GetClientSpectatorTarget(spec); + + if ((specMode == SPECMODE_FIRSTPERSON) && specTarget == client) + ShowOverlay(spec); + } +} +*/ +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public MRESReturn Detour_OnTakeDamage(int entity, Handle hReturn, Handle hParams) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return MRES_Ignored; + } + //https://github.com/alliedmodders/hl2sdk/blob/css/game/shared/takedamageinfo.h#L115 + int iHealth = GetEntProp(entity, Prop_Data, "m_iHealth"); + int client = DHookGetParamObjectPtrVar(hParams, 1, 3*(3*4) + 0, ObjectValueType_Ehandle); + + if (g_hCVar_Debug.BoolValue) + { + float dmg = DHookGetParamObjectPtrVar(hParams, 1, 48, ObjectValueType_Float); + PrintToChatAll("Detour_OnTakeDamage: ent: %d; client: %d; m_iHealth: %d; output: %d; dmg: %f", entity, client, iHealth, g_bHasOutputs[entity], dmg); + } + + if (!iHealth && !g_bHasOutputs[entity]) + return MRES_Ignored; + + if (!IsValidClient(client)) + return MRES_Ignored; + + if (g_bShowBossHitmarker[client]) + ShowOverlay(client); + + for (int spec = 1; spec <= MaxClients; spec++) + { + if (!IsClientInGame(spec) || !IsClientObserver(spec) || !g_bShowBossHitmarker[spec]) + continue; + + int specMode = GetClientSpectatorMode(spec); + int specTarget = GetClientSpectatorTarget(spec); + + if ((specMode == SPECMODE_FIRSTPERSON) && specTarget == client) + ShowOverlay(spec); + } + + return MRES_Ignored; +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public void OnClientHurt(Event hEvent, const char[] sEvent, bool bDontBroadcast) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return; + } + int client = GetClientOfUserId(hEvent.GetInt("attacker")); + int victim = GetClientOfUserId(hEvent.GetInt("userid")); + + if (client < 1 || client > MaxClients || victim < 1 || victim > MaxClients) + return; + + if (client == victim || (IsPlayerAlive(client) && GetClientTeam(client)) == CS_TEAM_CT) + return; + + if (g_bShowZombieHitmarker[client]) + ShowOverlay(client); + + for (int spec = 1; spec <= MaxClients; spec++) + { + if (!IsClientInGame(spec) || !IsClientObserver(spec) || !g_bShowZombieHitmarker[spec]) + continue; + + int specMode = GetClientSpectatorMode(spec); + int specTarget = GetClientSpectatorTarget(spec); + + if (specMode == SPECMODE_FIRSTPERSON && specTarget == client) + ShowOverlay(spec); + } +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +void ShowOverlay(int client, float fTime = 0.3) +{ + if(!g_hCVar_HitmarkerEnabled.BoolValue) + { + return; + } + if (g_bHitmarkerSound[client]) + { + float fVolume = g_iHitmarkerSoundVolume[client] / 100.0; + EmitSoundToClient(client, "unloze/hm_v3.mp3", .volume=fVolume); + } + + if (g_hTimer[client] != null) + { + delete g_hTimer[client]; + g_hTimer[client] = null; + } + ClientCommand(client, "r_screenoverlay \"%s\"", g_sHitmarkerSkins[g_iHitmarkerSkin[client]]); + g_hTimer[client] = CreateTimer(fTime, ClearOverlay, client); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +public Action ClearOverlay(Handle timer, int client) +{ + g_hTimer[client] = null; + if (IsClientConnected(client)) + ClientCommand(client, "r_screenoverlay \"\""); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +stock int IsValidClient(int client, bool nobots = true) +{ + if (client <= 0 || client > MaxClients || !IsClientConnected(client) || (nobots && IsFakeClient(client))) + return false; + + return IsClientInGame(client); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +int GetClientSpectatorMode(int client) +{ + return GetEntProp(client, Prop_Send, "m_iObserverMode"); +} + +//---------------------------------------------------------------------------------------------------- +// Purpose: +//---------------------------------------------------------------------------------------------------- +int GetClientSpectatorTarget(int client) +{ + return GetEntPropEnt(client, Prop_Send, "m_hObserverTarget"); +}