#pragma semicolon 1 #pragma newdecls required #define DEBUG #define PLUGIN_VERSION "1.0" #include #include #include bool bLasersUsed[2048]; ConVar hLaserNotice, hFinaleTimer, hFFNotice, hMPGamemode; int iFinaleStartTime; int botDropMeleeWeapon[MAXPLAYERS+1]; //TODO: Remove the Plugin_Stop on pickup, and give item back instead. keep reference to dropped weapon to delete. public Plugin myinfo = { name = "L4D2 Misc Tools", author = "Includes: Notice on laser use, Timer for gauntlet runs", description = "jackzmc", version = PLUGIN_VERSION, url = "" }; public void OnPluginStart() { EngineVersion g_Game = GetEngineVersion(); if(g_Game != Engine_Left4Dead && g_Game != Engine_Left4Dead2) { SetFailState("This plugin is for L4D/L4D2 only."); } hLaserNotice = CreateConVar("sm_laser_use_notice", "1.0", "Enable notification of a laser box being used", FCVAR_NONE, true, 0.0, true, 1.0); hFinaleTimer = CreateConVar("sm_time_finale", "0.0", "Record the time it takes to complete finale. 0 -> OFF, 1 -> Gauntlets Only, 2 -> All finales", FCVAR_NONE, true, 0.0, true, 2.0); hFFNotice = CreateConVar("sm_ff_notice", "0.0", "Notify players if a FF occurs. 0 -> Disabled, 1 -> In chat, 2 -> In Hint text", FCVAR_NONE, true, 0.0, true, 2.0); hMPGamemode = FindConVar("mp_gamemode"); HookEvent("player_use", Event_PlayerUse); HookEvent("player_hurt", Event_PlayerHurt); HookEvent("round_end", Event_RoundEnd); HookEvent("gauntlet_finale_start", Event_GauntletStart); HookEvent("finale_start", Event_FinaleStart); HookEvent("finale_vehicle_leaving", Event_FinaleEnd); HookEvent("player_entered_checkpoint", Event_EnterSaferoom); HookEvent("player_bot_replace", Event_BotPlayerSwap); HookEvent("bot_player_replace", Event_BotPlayerSwap); AutoExecConfig(true, "l4d2_tools"); for(int client = 1; client < MaxClients; client++) { if(IsClientConnected(client) && IsClientInGame(client) && IsFakeClient(client) && GetClientTeam(client) == 2) { SDKHook(client, SDKHook_WeaponDrop, Event_OnWeaponDrop); } } //RegAdminCmd("sm_respawn", Command_SpawnSpecial, ADMFLAG_CHEATS, "Respawn a dead survivor right where they died."); } public Action Event_BotPlayerSwap(Event event, const char[] name, bool dontBroadcast) { int bot = GetClientOfUserId(event.GetInt("bot")); if(StrEqual(name, "player_bot_replace")) { //Bot replaced player SDKHook(bot, SDKHook_WeaponDrop, Event_OnWeaponDrop); }else{ //Player replaced a bot int client = GetClientOfUserId(event.GetInt("player")); if(botDropMeleeWeapon[bot] > 0) { //todo: int meleeOwnerEnt = GetEntPropEnt(botDropMeleeWeapon[bot], Prop_Send, "m_hOwnerEntity"); if(meleeOwnerEnt == -1) { EquipPlayerWeapon(client, botDropMeleeWeapon[bot]); botDropMeleeWeapon[bot] = -1; }else{ PrintToChatAll("client %N cannot equip", client); PrintToConsole(client, "Could not give back your melee weapon, %N has it instead.", meleeOwnerEnt); } } SDKUnhook(bot, SDKHook_WeaponDrop, Event_OnWeaponDrop); } } public void OnClientDisconnect(int client) { botDropMeleeWeapon[client] = -1; } public Action Event_OnWeaponDrop(int client, int weapon) { char wpn[32]; GetEdictClassname(weapon, wpn, sizeof(wpn)); if(StrEqual(wpn, "weapon_melee") && GetEntProp(client, Prop_Send, "m_humanSpectatorUserID") > 0) { botDropMeleeWeapon[client] = weapon; } return Plugin_Continue; } public void Event_EnterSaferoom(Event event, const char[] name, bool dontBroadcast) { char currentGamemode[16]; hMPGamemode.GetString(currentGamemode, sizeof(currentGamemode)); if(StrEqual(currentGamemode, "tankrun", false)) { int user = GetClientOfUserId(event.GetInt("userid")); if(!IsFakeClient(user)) { CreateTimer(1.0, Timer_TPBots, user); } } } public Action Timer_TPBots(Handle timer, any user) { float pos[3]; GetClientAbsOrigin(user, pos); for(int i = 1; i < MaxClients; i++) { if(IsClientInGame(i) && IsFakeClient(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) { TeleportEntity(i, pos, NULL_VECTOR, NULL_VECTOR); } } } //laserNotice public void Event_PlayerHurt(Event event, const char[] name, bool dontBroadcast) { if(hFFNotice.IntValue > 0) { int victim = GetClientOfUserId(event.GetInt("userid")); int attacker = GetClientOfUserId(event.GetInt("attacker")); int dmg = event.GetInt("dmg_health"); if(dmg > 0) { if(attacker > 0 && !IsFakeClient(attacker) && attacker != victim) { if(GetClientTeam(attacker) == 2 && GetClientTeam(victim) == 2) { if(hFFNotice.IntValue == 1) { PrintHintTextToAll("%N has done %d HP of friendly fire damage to %N", attacker, dmg, victim); }else{ PrintToChatAll("%N has done %d HP of friendly fire damage to %N", attacker, dmg, victim); } } } } } } public void Event_PlayerUse(Event event, const char[] name, bool dontBroadcast) { if(hLaserNotice.BoolValue) { char player_name[32]; char entity_name[64]; int player_id = GetClientOfUserId(event.GetInt("userid")); int target_id = event.GetInt("targetid"); GetClientName(player_id, player_name, sizeof(player_name)); GetEntityClassname(target_id, entity_name, sizeof(entity_name)); if(StrEqual(entity_name,"upgrade_laser_sight")) { if(!bLasersUsed[target_id]) { bLasersUsed[target_id] = true; PrintToChatAll("%s picked up laser sights",player_name); } } } } public void Event_RoundEnd(Event event, const char[] name, bool dontBroadcast) { for (int i = 1; i < sizeof(bLasersUsed) ;i++) { bLasersUsed[i] = false; } } //finaletimer public void Event_GauntletStart(Event event, const char[] name, bool dontBroadcast) { if(hFinaleTimer.IntValue > 0) { iFinaleStartTime = GetTime(); } } public void Event_FinaleStart(Event event, const char[] name, bool dontBroadcast) { if(hFinaleTimer.IntValue == 2) { iFinaleStartTime = GetTime(); } } public void Event_FinaleEnd(Event event, const char[] name, bool dontBroadcast) { if(hFinaleTimer.IntValue != 0) { if(iFinaleStartTime != 0) { int difference = GetTime() - iFinaleStartTime; char time[32]; FormatSeconds(difference, time, sizeof(time)); PrintToChatAll("Finale took %s to complete", time); iFinaleStartTime = 0; } } } public void Event_CarAlarmTriggered(Event event, const char[] name, bool dontBroadcast) { int userID = GetClientOfUserId(event.GetInt("userid")); PrintToChatAll("%N activated a car alarm!", userID); } /** * Prints human readable duration from milliseconds * * @param ms The duration in milliseconds * @param str The char array to use for text * @param strSize The size of the string */ stock void FormatSeconds(int raw_sec, char[] str, int strSize) { int hours = raw_sec / 3600; int minutes = (raw_sec -(3600*hours))/60; int seconds = (raw_sec -(3600*hours)-(minutes*60)); if(hours >= 1) { Format(str, strSize, "%d hours, %d.%d minutes", hours, minutes, seconds); }else if(minutes >= 1) { Format(str, strSize, "%d minutes and %d seconds", minutes, seconds); }else { Format(str, strSize, "%d seconds", seconds); } } stock void ShowDelayedHintToAll(const char[] format, any ...) { char buffer[254]; VFormat(buffer, sizeof(buffer), format, 2); static int hintInt = 0; if(hintInt >= 10) { PrintHintTextToAll("%s",buffer); hintInt = 0; } hintInt++; } stock void ShowDelayedHint(int client, const char[] format, any ...) { char buffer[254]; VFormat(buffer, sizeof(buffer), format, 2); static int hintInt = 0; if(hintInt >= 10) { PrintHintText(client, "%s",buffer); hintInt = 0; } hintInt++; } stock void CheatCommand(int client, const char[] command, const char[] argument1, const char[] argument2) { int userFlags = GetUserFlagBits(client); SetUserFlagBits(client, ADMFLAG_ROOT); int flags = GetCommandFlags(command); SetCommandFlags(command, flags & ~FCVAR_CHEAT); FakeClientCommand(client, "%s %s %s", command, argument1, argument2); SetCommandFlags(command, flags); SetUserFlagBits(client, userFlags); } stock int GetAnyValidClient() { for (int i = 1; i <= MaxClients; i++) { if (IsClientInGame(i) && !IsFakeClient(i)) { return i; } } return -1; }