diff --git a/scripting/L4D2Tools.sp b/scripting/L4D2Tools.sp index f3dfcf3..5125faa 100644 --- a/scripting/L4D2Tools.sp +++ b/scripting/L4D2Tools.sp @@ -22,17 +22,6 @@ char PRECACHE_SOUNDS[PRECACHE_SOUNDS_COUNT][] = { #include #include "l4d_survivor_identity_fix.inc" -char ReserveLevels[4][] = { - "Public", "Watch", "Admin-Only", "Private" -}; -enum ReserveMode { - Reserve_None = 0, - Reserve_Watch, - Reserve_AdminOnly, - Reserve_Private -} - - char MODELS[8][] = { "models/survivors/survivor_gambler.mdl", "models/survivors/survivor_producer.mdl", @@ -58,7 +47,6 @@ enum L4DModelId { static ArrayList LasersUsed; static ConVar hLaserNotice, hFinaleTimer, hFFNotice, hPingDropThres, hForceSurvivorSet, hPlayerLimit, hSVMaxPlayers, hHideMotd, hGamemode; static int iFinaleStartTime, botDropMeleeWeapon[MAXPLAYERS+1], iHighPingCount[MAXPLAYERS+1]; -ReserveMode reserveMode; static bool isHighPingIdle[MAXPLAYERS+1], isL4D1Survivors; static Handle hGoAwayFromKeyboard; static StringMap SteamIDs; @@ -114,7 +102,6 @@ public void OnPluginStart() { hSVMaxPlayers.IntValue = hPlayerLimit.IntValue; } - hFFNotice.AddChangeHook(CVC_FFNotice); if(hFFNotice.IntValue > 0) { HookEvent("player_hurt", Event_PlayerHurt); @@ -160,9 +147,6 @@ public void OnPluginStart() { RegAdminCmd("sm_playsound", Command_PlaySound, ADMFLAG_KICK, "Plays a gamesound for player"); RegAdminCmd("sm_stopsound", Command_StopSound, ADMFLAG_GENERIC, "Stops the last played gamesound for player"); RegAdminCmd("sm_swap", Command_SwapPlayer, ADMFLAG_KICK, "Swarms two player's locations"); - RegAdminCmd("sm_perm", Command_SetServerPermissions, ADMFLAG_KICK, "Sets the server's permissions."); - RegAdminCmd("sm_perms", Command_SetServerPermissions, ADMFLAG_KICK, "Sets the server's permissions."); - RegAdminCmd("sm_permissions", Command_SetServerPermissions, ADMFLAG_KICK, "Sets the server's permissions."); RegConsoleCmd("sm_pmodels", Command_ListClientModels, "Lists all player's models"); RegAdminCmd("sm_skipoutro", Command_SkipOutro, ADMFLAG_KICK, "Skips the outro"); @@ -179,82 +163,6 @@ void Event_PlayerLimitChange(ConVar cvar, const char[] oldValue, const char[] ne } } - -public void OnClientConnected(int client) { - if(!IsFakeClient(client) && reserveMode == Reserve_Watch) { - PrintChatToAdmins("%N is connecting", client); - } -} - -// Returns -1 if not allowed, or their previous index -int GetAllowedPlayerIndex(const char[] authid2) { - int index; - return SteamIDs.GetValue(authid2, index) ? index : -1; -} - - -public void OnClientPostAdminCheck(int client) { - if(!IsFakeClient(client)) { - if(reserveMode == Reserve_AdminOnly && GetUserAdmin(client) == INVALID_ADMIN_ID) { - char auth[32]; - GetClientAuthId(client, AuthId_Steam2, auth, sizeof(auth)); - if(GetAllowedPlayerIndex(auth) == -1) { - KickClient(client, "Sorry, server is reserved"); - return; - } - } - } -} - -public void OnClientAuthorized(int client, const char[] auth) { - if(IsFakeClient(client)) return; - if(reserveMode == Reserve_Private) { - if(GetAllowedPlayerIndex(auth) == -1) { - KickClient(client, "Sorry, server is reserved"); - } - } - // Don't insert id here if admin only, let admin check do that - if(reserveMode != Reserve_AdminOnly) { - SteamIDs.SetValue(auth, client); - } -} - -Action Command_SetServerPermissions(int client, int args) { - if(args > 0) { - char arg1[32]; - GetCmdArg(1, arg1, sizeof(arg1)); - if(StrEqual(arg1, "public", false)) { - reserveMode = Reserve_None; - } else if(StrContains(arg1, "noti", false) > -1 || StrContains(arg1, "watch", false) > -1) { - reserveMode = Reserve_Watch; - } else if(StrContains(arg1, "admin", false) > -1) { - reserveMode = Reserve_AdminOnly; - for(int i = 1; i <= MaxClients; i++) { - if(IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i)) { - GetClientAuthId(i, AuthId_Steam2, arg1, sizeof(arg1)); - SteamIDs.SetValue(arg1, i); - } - } - } else if(StrEqual(arg1, "private", false)) { - reserveMode = Reserve_Private; - for(int i = 1; i <= MaxClients; i++) { - if(IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i)) { - GetClientAuthId(i, AuthId_Steam2, arg1, sizeof(arg1)); - SteamIDs.SetValue(arg1, i); - } - } - } else { - ReplyToCommand(client, "Usage: sm_reserve [public/notify/admin/private] or no arguments to view current reservation."); - return Plugin_Handled; - } - PrintChatToAdmins("Server access changed to %s", ReserveLevels[reserveMode]); - } else { - ReplyToCommand(client, "Server access level is currently %s", ReserveLevels[reserveMode]); - } - return Plugin_Handled; -} - - Action Timer_CheckPlayerPings(Handle timer) { if(StrEqual(gamemode, "hideandseek")) return Plugin_Continue; if(hPingDropThres.IntValue != 0) { diff --git a/scripting/include/epi/director.sp b/scripting/include/epi/director.sp index a3e836e..99b22b0 100644 --- a/scripting/include/epi/director.sp +++ b/scripting/include/epi/director.sp @@ -106,7 +106,7 @@ void Director_OnMapEnd() { } void Cvar_SpecialSpawningChange(ConVar convar, const char[] oldValue, const char[] newValue) { - if(convar.IntValue & 2 && IsEPIActive()) { + if(convar.IntValue & 2) { if(witchSpawnTimer == null) witchSpawnTimer = CreateTimer(DIRECTOR_WITCH_CHECK_TIME, Timer_DirectorWitch, _, TIMER_REPEAT); } else { @@ -165,6 +165,8 @@ void OnTankBotSpawn(int client) { if(g_finaleStage == Stage_Active) { // 1st tank spawned PrintDebug(DEBUG_SPAWNLOGIC, "OnTankBotSpawn: [FINALE] 1st tank spawned"); + int health = CalculateExtraTankHealth(client); + SetEntProp(client, Prop_Send, "m_iHealth", health); g_finaleStage = Stage_FirstTankSpawned; return; } else if(g_realSurvivorCount < 6 && g_finaleStage == Stage_FirstTankSpawned) { @@ -173,6 +175,8 @@ void OnTankBotSpawn(int client) { float duration = GetRandomFloat(EXTRA_TANK_MIN_SEC, EXTRA_TANK_MAX_SEC); // Pass it 0, which doesnt make it a split tank, has default health CreateTimer(duration, Timer_SpawnSplitTank, 0); + int health = CalculateExtraTankHealth(client); + SetEntProp(client, Prop_Send, "m_iHealth", health); g_finaleStage = Stage_SecondTankSpawned; return; } @@ -186,9 +190,7 @@ void OnTankBotSpawn(int client) { } // This should not run on active finales (different than finale maps, such as swamp fever's, where finale isnt full map) // Normal tank (not stage 2 / not secondary tank) spawned. Set its health and spawn split tank - int health = GetEntProp(client, Prop_Send, "m_iHealth"); - float additionalHealth = float(g_survivorCount - 4) * cvEPITankHealth.FloatValue; - health += RoundFloat(additionalHealth); + int health = CalculateExtraTankHealth(client); /* Split tank can only spawn if: (1) not finale @@ -207,7 +209,13 @@ void OnTankBotSpawn(int client) { PrintDebug(DEBUG_SPAWNLOGIC, "OnTankBotSpawn: Setting tank health to %d", health); SetEntProp(client, Prop_Send, "m_iHealth", health); } - +} + +int CalculateExtraTankHealth(int client) { + int health = GetEntProp(client, Prop_Send, "m_iHealth"); + float additionalHealth = float(g_survivorCount - 4) * cvEPITankHealth.FloatValue; + health += RoundFloat(additionalHealth); + return health; } Action Timer_SpawnSplitTank(Handle h, int health) { @@ -283,6 +291,9 @@ void InitExtraWitches() { void Director_PrintDebug(int client) { PrintToConsole(client, "State: %s(%d)", DIRECTOR_STATE[g_lastState], g_lastState); + float eCount = float(g_survivorCount - 3); + float chance = (eCount - float(g_infectedCount)) / eCount; + PrintToConsole(client, "Player Scale Chance: %f%%", chance * 100.0); PrintToConsole(client, "Map Bounds: [%f, %f]", FLOW_CUTOFF, L4D2Direct_GetMapMaxFlowDistance() - (FLOW_CUTOFF*2.0)); PrintToConsole(client, "Total Witches Spawned: %d | Target: %d", g_spawnCount[Special_Witch], g_extraWitchCount); for(int i = 0; i < g_extraWitchCount && i < DIRECTOR_WITCH_MAX_WITCHES; i++) { @@ -435,6 +446,7 @@ Action Timer_Director(Handle h) { Action Timer_DirectorWitch(Handle h) { // TODO: instead of +1, do it when director spawned a witch + if(!IsEPIActive()) return Plugin_Continue; if(g_spawnCount[Special_Witch] < g_extraWitchCount + 1) { //&& time - g_lastSpawnTimes.witch > DIRECTOR_WITCH_MIN_TIME for(int i = 0; i <= g_extraWitchCount; i++) { if(g_extraWitchFlowPositions[i] > 0.0 && g_highestFlowAchieved >= g_extraWitchFlowPositions[i]) { @@ -443,11 +455,12 @@ Action Timer_DirectorWitch(Handle h) { int target = L4D_GetHighestFlowSurvivor(); if(!target) return Plugin_Continue; DirectorSpawn(Special_Witch, target); - break; + return Plugin_Continue; } } } - return Plugin_Continue; + witchSpawnTimer = null; + return Plugin_Stop; } // UTIL functions diff --git a/scripting/include/gamemodes/ents.inc b/scripting/include/gamemodes/ents.inc index 81b7c31..ea99bc9 100644 --- a/scripting/include/gamemodes/ents.inc +++ b/scripting/include/gamemodes/ents.inc @@ -145,19 +145,19 @@ void OnPortalTouch(const char[] output, int caller, int activator, float delay) #endif } -stock int StartPropCreate(const char[] entClass, const char[] model, const float pos[3], const float ang[3]) { +stock int StartPropCreate(const char[] entClass, const char[] model, const float pos[3], const float ang[3] = NULL_VECTOR, const float vel[3] = NULL_VECTOR) { int entity = CreateEntityByName(entClass); if(entity == -1) return -1; DispatchKeyValue(entity, "model", model); DispatchKeyValue(entity, "solid", "6"); DispatchKeyValue(entity, "targetname", ENT_PROP_NAME); DispatchKeyValue(entity, "disableshadows", "1"); - TeleportEntity(entity, pos, ang, NULL_VECTOR); + TeleportEntity(entity, pos, ang, vel); return entity; } -stock int CreateProp(const char[] entClass, const char[] model, const float pos[3], const float ang[3]) { - int entity = StartPropCreate(entClass, model, pos, ang); +stock int CreateProp(const char[] entClass, const char[] model, const float pos[3], const float ang[3] = NULL_VECTOR, const float vel[3] = NULL_VECTOR) { + int entity = StartPropCreate(entClass, model, pos, ang, vel); if(DispatchSpawn(entity)) { #if defined DEBUG_LOG_MAPSTART PrintToServer("spawn prop %.1f %.1f %.1f model %s", pos[0], pos[1], pos[2], model[7]); diff --git a/scripting/include/hats/hats.sp b/scripting/include/hats/hats.sp index 2e4fadc..615fe98 100644 --- a/scripting/include/hats/hats.sp +++ b/scripting/include/hats/hats.sp @@ -377,7 +377,10 @@ Action Command_DoAHat(int client, int args) { PrintToConsole(client, "[Hats] Selected a child entity, selecting parent (child %d -> parent %d)", entity, parent); entity = parent; } else if(entity <= MaxClients) { // Checks for hatting a player entity - if(GetClientTeam(entity) != 2 && ~cvar_sm_hats_flags.IntValue & view_as(HatConfig_InfectedHats)) { + if(IsFakeClient(entity)) { + PrintToChat(client, "[Hats] Cannot hat bots"); + return Plugin_Handled; + } else if(GetClientTeam(entity) != 2 && ~cvar_sm_hats_flags.IntValue & view_as(HatConfig_InfectedHats)) { PrintToChat(client, "[Hats] Cannot make enemy a hat... it's dangerous"); return Plugin_Handled; } else if(entity == EntRefToEntIndex(WallBuilder[client].entity)) { diff --git a/scripting/l4d2_TKStopper.sp b/scripting/l4d2_TKStopper.sp index bc3a51d..72b9ed6 100644 --- a/scripting/l4d2_TKStopper.sp +++ b/scripting/l4d2_TKStopper.sp @@ -340,7 +340,7 @@ Action Event_OnTakeDamage(int victim, int& attacker, int& inflictor, float& dam else if(pData[victim].underAttack) return Plugin_Continue; // Is damage not caused by fire or pipebombs? - bool isDamageDirect = true; //(damagetype & DMG_BURN) == 0; + bool isDamageDirect = (~damagetype & DMG_BURN) != 0; // Forgive player teamkill based on threshold, resetting accumlated damage if(time - pData[attacker].lastFFTime > hForgivenessTime.IntValue) { @@ -587,10 +587,10 @@ Action Command_IgnorePlayer(int client, int args) { if (flags & Immune_TK) { if (pData[target].immunityFlags & Immune_TK) { LogAction(client, target, "\"%L\" re-enabled teamkiller detection for \"%L\"", client, target); - CShowActivity2(client, "[FTT] ", "{yellow}%N has re-enabled teamkiller detection for {olive}%N", client, target); + CShowActivity2(client, "[FTT] ", "{yellow}%N{default} has re-enabled teamkiller detection for {olive}%N", client, target); } else { LogAction(client, target, "\"%L\" ignored teamkiller detection for \"%L\"", client, target); - CShowActivity2(client, "[FTT] ", "{yellow}%N has ignored teamkiller detection for {olive}%N", client, target); + CShowActivity2(client, "[FTT] ", "{yellow}%N{default} has ignored teamkiller detection for {olive}%N", client, target); } pData[target].immunityFlags ^= Immune_TK; } @@ -598,9 +598,10 @@ Action Command_IgnorePlayer(int client, int args) { if (flags & Immune_RFF) { if (pData[target].immunityFlags & Immune_RFF) { LogAction(client, target, "\"%L\" re-enabled auto reverse friendly-fire for \"%L\"", client, target); + CShowActivity2(client, "[FTT] ", "{yellow}%N{default} has enabled auto reverse friendly-fire for {olive}%N", client, target); } else { LogAction(client, target, "\"%L\" disabled auto reverse friendly-fire for \"%L\"", client, target); - CShowActivity2(client, "[FTT] ", "{yellow}%N has disabled auto reverse friendly-fire for {olive}%N", client, target); + CShowActivity2(client, "[FTT] ", "{yellow}%N{default} has disabled auto reverse friendly-fire for {olive}%N", client, target); pData[target].autoRFFScaleFactor = 0.0; } pData[target].immunityFlags ^= Immune_RFF; diff --git a/scripting/l4d2_extraplayeritems.sp b/scripting/l4d2_extraplayeritems.sp index 596a2dd..ba1339d 100644 --- a/scripting/l4d2_extraplayeritems.sp +++ b/scripting/l4d2_extraplayeritems.sp @@ -305,7 +305,7 @@ public void OnPluginStart() { hEPIHudState = CreateConVar("epi_hudstate", "1", "Controls when the hud displays.\n0 -> OFF, 1 = When 5+ players, 2 = ALWAYS", FCVAR_NONE, true, 0.0, true, 3.0); hExtraFinaleTank = CreateConVar("epi_extra_tanks", "3", "Add bits together. 0 = Normal tank spawning, 1 = 50% tank split on non-finale (half health), 2 = Tank split (full health) on finale ", FCVAR_NONE, true, 0.0, true, 3.0); hExtraTankThreshold = CreateConVar("epi_extra_tanks_min_players", "6", "The minimum number of players for extra tanks to spawn. When disabled, normal 5+ tank health applies", FCVAR_NONE, true, 0.0); - hSplitTankChance = CreateConVar("epi_splittank_chance", "0.75", "The % chance of a split tank occurring in non-finales", FCVAR_NONE, true, 0.0, true, 1.0); + hSplitTankChance = CreateConVar("epi_splittank_chance", "0.65", "The % chance of a split tank occurring in non-finales", FCVAR_NONE, true, 0.0, true, 1.0); cvDropDisconnectTime = CreateConVar("epi_disconnect_time", "120.0", "The amount of seconds after a player has actually disconnected, where their character slot will be void. 0 to disable", FCVAR_NONE, true, 0.0); cvFFDecreaseRate = CreateConVar("epi_ff_decrease_rate", "0.3", "The friendly fire factor is subtracted from the formula (playerCount-4) * this rate. Effectively reduces ff penalty when more players. 0.0 to subtract none", FCVAR_NONE, true, 0.0); cvEPIHudFlags = CreateConVar("epi_hud_flags", "3", "Add together.\n1 = Scrolling hud, 2 = Show ping", FCVAR_NONE, true, 0.0); @@ -1181,20 +1181,36 @@ int SpawnItem(const char[] itemName, float pos[3], float ang[3] = NULL_VECTOR) { return spawner; } -void IncreaseKits() { +void IncreaseKits(bool inFinale) { float pos[3]; int entity = FindEntityByClassname(-1, "weapon_first_aid_kit_spawn"); if(entity == INVALID_ENT_REFERENCE) { - PrintToServer("[EPI] Warn: No kit spawns (weapon_first_aid_kit_spawn) found"); + PrintToServer("[EPI] Warn: No kit spawns (weapon_first_aid_kit_spawn) found (inFinale=%b)", inFinale); return; } int count = 0; while(g_extraKitsAmount > 0) { GetEntPropVector(entity, Prop_Data, "m_vecOrigin", pos); - if(L4D_IsPositionInLastCheckpoint(pos)) { + bool result = false; + if(inFinale) { + // Finale + Address address = L4D_GetNearestNavArea(pos); + if(address != Address_Null) { + int attributes = L4D_GetNavArea_SpawnAttributes(address); + if(attributes & NAV_SPAWN_FINALE) { + result = true; + } + } + } else { + // Checkpoint + result = L4D_IsPositionInLastCheckpoint(pos); + } + if(result) { count++; // Give it a little chance to nudge itself - pos[2] += 0.3; + pos[0] += GetRandomFloat(-8.0, 8.0); + pos[1] += GetRandomFloat(-8.0, 8.0); + pos[2] += 0.4; SpawnItem("first_aid_kit", pos); g_extraKitsAmount--; } @@ -1204,41 +1220,13 @@ void IncreaseKits() { entity = -1; // If we did not find any suitable kits, stop here. if(count == 0) { + PrintToServer("[EPI] Warn: No valid kit spawns (weapon_first_aid_kit_spawn) found (inFinale=%b)", inFinale); break; } } } } -void IncreaseFinaleKits() { - float pos[3]; - int entity = -1; - int spawnCount = g_survivorCount - 4; - int count = 0; - PrintDebug(DEBUG_SPAWNLOGIC, "Spawning %d finale kits", spawnCount); - while(spawnCount > 0) { - GetEntPropVector(entity, Prop_Data, "m_vecOrigin", pos); - Address address = L4D_GetNearestNavArea(pos); - if(address != Address_Null) { - int attributes = L4D_GetNavArea_SpawnAttributes(address); - if(attributes & NAV_SPAWN_FINALE) { - count++; - pos[2] += 0.3; - SpawnItem("first_aid_kit", pos); - spawnCount--; - } - } - entity = FindEntityByClassname(entity, "weapon_first_aid_kit_spawn"); - // Loop around - if(entity == INVALID_ENT_REFERENCE) { - entity = -1; - // If we did not find any suitable kits, stop here. - if(count == 0) { - break; - } - } - } -} char NAV_SPAWN_NAMES[32][] = { "EMPTY", @@ -1303,7 +1291,7 @@ public void OnMapStart() { } if(L4D_IsMissionFinalMap()) { - IncreaseFinaleKits(); + IncreaseKits(true); // Disable tank split on hard rain finale g_extraFinaleTankEnabled = true; if(StrEqual(map, "c4m5_milltown_escape")) { @@ -1394,7 +1382,7 @@ public void EntityOutput_OnStartTouchSaferoom(const char[] output, int caller, i UpdateSurvivorCount(); if(IsEPIActive()) { SetExtraKits(g_survivorCount); - IncreaseKits(); + IncreaseKits(false); PrintToServer("[EPI] Player entered saferoom. Extra Kits: %d", g_extraKitsAmount); } } diff --git a/scripting/l4d2_turret.sp b/scripting/l4d2_turret.sp index 5701ae5..15c082f 100644 --- a/scripting/l4d2_turret.sp +++ b/scripting/l4d2_turret.sp @@ -413,9 +413,10 @@ public void OnClientDisconnect(int client) { } public Action OnTakeDamageAlive(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) { + // TODO: see if DMG_ENERGYBEAM if(attacker > MaxClients && attacker < 2048 && turretIsActiveLaser[attacker] && GetClientTeam(victim) != 3) { int health = L4D_GetPlayerTempHealth(victim); - L4D_SetPlayerTempHealth(victim, health); + L4D_SetPlayerTempHealth(victim, health + 1.0); damage = 0.0; return Plugin_Stop; } diff --git a/scripting/l4d_anti_rush.sp b/scripting/l4d_anti_rush.sp index 868070b..a3c64a8 100644 --- a/scripting/l4d_anti_rush.sp +++ b/scripting/l4d_anti_rush.sp @@ -140,7 +140,7 @@ float g_fBenchAvg; float g_iBenchTicks; #endif -#define CVAR_FLAGS FCVAR_NOTIFY +#define CVAR_FLAGS FCVAR_NONE #define MINIMUM_RANGE 1500.0 // Minimum range for last and lead cvars. #define EVENTS_CONFIG "data/l4d_anti_rush.cfg"