//==================================================================================================== // // Name: [entWatch] Core // Author: zaCade & Prometheum // Description: Handle the core functions of [entWatch] // //==================================================================================================== #include #pragma newdecls required #include #include #include #include #include /* BOOLS */ bool g_bLate; bool g_bLoaded; bool g_bLoadPending; bool g_bIntermission; /* ARRAYS */ ArrayList g_hArray_Items; ArrayList g_hArray_Configs; /* FORWARDS */ Handle g_hFwd_OnClientItemDrop; Handle g_hFwd_OnClientItemDeath; Handle g_hFwd_OnClientItemPickup; Handle g_hFwd_OnClientItemActivate; Handle g_hFwd_OnClientItemDisconnect; /* HOOKS */ Handle g_hFwd_OnClientItemCanPickup; Handle g_hFwd_OnClientItemCanActivate; //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Plugin myinfo = { name = "[entWatch] Core", author = "zaCade & Prometheum", description = "Handle the core functions of [entWatch]", version = "4.0.0" }; //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public APLRes AskPluginLoad2(Handle hMyself, bool bLate, char[] sError, int errorSize) { g_bLate = bLate; CreateNative("EW_GetItemCount", Native_GetItemCount); CreateNative("EW_GetItemData", Native_GetItemData); RegPluginLibrary("entWatch-core"); return APLRes_Success; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnPluginStart() { g_hFwd_OnClientItemDrop = CreateGlobalForward("EW_OnClientItemDrop", ET_Ignore, Param_Cell, Param_Cell); g_hFwd_OnClientItemDeath = CreateGlobalForward("EW_OnClientItemDeath", ET_Ignore, Param_Cell, Param_Cell); g_hFwd_OnClientItemPickup = CreateGlobalForward("EW_OnClientItemPickup", ET_Ignore, Param_Cell, Param_Cell); g_hFwd_OnClientItemActivate = CreateGlobalForward("EW_OnClientItemActivate", ET_Ignore, Param_Cell, Param_Cell); g_hFwd_OnClientItemDisconnect = CreateGlobalForward("EW_OnClientItemDisconnect", ET_Ignore, Param_Cell, Param_Cell); g_hFwd_OnClientItemCanPickup = CreateGlobalForward("EW_OnClientItemCanPickup", ET_Hook, Param_Cell, Param_Cell); g_hFwd_OnClientItemCanActivate = CreateGlobalForward("EW_OnClientItemCanActivate", ET_Hook, Param_Cell, Param_Cell); g_hArray_Items = new ArrayList(); g_hArray_Configs = new ArrayList(); RegAdminCmd("sm_ereload", Command_ReloadConfig, ADMFLAG_BAN); HookEvent("player_death", OnClientDeath); HookEvent("round_start", OnRoundStart); HookEvent("round_end", OnRoundEnd); if (g_bLate) { for (int client = 1; client <= MaxClients; client++) { if (!IsClientInGame(client) || IsFakeClient(client)) continue; SDKHook(client, SDKHook_WeaponEquipPost, OnWeaponPickup); SDKHook(client, SDKHook_WeaponDropPost, OnWeaponDrop); SDKHook(client, SDKHook_WeaponCanUse, OnWeaponTouch); } } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Action Command_ReloadConfig(int client, int args) { if (g_bLoaded) { g_bLoadPending = !g_bLoadPending; if (g_bLoadPending) { CReplyToCommand(client, "\x07%s[entWatch] \x07%sConfig load pending, loading at roundstart.", "E01B5D", "F16767"); return Plugin_Handled; } else { CReplyToCommand(client, "\x07%s[entWatch] \x07%sPending config load cancelled!", "E01B5D", "F16767"); return Plugin_Handled; } } else { g_bLoaded = LoadConfig(); if (g_bLoaded) { CReplyToCommand(client, "\x07%s[entWatch] \x07%sConfig load successfull.", "E01B5D", "F16767"); return Plugin_Handled; } else { CReplyToCommand(client, "\x07%s[entWatch] \x07%sConfig load failed!", "E01B5D", "F16767"); return Plugin_Handled; } } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnMapStart() { g_bLoaded = LoadConfig(); g_bLoadPending = false; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- stock bool LoadConfig() { g_hArray_Items.Clear(); g_hArray_Configs.Clear(); char sCurrentMap[128]; GetCurrentMap(sCurrentMap, sizeof(sCurrentMap)); String_ToLower(sCurrentMap, sCurrentMap, sizeof(sCurrentMap)); char sFilePathDefault[PLATFORM_MAX_PATH]; char sFilePathOverride[PLATFORM_MAX_PATH]; BuildPath(Path_SM, sFilePathDefault, sizeof(sFilePathDefault), "configs/entwatch/%s.cfg", sCurrentMap); BuildPath(Path_SM, sFilePathOverride, sizeof(sFilePathOverride), "configs/entwatch/%s.override.cfg", sCurrentMap); KeyValues hConfig = new KeyValues("items"); if (FileExists(sFilePathOverride)) { if (!hConfig.ImportFromFile(sFilePathOverride)) { LogMessage("Unable to load config \"%s\"!", sFilePathOverride); delete hConfig; return false; } else LogMessage("Loaded config \"%s\"", sFilePathOverride); } else { if (!hConfig.ImportFromFile(sFilePathDefault)) { LogMessage("Unable to load config \"%s\"!", sFilePathDefault); delete hConfig; return false; } else LogMessage("Loaded config \"%s\"", sFilePathDefault); } if (hConfig.GotoFirstSubKey()) { int iConfigID; do { CConfig config = new CConfig(); char sName[64], sShort[64], sColor[64], sFilter[64]; hConfig.GetString("name", sName, sizeof(sName)); hConfig.GetString("short", sShort, sizeof(sShort)); hConfig.GetString("color", sColor, sizeof(sColor)); hConfig.GetString("filter", sFilter, sizeof(sFilter)); config.SetName(sName); config.SetShort(sShort); config.SetColor(sColor); config.SetFilter(sFilter); config.iConfigID = iConfigID++; config.iWeaponID = hConfig.GetNum("weaponid"); config.iButtonID = hConfig.GetNum("buttonid"); config.iTriggerID = hConfig.GetNum("triggerid"); config.iDisplay = hConfig.GetNum("display"); config.iSlot = hConfig.GetNum("slot"); config.iMode = hConfig.GetNum("mode"); config.iMaxUses = hConfig.GetNum("maxuses"); config.iCooldown = hConfig.GetNum("cooldown"); g_hArray_Configs.Push(config); } while (hConfig.GotoNextKey()); } if (g_bLate) { int entity = INVALID_ENT_REFERENCE; while ((entity = FindEntityByClassname(entity, "*")) != INVALID_ENT_REFERENCE) { char sClassname[64]; if(GetEntityClassname(entity, sClassname, sizeof(sClassname))) OnEntitySpawned(entity, sClassname); } } delete hConfig; return true; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnRoundStart(Event hEvent, const char[] sEvent, bool bDontBroadcast) { if (g_bLoadPending) { g_bLoaded = LoadConfig(); if (g_bLoaded) { CPrintToChatAll("\x07%s[entWatch] \x07%sPending config load successfull.", "E01B5D", "F16767"); } } g_bLoadPending = false; g_bIntermission = false; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnRoundEnd(Event hEvent, const char[] sEvent, bool bDontBroadcast) { if (g_hArray_Items.Length) g_hArray_Items.Clear(); g_bIntermission = true; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnEntitySpawned(int entity, const char[] classname) { if (Entity_IsValid(entity) && g_hArray_Configs.Length) { int iHammerID = Entity_GetHammerID(entity); for (int index; index < g_hArray_Configs.Length; index++) { CConfig config = g_hArray_Configs.Get(index); if (config.iWeaponID && config.iWeaponID == iHammerID) { if (!RegisterExistingItem(config, entity, REGISTER_WEAPON)) { CItem item = new CItem(config); if (RegisterItemEntity(item, entity, REGISTER_WEAPON)) { g_hArray_Items.Push(item); SortADTArrayCustom(g_hArray_Items, SortItemsArray); } } } else if (config.iButtonID && config.iButtonID == iHammerID) { if (!RegisterExistingItem(config, entity, REGISTER_BUTTON)) { CItem item = new CItem(config); if (RegisterItemEntity(item, entity, REGISTER_BUTTON)) { g_hArray_Items.Push(item); SortADTArrayCustom(g_hArray_Items, SortItemsArray); } } } else if (config.iTriggerID && config.iTriggerID == iHammerID) { if (!RegisterExistingItem(config, entity, REGISTER_TRIGGER)) { CItem item = new CItem(config); if (RegisterItemEntity(item, entity, REGISTER_TRIGGER)) { g_hArray_Items.Push(item); SortADTArrayCustom(g_hArray_Items, SortItemsArray); } } } } } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- stock bool RegisterExistingItem(CConfig config, int entity, int type) { if (Entity_IsValid(entity) && g_hArray_Items.Length) { for (int index; index < g_hArray_Items.Length; index++) { CItem item = g_hArray_Items.Get(index); if (item.dConfig == config) { if (RegisterItemEntity(item, entity, type)) return true; } } } return false; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- stock bool RegisterItemEntity(CItem item, int entity, int type) { if (Entity_IsValid(entity)) { int iOwner = Entity_GetOwner(entity); int iParent = Entity_GetParent(entity); switch(type) { case REGISTER_WEAPON: { if (!item.bWeapon && (iOwner == INVALID_ENT_REFERENCE)) { item.iWeapon = entity; return true; } } case REGISTER_BUTTON: { if (!item.bButton && (iParent == INVALID_ENT_REFERENCE || (item.bWeapon && iParent == item.iWeapon))) { SDKHook(entity, SDKHook_Use, OnButtonPress); item.iButton = entity; return true; } } case REGISTER_TRIGGER: { if (!item.bTrigger && (iParent == INVALID_ENT_REFERENCE || (item.bWeapon && iParent == item.iWeapon))) { SDKHook(entity, SDKHook_StartTouch, OnTriggerTouch); SDKHook(entity, SDKHook_EndTouch, OnTriggerTouch); SDKHook(entity, SDKHook_Touch, OnTriggerTouch); item.iTrigger = entity; return true; } } } } return false; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnEntityDestroyed(int entity) { if (Entity_IsValid(entity) && g_hArray_Items.Length) { for (int index; index < g_hArray_Items.Length; index++) { CItem item = g_hArray_Items.Get(index); if (item.bWeapon && item.iWeapon == entity) { item.iClient = INVALID_ENT_REFERENCE; item.iWeapon = INVALID_ENT_REFERENCE; return; } else if (item.bButton && item.iButton == entity) { item.iButton = INVALID_ENT_REFERENCE; return; } else if (item.bTrigger && item.iTrigger == entity) { item.iTrigger = INVALID_ENT_REFERENCE; return; } } } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public int SortItemsArray(int index1, int index2, Handle array, Handle hndl) { CConfig config1 = view_as(g_hArray_Items.Get(index1)).dConfig; CConfig config2 = view_as(g_hArray_Items.Get(index2)).dConfig; if (config1.iConfigID < config2.iConfigID) return -1; if (config1.iConfigID > config2.iConfigID) return 1; return 0; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnClientPutInServer(int client) { if (!IsFakeClient(client)) { SDKHook(client, SDKHook_WeaponEquipPost, OnWeaponPickup); SDKHook(client, SDKHook_WeaponDropPost, OnWeaponDrop); SDKHook(client, SDKHook_WeaponCanUse, OnWeaponTouch); } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnClientDisconnect(int client) { if (!IsFakeClient(client) && g_hArray_Items.Length) { for (int index; index < g_hArray_Items.Length; index++) { CItem item = g_hArray_Items.Get(index); if (item.bClient && item.iClient == client) { if (item.bWeapon && !(item.dConfig.iSlot == SLOT_NONE || item.dConfig.iSlot == SLOT_KNIFE)) { SDKHooks_DropWeapon(item.iClient, item.iWeapon, NULL_VECTOR, NULL_VECTOR); } item.iClient = INVALID_ENT_REFERENCE; Call_StartForward(g_hFwd_OnClientItemDisconnect); Call_PushCell(client); Call_PushCell(index); Call_Finish(); } } } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public void OnClientDeath(Event hEvent, const char[] sEvent, bool bDontBroadcast) { int client = GetClientOfUserId(hEvent.GetInt("userid")); if (Client_IsValid(client) && !IsFakeClient(client) && g_hArray_Items.Length) { for (int index; index < g_hArray_Items.Length; index++) { CItem item = g_hArray_Items.Get(index); if (item.bClient && item.iClient == client) { if (item.bWeapon && !(item.dConfig.iSlot == SLOT_NONE || item.dConfig.iSlot == SLOT_KNIFE)) { SDKHooks_DropWeapon(item.iClient, item.iWeapon, NULL_VECTOR, NULL_VECTOR); } item.iClient = INVALID_ENT_REFERENCE; Call_StartForward(g_hFwd_OnClientItemDeath); Call_PushCell(client); Call_PushCell(index); Call_Finish(); } } } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Action OnWeaponPickup(int client, int weapon) { if (Client_IsValid(client) && Entity_IsValid(weapon) && g_hArray_Items.Length) { for (int index; index < g_hArray_Items.Length; index++) { CItem item = g_hArray_Items.Get(index); if (item.bWeapon && item.iWeapon == weapon) { item.iClient = client; Call_StartForward(g_hFwd_OnClientItemPickup); Call_PushCell(client); Call_PushCell(index); Call_Finish(); return; } } } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Action OnWeaponDrop(int client, int weapon) { if (Client_IsValid(client) && Entity_IsValid(weapon) && g_hArray_Items.Length) { for (int index; index < g_hArray_Items.Length; index++) { CItem item = g_hArray_Items.Get(index); if (item.bWeapon && item.iWeapon == weapon) { item.iClient = INVALID_ENT_REFERENCE; Call_StartForward(g_hFwd_OnClientItemDrop); Call_PushCell(client); Call_PushCell(index); Call_Finish(); return; } } } } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Action OnButtonPress(int button, int client) { if (Client_IsValid(client) && Entity_IsValid(button) && g_hArray_Items.Length) { if (HasEntProp(button, Prop_Data, "m_bLocked") && GetEntProp(button, Prop_Data, "m_bLocked")) return Plugin_Handled; for (int index; index < g_hArray_Items.Length; index++) { CItem item = g_hArray_Items.Get(index); if ((item.bButton && item.iButton == button) && (item.bClient && item.iClient == client)) { Action aResult; Call_StartForward(g_hFwd_OnClientItemCanActivate); Call_PushCell(client); Call_PushCell(index); Call_Finish(aResult); switch(aResult) { case Plugin_Continue, Plugin_Changed: { if (HasEntProp(button, Prop_Data, "m_flWait")) { if (item.flWait < GetEngineTime()) { item.flWait = GetEngineTime() + GetEntPropFloat(button, Prop_Data, "m_flWait"); } else return Plugin_Handled; } switch(item.dConfig.iMode) { case MODE_COOLDOWN: { if (item.iTimeReady < RoundToCeil(GetEngineTime())) { item.iTimeReady = RoundToCeil(GetEngineTime()) + item.dConfig.iCooldown; } else return Plugin_Handled; } case MODE_MAXUSES: { if (item.iTimesUsed < item.dConfig.iMaxUses) { item.iTimesUsed++; } else return Plugin_Handled; } case MODE_COOLDOWNMAXUSES: { if (item.iTimeReady < RoundToCeil(GetEngineTime()) && item.iTimesUsed < item.dConfig.iMaxUses) { item.iTimeReady = RoundToCeil(GetEngineTime()) + item.dConfig.iCooldown; item.iTimesUsed++; } else return Plugin_Handled; } case MODE_COOLDOWNCHARGES: { if (item.iTimeReady < RoundToCeil(GetEngineTime())) { item.iTimesUsed++; if (item.iTimesUsed >= item.dConfig.iMaxUses) { item.iTimeReady = RoundToCeil(GetEngineTime()) + item.dConfig.iCooldown; item.iTimesUsed = 0; } } else return Plugin_Handled; } } char sFilter[64]; if (item.dConfig.GetFilter(sFilter, sizeof(sFilter)) && sFilter[0]) Entity_SetName(client, sFilter); Call_StartForward(g_hFwd_OnClientItemActivate); Call_PushCell(client); Call_PushCell(index); Call_Finish(); } } return aResult; } } } return Plugin_Handled; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Action OnTriggerTouch(int trigger, int client) { if (Client_IsValid(client) && Entity_IsValid(trigger) && g_hArray_Items.Length) { for (int index; index < g_hArray_Items.Length; index++) { CItem item = g_hArray_Items.Get(index); if (item.bTrigger && item.iTrigger == trigger) { if (g_bIntermission) return Plugin_Handled; Action aResult; Call_StartForward(g_hFwd_OnClientItemCanPickup); Call_PushCell(client); Call_PushCell(index); Call_Finish(aResult); return aResult; } } } return Plugin_Handled; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public Action OnWeaponTouch(int client, int weapon) { if (Client_IsValid(client) && Entity_IsValid(weapon) && g_hArray_Items.Length) { for (int index; index < g_hArray_Items.Length; index++) { CItem item = g_hArray_Items.Get(index); if (item.bWeapon && item.iWeapon == weapon) { if (g_bIntermission) return Plugin_Handled; Action aResult; Call_StartForward(g_hFwd_OnClientItemCanPickup); Call_PushCell(client); Call_PushCell(index); Call_Finish(aResult); return aResult; } } } return Plugin_Continue; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public int Native_GetItemCount(Handle hPlugin, int numParams) { return g_hArray_Items.Length; } //---------------------------------------------------------------------------------------------------- // Purpose: //---------------------------------------------------------------------------------------------------- public int Native_GetItemData(Handle hPlugin, int numParams) { int index = GetNativeCell(1); if ((index < 0) || (index > g_hArray_Items.Length)) { return ThrowNativeError(SP_ERROR_INDEX, "Item index %d is invalid.", index); } return view_as(g_hArray_Items.Get(index)); }