diff --git a/plugins/globalbans.smx b/plugins/globalbans.smx index 7adbc75..f63fb42 100644 Binary files a/plugins/globalbans.smx and b/plugins/globalbans.smx differ diff --git a/plugins/l4d2_TKStopper.smx b/plugins/l4d2_TKStopper.smx index 1eea255..1648067 100644 Binary files a/plugins/l4d2_TKStopper.smx and b/plugins/l4d2_TKStopper.smx differ diff --git a/plugins/l4d2_ai_minigun.smx b/plugins/l4d2_ai_minigun.smx index 6478760..0b84af1 100644 Binary files a/plugins/l4d2_ai_minigun.smx and b/plugins/l4d2_ai_minigun.smx differ diff --git a/plugins/l4d2_autorestart.smx b/plugins/l4d2_autorestart.smx index 3e03396..887d4ce 100644 Binary files a/plugins/l4d2_autorestart.smx and b/plugins/l4d2_autorestart.smx differ diff --git a/plugins/l4d2_detections.smx b/plugins/l4d2_detections.smx new file mode 100644 index 0000000..d8f3d74 Binary files /dev/null and b/plugins/l4d2_detections.smx differ diff --git a/plugins/l4d2_extraplayeritems.smx b/plugins/l4d2_extraplayeritems.smx index c0b3940..cf77a5c 100644 Binary files a/plugins/l4d2_extraplayeritems.smx and b/plugins/l4d2_extraplayeritems.smx differ diff --git a/plugins/l4d2_population_control.smx b/plugins/l4d2_population_control.smx index 0b16bba..d5a8904 100644 Binary files a/plugins/l4d2_population_control.smx and b/plugins/l4d2_population_control.smx differ diff --git a/plugins/l4d2_sb_fix.smx b/plugins/l4d2_sb_fix.smx index aec5ec9..1e76ef4 100644 Binary files a/plugins/l4d2_sb_fix.smx and b/plugins/l4d2_sb_fix.smx differ diff --git a/plugins/l4d2_vocalize_control.smx b/plugins/l4d2_vocalize_control.smx index f6bf586..a5717ca 100644 Binary files a/plugins/l4d2_vocalize_control.smx and b/plugins/l4d2_vocalize_control.smx differ diff --git a/scripting/globalbans.sp b/scripting/globalbans.sp index 9c7c38a..edf46bb 100644 --- a/scripting/globalbans.sp +++ b/scripting/globalbans.sp @@ -62,7 +62,7 @@ public void OnClientAuthorized(int client, const char[] auth) { if(!StrEqual(auth, "BOT", true)) { static char query[256], ip[32]; GetClientIP(client, ip, sizeof(ip)); - Format(query, sizeof(query), "SELECT `reason`, `steamid`, `expired` FROM `bans` WHERE `steamid` = '%s' OR ip = '?'", auth, ip); + Format(query, sizeof(query), "SELECT `reason`, `steamid`, `expired` FROM `bans` WHERE `steamid` = 'STEAM_%:%:%s' OR ip = '?'", auth[10], ip); g_db.Query(DB_OnConnectCheck, query, GetClientUserId(client), DBPrio_High); } } @@ -174,6 +174,7 @@ public void DB_OnConnectCheck(Database db, DBResultSet results, const char[] err KickClient(client, "You have been banned from this server."); } else { PrintChatToAdmins("%N was banned from this server for: \"%s\"", client, reason); + return; } static char query[128]; g_db.Format(query, sizeof(query), "UPDATE bans SET times_tried=times_tried+1 WHERE steamid = '%s'", steamid); diff --git a/scripting/include/jutils.inc b/scripting/include/jutils.inc index 8b96e86..dead838 100644 --- a/scripting/include/jutils.inc +++ b/scripting/include/jutils.inc @@ -274,8 +274,15 @@ stock bool SpawnMinigun(const float vPos[3], const float vAng[3]) { } } +stock int GiveClientWeaponLasers(int client, const char[] wpnName) { + int entity = GiveClientWeapon(client, wpnName); + if(entity != -1) { + SetEntProp(entity, Prop_Send, "m_upgradeBitVec", 4); + } + return entity; +} -stock bool GiveClientWeapon(int client, const char[] wpnName, bool lasers) { +stock int GiveClientWeapon(int client, const char[] wpnName) { static char sTemp[64]; float pos[3]; GetClientAbsOrigin(client, pos); @@ -286,12 +293,10 @@ stock bool GiveClientWeapon(int client, const char[] wpnName, bool lasers) { DispatchSpawn(entity); TeleportEntity(entity, pos, NULL_VECTOR, NULL_VECTOR); - if(lasers) SetEntProp(entity, Prop_Send, "m_upgradeBitVec", 4); - EquipPlayerWeapon(client, entity); - return true; + return entity; }else{ - return false; + return -1; } } stock int GetNearestEntity(int client, char[] classname) @@ -589,6 +594,12 @@ stock void StringToLower(char[] str) { str[i] = CharToLower(str[i]); } } +stock void StringToUpper(char[] str) { + int len = strlen(str); + for(int i = 0; i < len; i++) { + str[i] = CharToUpper(str[i]); + } +} stock int GetRealClient(int client) { if(IsFakeClient(client)) { diff --git a/scripting/l4d2_TKStopper.sp b/scripting/l4d2_TKStopper.sp index 88ab759..877b85b 100644 --- a/scripting/l4d2_TKStopper.sp +++ b/scripting/l4d2_TKStopper.sp @@ -19,7 +19,9 @@ int iJoinTime[MAXPLAYERS+1], iIdleStartTime[MAXPLAYERS+1], iJumpAttempts[MAXPLAY float playerTotalDamageFF[MAXPLAYERS+1]; int lastFF[MAXPLAYERS+1]; -ConVar hForgivenessTime, hBanTime, hThreshold, hJoinTime, hTKAction, hSuicideAction, hSuicideLimit; +float autoFFScaleFactor[MAXPLAYERS+1]; + +ConVar hForgivenessTime, hBanTime, hThreshold, hJoinTime, hTKAction, hSuicideAction, hSuicideLimit, hFFAutoScaleAmount, hFFAutoScaleForgivenessAmount, hFFAutoScaleMaxRatio, hFFAutoScaleIgnoreAdmins; public Plugin myinfo = { @@ -51,7 +53,11 @@ public void OnPluginStart() hTKAction = CreateConVar("l4d2_tk_action", "3", "How should the TK be punished?\n0 = No action (No message), 1 = Kick, 2 = Instant Ban, 3 = Ban on disconnect", FCVAR_NONE, true, 0.0, true, 3.0); hSuicideAction = CreateConVar("l4d2_suicide_action", "3", "How should a suicider be punished?\n0 = No action (No message), 1 = Kick, 2 = Instant Ban, 3 = Ban on disconnect", FCVAR_NONE, true, 0.0, true, 3.0); hSuicideLimit = CreateConVar("l4d2_suicide_limit", "1", "How many attempts does a new joined player have until action is taken for suiciding?", FCVAR_NONE, true, 0.0); - + + hFFAutoScaleAmount = CreateConVar("l4d2_tk_auto_ff_rate", "0.04", "The rate at which auto reverse-ff is scaled by.", FCVAR_NONE, true, 0.0); + hFFAutoScaleMaxRatio = CreateConVar("l4d2_tk_auto_ff_max_ratio", "5.0", "The maximum amount that the reverse ff can go. 0.0 for unlimited", FCVAR_NONE, true, 0.0); + hFFAutoScaleForgivenessAmount = CreateConVar("l4d2_tk_auto_ff_forgive_rate", "0.008", "This amount times amount of minutes since last ff is removed from ff rate", FCVAR_NONE, true, 0.0); + hFFAutoScaleIgnoreAdmins = CreateConVar("l4d2_tk_auto_ff_ignore_admins", "1", "Should automatic reverse ff ignore admins? 0 = Admins are subjected\n1 = Admins are excempt", FCVAR_NONE, true, 0.0, true, 1.0); //AutoExecConfig(true, "l4d2_tkstopper"); @@ -78,6 +84,8 @@ public void OnPluginStart() RegAdminCmd("sm_ignore", Command_IgnorePlayer, ADMFLAG_KICK, "Makes a player immune for any anti trolling detection for a session"); + RegAdminCmd("sm_tkinfo", Command_TKInfo, ADMFLAG_KICK, "Debug info for TKSTopper"); + if(lateLoaded) { for(int i = 1; i <= MaxClients; i++) { if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2) { @@ -85,8 +93,18 @@ public void OnPluginStart() } } } + // CreateTimer(60.0, Timer_Forgive, _, TIMER_REPEAT); } +/*public Action Timer_Forgive(Handle h) { + for(int i = 1; i <= MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && ) { + + } + } + return Plugin_Continue; +}*/ + /////////////////////////////////////////////////////////////////////////////// // Special Infected Events /////////////////////////////////////////////////////////////////////////////// @@ -173,6 +191,7 @@ public void OnMapEnd() { public void OnClientPutInServer(int client) { iJoinTime[client] = GetTime(); + lastFF[client] = GetTime(); SDKHook(client, SDKHook_OnTakeDamage, Event_OnTakeDamage); } @@ -191,21 +210,32 @@ public void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroa BanClient(client, hBanTime.IntValue, BANFLAG_AUTO | BANFLAG_AUTHID, "Excessive FF", "Excessive Friendly Fire", "TKStopper"); } isPlayerTroll[client] = false; + autoFFScaleFactor[client] = 0.0; } public Action Event_OnTakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype, int& weapon, float damageForce[3], float damagePosition[3]) { if(damage > 0.0 && victim <= MaxClients && attacker <= MaxClients && attacker > 0 && victim > 0) { - if(GetUserAdmin(attacker) != INVALID_ADMIN_ID || isImmune[attacker] || IsFakeClient(attacker)) return Plugin_Continue; + if(damagetype & DMG_BURN && IsFakeClient(attacker)) { + damage = 0.0; + return Plugin_Changed; + } + bool isAdmin = GetUserAdmin(attacker) != INVALID_ADMIN_ID; + bool ignore = hFFAutoScaleIgnoreAdmins.BoolValue && isAdmin; + if(isImmune[attacker] || IsFakeClient(attacker)) return Plugin_Continue; if(GetClientTeam(victim) != 2 || GetClientTeam(attacker) != 2 || attacker == victim) return Plugin_Continue; //Allow friendly firing BOTS that aren't idle players: //if(IsFakeClient(victim) && !HasEntProp(attacker, Prop_Send, "m_humanSpectatorUserID") || GetEntProp(attacker, Prop_Send, "m_humanSpectatorUserID") == 0) return Plugin_Continue; + + // Stop all damage early if already marked as troll if(isPlayerTroll[attacker]) return Plugin_Stop; + // Allow vanilla-damage if being attacked by special (example, charger carry) if(isUnderAttack[victim]) return Plugin_Continue; + // Is damage not caused by fire or pipebombs? bool isDamageDirect = damagetype & (DMG_BLAST|DMG_BURN|DMG_BLAST_SURFACE) == 0; int time = GetTime(); // If is a fall within first 2 minutes, do appropiate action - if(damagetype & DMG_FALL && attacker == victim && damage > 0.0 && time- iJoinTime[victim] <= hJoinTime.IntValue * 60000) { + if(!isAdmin && damagetype & DMG_FALL && attacker == victim && damage > 0.0 && time - iJoinTime[victim] <= hJoinTime.IntValue * 60) { iJumpAttempts[victim]++; float pos[3]; GetNearestPlayerPosition(victim, pos); @@ -232,10 +262,28 @@ public Action Event_OnTakeDamage(int victim, int& attacker, int& inflictor, flo playerTotalDamageFF[attacker] = 0.0; } playerTotalDamageFF[attacker] += damage; + + // Auto reverse ff logic lastFF[attacker] = time; + if(isDamageDirect && !ignore) { + // Decrement any recovered FF + float minutesSinceLastFF = (time - lastFF[attacker]) / 60.0; + autoFFScaleFactor[attacker] -= minutesSinceLastFF * hFFAutoScaleForgivenessAmount.FloatValue; + if(autoFFScaleFactor[attacker] < 0.0) { + autoFFScaleFactor[attacker] = 0.0; + } + // Then increment + autoFFScaleFactor[attacker] += hFFAutoScaleAmount.FloatValue * damage; + if(hFFAutoScaleMaxRatio.FloatValue > 0.0 && autoFFScaleFactor[attacker] > hFFAutoScaleMaxRatio.FloatValue) { + autoFFScaleFactor[attacker] = hFFAutoScaleMaxRatio.FloatValue; + } + if(minutesSinceLastFF > 3.0) { + PrintToConsoleAdmins("%N new reverse ratio: %f", attacker, autoFFScaleFactor[attacker]); + } + } - // Check for friendly fire damage - if(playerTotalDamageFF[attacker] > hThreshold.IntValue && !IsFinaleEnding && isDamageDirect) { + // Check for excessive friendly fire damage in short timespan + if(!isAdmin && playerTotalDamageFF[attacker] > hThreshold.IntValue && !IsFinaleEnding && isDamageDirect) { LogAction(-1, attacker, "Excessive FF (%.2f HP)", playerTotalDamageFF[attacker]); if(hTKAction.IntValue == 1) { LogMessage("[NOTICE] Kicking %N for excessive FF (%.2f HP) for %d minutes.", attacker, playerTotalDamageFF[attacker], hBanTime.IntValue); @@ -255,19 +303,19 @@ public Action Event_OnTakeDamage(int victim, int& attacker, int& inflictor, flo } // Modify damages based on criteria - if(iJumpAttempts[victim] > 0 || L4D_IsInFirstCheckpoint(victim) || L4D_IsInLastCheckpoint(victim) || time - iJoinTime[attacker] <= hJoinTime.IntValue * 60000) { + if(iJumpAttempts[victim] > 0 || L4D_IsInFirstCheckpoint(victim) || L4D_IsInLastCheckpoint(victim) || time - iJoinTime[attacker] <= hJoinTime.IntValue * 60) { // If the amount of MS is <= join time threshold * 60000 ms then cancel // Or if the player is in a saferoom // Or if the player tried to suicide jump damage = 0.0; return Plugin_Handled; }else if(IsFinaleEnding) { + if(isAdmin) return Plugin_Continue; SDKHooks_TakeDamage(attacker, attacker, attacker, damage * 2.0); damage = 0.0; return Plugin_Changed; }else if(!isDamageDirect) { // Ignore fire and propane damage, mistakes can happen - // Make the victim take slightly less, attacker more, to in event of 1-1 victim wins - SDKHooks_TakeDamage(attacker, attacker, attacker, damage / 1.9); + SDKHooks_TakeDamage(attacker, attacker, attacker, float(RoundToCeil(autoFFScaleFactor[attacker] * damage))); damage /= 2.1; return Plugin_Changed; } @@ -275,6 +323,20 @@ public Action Event_OnTakeDamage(int victim, int& attacker, int& inflictor, flo return Plugin_Continue; } +public Action Command_TKInfo(int client, int args) { + int time = GetTime(); + for(int i = 1; i <= MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i)) { + float minutesSinceLastFF = (time - lastFF[i]) / 60.0; + float activeRate = autoFFScaleFactor[i] - (minutesSinceLastFF * hFFAutoScaleForgivenessAmount.FloatValue); + if(activeRate < 0.0) { + activeRate = 0.0; + } + ReplyToCommand(client, "%N: %f TK-FF buffer | %f (active: %f), reverse FF rate | %f ff min ago | %d suicide jumps", i, playerTotalDamageFF[i], autoFFScaleFactor[i], activeRate, minutesSinceLastFF, iJumpAttempts[i]); + } + } + return Plugin_Handled; +} public Action Command_IgnorePlayer(int client, int args) { char arg1[32]; GetCmdArg(1, arg1, sizeof(arg1)); @@ -284,15 +346,15 @@ public Action Command_IgnorePlayer(int client, int args) { bool tn_is_ml; if ((target_count = ProcessTargetString( - arg1, - client, - target_list, - MaxClients, - COMMAND_FILTER_ALIVE, - target_name, - sizeof(target_name), - tn_is_ml)) <= 0) - { + arg1, + client, + target_list, + MaxClients, + COMMAND_FILTER_ALIVE, + target_name, + sizeof(target_name), + tn_is_ml)) <= 0 + ) { ReplyToTargetError(client, target_count); return Plugin_Handled; } @@ -338,7 +400,7 @@ stock bool GetNearestPlayerPosition(int client, float pos[3]) { stock void PrintChatToAdmins(const char[] format, any ...) { char buffer[254]; VFormat(buffer, sizeof(buffer), format, 2); - for(int i = 1; i < MaxClients; i++) { + for(int i = 1; i <= MaxClients; i++) { if(IsClientConnected(i) && IsClientInGame(i)) { AdminId admin = GetUserAdmin(i); if(admin != INVALID_ADMIN_ID) { @@ -352,7 +414,7 @@ stock void PrintChatToAdmins(const char[] format, any ...) { stock void PrintToConsoleAdmins(const char[] format, any ...) { char buffer[254]; VFormat(buffer, sizeof(buffer), format, 2); - for(int i = 1; i < MaxClients; i++) { + for(int i = 1; i <= MaxClients; i++) { if(IsClientConnected(i) && IsClientInGame(i)) { AdminId admin = GetUserAdmin(i); if(admin != INVALID_ADMIN_ID) { diff --git a/scripting/l4d2_autorestart.sp b/scripting/l4d2_autorestart.sp index 5f8ee8e..a080544 100644 --- a/scripting/l4d2_autorestart.sp +++ b/scripting/l4d2_autorestart.sp @@ -54,7 +54,7 @@ public Action Timer_Check(Handle h) { } else if(GetTime() - startupTime > MAX_TIME_ONLINE_MS) { LogAction(0, -1, "Server has passed max online time threshold, will restart if remains empty"); if(IsServerEmpty()) { - if(++triesEmpty > 3) { + if(++triesEmpty > 4) { LogAction(0, -1, "Server has passed max online time threshold and is empty after %d tries, restarting now", triesEmpty); ServerCommand("quit"); } @@ -86,10 +86,8 @@ bool IsServerEmptyWithOnlyBots() { //Returns true if there is a bot connected and there is no real players bool IsServerEmpty() { for(int i = 1; i <= MaxClients; i++) { - if(IsClientConnected(i) && IsClientInGame(i)) { - if(!IsFakeClient(i)) - return false; - + if(IsClientConnected(i) && !IsFakeClient(i)) { + return false; } } return true; diff --git a/scripting/l4d2_detections.sp b/scripting/l4d2_detections.sp new file mode 100644 index 0000000..0943847 --- /dev/null +++ b/scripting/l4d2_detections.sp @@ -0,0 +1,218 @@ +#pragma semicolon 1 +#pragma newdecls required + +//#define DEBUG + +#define PLUGIN_VERSION "1.0" +#define BILE_NO_HORDE_THRESHOLD 20 +#define DOOR_CLOSE_THRESHOLD 5000.0 + +#include +#include +#include +#include +//#include + +enum struct PlayerDetections { + int kitPickupsSaferoom; + int saferoomLastOpen; + int saferoomOpenCount; + + void Reset() { + this.kitPickupsSaferoom = 0; + this.saferoomLastOpen = 0; + this.saferoomOpenCount = 0; + } + +} + +/* +Bile Detections: +1. No commons around entowner or bile +2. Bile already exists +3. Player is currently vomitted on (check time?) +4. Bile on tank (common count near tank) +*/ + +stock bool IsPlayerBoomed(int client) { + return GetEntPropFloat(%0, Prop_Send, "m_vomitStart") + 20.1 > GetGameTime(); +} +stock bool IsAnyPlayerBoomed() { + for(int i = 1; i <= MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerBoomed(i)) { + return true; + } + } + return false; +} + +stock bool AnyRecentBileInPlay(int ignore) { + return false; +} + +stock int GetEntityCountNear(const float[3] srcPos, float radius = 50000.0) { + float pos[3]; + int count; + int entity = -1; + while( (entity = FindEntityByClassname(entity, "infected")) != INVALID_ENT_REFERENCE ) { + GetEntPropVector(entity, Prop_Send, "m_vecOrigin", pos); + if(GetEntProp(entity, Prop_Send, "m_clientLookatTarget") != -1 && GetVectorDistance(pos, srcPos) <= radius) { + count++; + } + } + return count; +} +stock int L4D_SpawnCommonInfected2(const float vPos[3], const float vAng[3] = { 0.0, 0.0, 0.0 }) +{ + int entity = CreateEntityByName("infected"); + if( entity != -1 ) + { + DispatchSpawn(entity); + TeleportEntity(entity, vPos, vAng, NULL_VECTOR); + } + + return entity; +} + +PlayerDetections[MAXPLAYERS+1] detections; + +GlobalForward fwd_PlayerDoubleKit, fwd_NoHordeBileWaste, fwd_DoorFaceCloser, fwd_CheckpointDoorFaceCloser; + +public Plugin myinfo = +{ + name = "L4D2 Detections", + author = "jackzmc", + description = "", + 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."); + } + + fwd_PlayerDoubleKit = new GlobalForward("OnDoubleKit", ET_Hook, Param_Cell); + fwd_NoHordeBileWaste = new GlobalForward("OnNoHordeBileWaste", ET_Event, Param_Cell, Param_Cell); + fwd_DoorFaceCloser = new GlobalForward("OnDoorCloseInFace", ET_Hook, Param_Cell); + fwd_CheckpointDoorFaceCloser = new GlobalForward("OnDoorCloseInFaceSaferoom", ET_Hook, Param_Cell, Param_Cell); + + HookEvent("item_pickup", Event_ItemPickup); + HookEvent("door_close", Event_DoorClose); +} + +// Called on map changes too, we want this: +public void OnClientDisconnect(int client) { + detections[client].Reset(); +} + +public Action Event_ItemPickup(Event event, const char[] name, bool dontBroadcast) { + int client = GetClientOfUserId(event.GetInt("userid")); + if(client && L4D_IsInLastCheckpoint(client)) { + static char itmName[32]; + event.GetString("item", itmName, sizeof(itmName)); + if(StrEqual(itmName, "first_aid_kit")) { + if(++detections[client].kitPickupsSaferoom == 2) { + InternalDebugLog("DOUBLE_KIT", client); + Call_StartForward(fwd_PlayerDoubleKit); + Call_PushCell(client); + Call_Finish(); + } + } + } +} + +public Action Event_DoorClose(Event event, const char[] name, bool dontBroadcast) { + int client = GetClientOfUserId(event.GetInt("userid")); + if(fwd_DoorFaceCloser.FunctionCount > 0 && client) { + bool isCheckpoint = event.GetBool("checkpoint"); + DataPack pack = GetNearestClient(client); + pack.Reset(); + int victim = pack.ReadCell(); + float dist = pack.ReadFloat(); + if(victim) { + if(dist < DOOR_CLOSE_THRESHOLD) { + if(isCheckpoint) { + if(detections[client].saferoomLastOpen > 0 && GetTime() - detections[client].saferoomLastOpen > 30000) { + detections[client].saferoomLastOpen = 0; + detections[client].saferoomOpenCount = 0; + } + Call_StartForward(fwd_CheckpointDoorFaceCloser); + Call_PushCell(client); + Call_PushCell(victim); + Call_PushCell(++detections[client].saferoomOpenCount); + Call_Finish(); + detections[client].saferoomLastOpen = GetTime(); + PrintToServer("[Detections] DOOR_SAFEROOM: %N victim -> %N %d times", client, victim, detections[client].saferoomOpenCount); + //TODO: Find way to reset, timer? + } else { + Call_StartForward(fwd_DoorFaceCloser); + Call_PushCell(client); + Call_PushCell(victim); + Call_Finish(); + PrintToServer("[Detections] DOOR=: %N victim -> %N", client, victim); + } + } + } + } +} + +public void OnEntityDestroyed(int entity) { + static char classname[16]; + if(IsValidEntity(entity) && entity <= 4096) { + GetEntityClassname(entity, classname, sizeof(classname)); + if(StrEqual(classname, "vomitjar_projec")) { + int thrower = GetEntPropEnt(entity, Prop_Send, "m_hThrower"); + if(thrower > 0 && thrower <= MaxClients && IsClientConnected(thrower) && IsClientInGame(thrower)) { + static float src[3]; + float tmp[3]; + GetClientAbsOrigin(thrower, tmp); + // TODO: Get source when lands + GetEntPropVector(entity, Prop_Send, "m_vecOrigin", src); + + int commons = GetEntityCountNear(src, 50000.0); + PrintToConsoleAll("[Debug] Bile Thrown By %N, Commons: %d", thrower, commons); + if(commons < BILE_NO_HORDE_THRESHOLD) { + InternalDebugLog("BILE_NO_HORDE", thrower); + Action result; + Call_StartForward(fwd_NoHordeBileWaste); + Call_PushCell(thrower); + Call_PushCell(commons); + Call_Finish(result); + + if(result == Plugin_Stop) { + AcceptEntityInput(entity, "kill"); + GiveClientWeapon(thrower, "vomitjar"); + } + } + } + } + } +} + +// TODO: Door close + +void InternalDebugLog(const char[] name, int client) { + PrintToConsoleAll("[Detection] %s: Client %N", name, client); +} + +stock DataPack GetNearestClient(int client) { + int victim; + float pos[3], pos2[3], distance; + GetClientAbsOrigin(client, pos); + for(int i = 1; i <= MaxClients; i++) { + if(i != client && IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2) { + GetClientAbsOrigin(i, pos2); + float dist = GetVectorDistance(pos, pos2, false); + if(victim == 0 || dist < distance) { + distance = dist; + victim = i; + } + } + } + DataPack pack = new DataPack(); + pack.WriteCell(victim); + pack.WriteFloat(distance); + return pack; +} \ No newline at end of file diff --git a/scripting/l4d2_extraplayeritems.sp b/scripting/l4d2_extraplayeritems.sp index 11c38e9..30f4183 100644 --- a/scripting/l4d2_extraplayeritems.sp +++ b/scripting/l4d2_extraplayeritems.sp @@ -27,7 +27,7 @@ #define DEBUG_LEVEL DEBUG_GENERIC #define EXTRA_PLAYER_HUD_UPDATE_INTERVAL 0.8 //Sets abmExtraCount to this value if set -//#define DEBUG_FORCE_PLAYERS 5 +// #define DEBUG_FORCE_PLAYERS 5 #define PLUGIN_VERSION "1.0" @@ -269,19 +269,25 @@ public Action Command_RunExtraItems(int client, int args) { /// EVENTS //////////////////////////////////// -// 0 = inactive | 1 = started | 2 = first tank round started | 3 = waiting for tank spawn | # > 3: Health for next tank +#define FINALE_TANK 8 +#define FINALE_STARTED 1 +#define FINALE_RESCUE_READY 6 +#define FINALE_HORDE 7 +#define FINALE_WAIT 10 public Action L4D2_OnChangeFinaleStage(int &finaleType, const char[] arg) { - if(finaleType == 1 && abmExtraCount > 4 && hExtraFinaleTank.BoolValue) { + if(finaleType == FINALE_STARTED && abmExtraCount > 4 && hExtraFinaleTank.BoolValue) { finaleStage = 1; PrintToConsoleAll("[EPI] Finale started and over threshold"); - } else if(finaleType == 8) { + } else if(finaleType == FINALE_TANK) { if(finaleStage == 1) { finaleStage = 2; - PrintToConsoleAll("[EPI] First tank has spawned"); - } else { + PrintToConsoleAll("[EPI] First tank stage has started"); + } else if(finaleStage == 2) { finaleStage = 3; - PrintToConsoleAll("[EPI] Waiting for second tank to spawn"); + PrintToConsoleAll("[EPI] Second stage started, waiting for tank"); + } else { + PrintToConsoleAll("invalid"); } } return Plugin_Continue; @@ -291,23 +297,25 @@ public void Event_TankSpawn(Event event, const char[] name, bool dontBroadcast) int user = GetEventInt(event, "userid"); int tank = GetClientOfUserId(user); if(finaleStage == 3) { - PrintToConsoleAll("[EPI] Third tank spawned, setting health."); + PrintToConsoleAll("[EPI] Second tank spawned, setting health."); if(tank > 0 && IsFakeClient(tank)) { - RequestFrame(Frame_ExtraTankWait, user); + // Sets health in half, sets finaleStage to health + CreateTimer(5.0, Timer_SplitTank, user); } - finaleStage = 0; //Only set for a frame } else if(finaleStage > 3) { + PrintToConsoleAll("[EPI] Third & final tank spawned, setting health."); RequestFrame(Frame_SetExtraTankHealth, user); } } - -public void Frame_ExtraTankWait(int user) { +public Action Timer_SplitTank(Handle t, int user) { int tank = GetClientOfUserId(user); if(tank > 0) { // Half their HP, assign half to self and for next tank int hp = GetEntProp(tank, Prop_Send, "m_iHealth") / 2; SetEntProp(tank, Prop_Send, "m_iHealth", hp); finaleStage = hp; + // Then, summon the next tank + ServerCommand("sm_forcespecial tank"); } } @@ -362,7 +370,13 @@ public Action Event_PlayerFirstSpawn(Event event, const char[] name, bool dontBr } else { // New client has connected, not on first map. // TODO: Check if Timer_UpdateMinPlayers is needed, or if this works: - if(++abmExtraCount > 4) { + // Never decrease abmExtraCount + int newCount = GetRealSurvivorsCount(); + if(newCount > abmExtraCount) { + abmExtraCount = newCount; + } + // If 5 survivors, then set them up, TP them. + if(abmExtraCount > 4) { RequestFrame(Frame_SetupNewClient, client); } } @@ -427,8 +441,9 @@ public void Frame_SetupNewClient(int client) { EquipPlayerWeapon(client, item); } static float spawnPos[3]; - GetCenterPositionInSurvivorFlow(client, spawnPos); - TeleportEntity(client, spawnPos, NULL_VECTOR, NULL_VECTOR); + // TODO: Fix null + if(GetCenterPositionInSurvivorFlow(client, spawnPos)) + TeleportEntity(client, spawnPos, NULL_VECTOR, NULL_VECTOR); } public Action Timer_GiveClientKit(Handle hdl, int user) { int client = GetClientOfUserId(user); @@ -479,6 +494,7 @@ public void OnMapStart() { extraKitsStarted = extraKitsAmount; } } + if(!isLateLoaded) { isLateLoaded = false; } @@ -505,6 +521,7 @@ public void OnMapStart() { HookEntityOutput("trigger_changelevel", "OnStartTouch", EntityOutput_OnStartTouchSaferoom); playersLoadedIn = 0; + finaleStage = 0; } @@ -521,7 +538,6 @@ public void OnMapEnd() { } ammoPacks.Clear(); playersLoadedIn = 0; - L4D2_RunScript("ExtraPlayerHUD <- { Fields = { } }; HUDSetLayout(ExtraPlayerHud); HUDPlace( g_ModeScript.HUD_RIGHT_BOT, 0.72, 0.79, 0.25, 0.2 ); g_ModeScript"); } public void Event_RoundFreezeEnd(Event event, const char[] name, bool dontBroadcast) { @@ -577,7 +593,7 @@ public Action Event_MapTransition(Event event, const char[] name, bool dontBroad } //TODO: Possibly hacky logic of on third different ent id picked up, in short timespan, detect as set of 4 (pills, kits) & give extra public Action Event_Pickup(int client, int weapon) { - char name[32]; + static char name[32]; GetEntityClassname(weapon, name, sizeof(name)); if(StrEqual(name, "weapon_first_aid_kit", true)) { if(isBeingGivenKit[client]) return Plugin_Continue; @@ -1108,25 +1124,45 @@ stock void RunVScriptLong(const char[] sCode, any ...) { } // Gets a position (from a nav area) -stock void GetCenterPositionInSurvivorFlow(int target, float pos[3]) { +stock bool GetCenterPositionInSurvivorFlow(int target, float pos[3]) { + static float ang[3]; int client = GetHighestFlowSurvivor(target); - GetClientAbsOrigin(client, pos); - int nav = L4D_GetNearestNavArea(pos); - L4D_FindRandomSpot(nav, pos); + if(client > 0) { + GetClientAbsOrigin(client, pos); + GetClientAbsAngles(client, ang); + pos[2] = -pos[2]; + TR_TraceRayFilter(pos, ang, MASK_SHOT, RayType_Infinite, Filter_GroundOnly); + if(TR_DidHit()) { + TR_GetEndPosition(pos); + return true; + } else { + return false; + } + } + return false; +} + +bool Filter_GroundOnly(int entity, int mask) { + return entity == 0; } stock int GetLowestFlowSurvivor(int ignoreTarget = 0) { int client = L4D_GetHighestFlowSurvivor(); - float lowestFlow = L4D2Direct_GetFlowDistance(client); - for(int i = 1; i <= MaxClients; i++) { - if(ignoreTarget != i && IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) { - if(L4D2Direct_GetFlowDistance(i) < lowestFlow) { - client = i; - lowestFlow = L4D2Direct_GetFlowDistance(i); + if(client != ignoreTarget) { + return client; + } else { + client = -1; + float lowestFlow = L4D2Direct_GetFlowDistance(client); + for(int i = 1; i <= MaxClients; i++) { + if(ignoreTarget != i && IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) { + if(L4D2Direct_GetFlowDistance(i) < lowestFlow) { + client = i; + lowestFlow = L4D2Direct_GetFlowDistance(i); + } } } + return client; } - return client; } stock int GetHighestFlowSurvivor(int ignoreTarget = 0) { @@ -1134,6 +1170,7 @@ stock int GetHighestFlowSurvivor(int ignoreTarget = 0) { if(client != ignoreTarget) { return client; } else { + client = -1; float highestFlow = L4D2Direct_GetFlowDistance(client); for(int i = 1; i <= MaxClients; i++) { if(ignoreTarget != i && IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) { diff --git a/scripting/l4d2_sb_fix.sp b/scripting/l4d2_sb_fix.sp index 672a7f9..ed8f5b1 100644 --- a/scripting/l4d2_sb_fix.sp +++ b/scripting/l4d2_sb_fix.sp @@ -1,8 +1,10 @@ +#pragma newdecls required + #include #include #include -public Plugin:myinfo = +public Plugin myinfo = { name = "L4D2 Survivor Bot Fix", author = "DingbatFlat", @@ -232,13 +234,13 @@ bool TimerAlreadyWorking = false; bool bLateLoad = false; -public APLRes:AskPluginLoad2(Handle plugin, bool late, char[] error, errMax) +public APLRes AskPluginLoad2(Handle plugin, bool late, char[] error, int errMax) { bLateLoad = late; return APLRes_Success; } -public OnPluginStart() +public void OnPluginStart() { // Notes: // If "~_enabled" of the group is not set to 1, other Cvars in that group will not work. @@ -346,7 +348,7 @@ public OnPluginStart() HookConVarChange(sb_fix_select_character_name, SBSelectChangeConvar); if (bLateLoad) { - for (new x = 1; x <= MaxClients; x++) { + for (int x = 1; x <= MaxClients; x++) { if (x > 0 && x <= MaxClients && IsClientInGame(x)) { SDKHook(x, SDKHook_WeaponSwitch, WeaponSwitch); } @@ -374,7 +376,7 @@ public OnPluginStart() InitTimers(); // Safe Room Check } -public OnMapStart() +public void OnMapStart() { input_Help(); input_CI(); @@ -385,7 +387,7 @@ public OnMapStart() inputConfig(); } -public OnAllPluginsLoaded() +public void OnAllPluginsLoaded() { input_Help(); input_CI(); @@ -396,46 +398,46 @@ public OnAllPluginsLoaded() inputConfig(); } -public SBHelp_ChangeConvar(Handle:convar, const char[] oldValue, const char[] newValue) { input_Help(); } -public SBCI_ChangeConvar(Handle:convar, const char[] oldValue, const char[] newValue) { input_CI(); } -public SBSI_ChangeConvar(Handle:convar, const char[] oldValue, const char[] newValue) { input_SI(); } -public SBTank_ChangeConvar(Handle:convar, const char[] oldValue, const char[] newValue) { input_Tank(); } -public SBBash_ChangeConvar(Handle:convar, const char[] oldValue, const char[] newValue) { input_Bash(); } -public SBEnt_ChangeConvar(Handle:convar, const char[] oldValue, const char[] newValue) { input_Entity(); } +public void SBHelp_ChangeConvar(Handle convar, const char[] oldValue, const char[] intValue) { input_Help(); } +public void SBCI_ChangeConvar(Handle convar, const char[] oldValue, const char[] intValue) { input_CI(); } +public void SBSI_ChangeConvar(Handle convar, const char[] oldValue, const char[] intValue) { input_SI(); } +public void SBTank_ChangeConvar(Handle convar, const char[] oldValue, const char[] intValue) { input_Tank(); } +public void SBBash_ChangeConvar(Handle convar, const char[] oldValue, const char[] intValue) { input_Bash(); } +public void SBEnt_ChangeConvar(Handle convar, const char[] oldValue, const char[] intValue) { input_Entity(); } -public SBConfigChangeConvar(Handle:convar, const char[] oldValue, const char[] newValue) { inputConfig(); } +public void SBConfigChangeConvar(Handle convar, const char[] oldValue, const char[] intValue) { inputConfig(); } -public SBSelectChangeConvar(Handle:convar, const char[] oldValue, const char[] newValue) { SelectImprovedTarget(); } +public void SBSelectChangeConvar(Handle convar, const char[] oldValue, const char[] intValue) { SelectImprovedTarget(); } -input_Help() +void input_Help() { c_bHelp_Enabled = GetConVarBool(sb_fix_help_enabled); c_fHelp_Range = GetConVarInt(sb_fix_help_range) * 1.0; c_iHelp_ShoveType = GetConVarInt(sb_fix_help_shove_type); c_bHelp_ShoveOnlyReloading = GetConVarBool(sb_fix_help_shove_reloading); } -input_CI() +void input_CI() { c_bCI_Enabled = GetConVarBool(sb_fix_ci_enabled); c_fCI_Range = GetConVarInt(sb_fix_ci_range) * 1.0; c_bCI_MeleeEnabled = GetConVarBool(sb_fix_ci_melee_allow); c_fCI_MeleeRange = GetConVarInt(sb_fix_ci_melee_range) * 1.0; } -input_SI() +void input_SI() { c_bSI_Enabled = GetConVarBool(sb_fix_si_enabled); c_fSI_Range = GetConVarInt(sb_fix_si_range) * 1.0; c_bSI_IgnoreBoomer = GetConVarBool(sb_fix_si_ignore_boomer); c_fSI_IgnoreBoomerRange = GetConVarInt(sb_fix_si_ignore_boomer_range) * 1.0; } -input_Tank() +void input_Tank() { c_bTank_Enabled = GetConVarBool(sb_fix_tank_enabled); c_fTank_Range = GetConVarInt(sb_fix_tank_range) * 1.0; c_iSITank_PriorityType = GetConVarInt(sb_fix_si_tank_priority_type); } -input_Bash() +void input_Bash() { c_bBash_Enabled = GetConVarBool(sb_fix_bash_enabled); c_iBash_HunterChance = GetConVarInt(sb_fix_bash_hunter_chance); @@ -443,7 +445,7 @@ input_Bash() c_iBash_JockeyChance = GetConVarInt(sb_fix_bash_jockey_chance); c_fBash_JockeyRange = GetConVarInt(sb_fix_bash_jockey_range) * 1.0; } -input_Entity() +void input_Entity() { c_bRock_Enabled = GetConVarBool(sb_fix_rock_enabled); c_fRock_Range = GetConVarInt(sb_fix_rock_range) * 1.0; @@ -457,7 +459,7 @@ input_Entity() c_fWitch_Shotgun_Range_Min = GetConVarInt(sb_fix_witch_shotgun_range_min) * 1.0; } -inputConfig() +void inputConfig() { g_hEnabled = GetConVarBool(sb_fix_enabled); c_iSelectType = GetConVarInt(sb_fix_select_type); @@ -481,7 +483,7 @@ inputConfig() *= Round / Start Ready / Select Improved Targets *= ================================================================================================ */ -public Action:Event_RoundStart(Event event, const char[] name, bool dontBroadcast) +public Action Event_RoundStart(Event event, const char[] name, bool dontBroadcast) { for (int x = 1; x <= MAXPLAYERS; x++) g_bFixTarget[x] = false; // RESET @@ -496,17 +498,17 @@ public Action:Event_RoundStart(Event event, const char[] name, bool dontBroadcas InitTimers(); } -public Action:Event_BotAndPlayerReplace(Handle:event, const char[] name, bool:dontBroadcast) +public Action Event_BotAndPlayerReplace(Handle event, const char[] name, bool dontBroadcast) { if (!LeftSafeRoom) return; - new bot = GetClientOfUserId(GetEventInt(event, "bot")); + int bot = GetClientOfUserId(GetEventInt(event, "bot")); if (g_bFixTarget[bot]) { SelectImprovedTarget(); } } -InitTimers() +void InitTimers() { if (LeftSafeRoom) SelectImprovedTarget(); @@ -517,7 +519,7 @@ InitTimers() } } -public Action:Timer_PlayerLeftCheck(Handle:Timer) +public Action Timer_PlayerLeftCheck(Handle Timer) { if (LeftStartArea()) { @@ -536,10 +538,10 @@ public Action:Timer_PlayerLeftCheck(Handle:Timer) return Plugin_Continue; } -bool:LeftStartArea() +bool LeftStartArea() { - new ent = -1, maxents = GetMaxEntities(); - for (new i = MaxClients+1; i <= maxents; i++) + int ent = -1, maxents = GetMaxEntities(); + for (int i = MaxClients+1; i <= maxents; i++) { if (IsValidEntity(i)) { @@ -556,7 +558,7 @@ bool:LeftStartArea() if (ent > -1) { - new offset = FindSendPropInfo("CTerrorPlayerResource", "m_hasAnySurvivorLeftSafeArea"); + int offset = FindSendPropInfo("CTerrorPlayerResource", "m_hasAnySurvivorLeftSafeArea"); if (offset > 0) { if (GetEntData(ent, offset)) @@ -568,12 +570,12 @@ bool:LeftStartArea() return false; } -SelectImprovedTarget() +void SelectImprovedTarget() { if (!g_hEnabled || !LeftSafeRoom) return; // Select targets when left the safe area. else if (c_iSelectType == 1) { - new count; - for (new x = 1; x <= MaxClients; x++) { + int count; + for (int x = 1; x <= MaxClients; x++) { if (isSurvivorBot(x)) { g_bFixTarget[x] = true; count++ @@ -587,8 +589,8 @@ SelectImprovedTarget() static char sSelectName[256]; GetConVarString(sb_fix_select_character_name, sSelectName, sizeof(sSelectName)); - new count; - for (new x = 1; x <= MaxClients; x++) { + int count; + for (int x = 1; x <= MaxClients; x++) { if (isSurvivorBot(x)) { static char sName[128]; GetClientName(x, sName, sizeof(sName)); @@ -606,15 +608,15 @@ SelectImprovedTarget() } } -public Action:Timer_ShoveChance(Handle:Timer) +public Action Timer_ShoveChance(Handle Timer) { // ----------------------- Bash Chance ----------------------- if (c_iBash_HunterChance < 100 || c_iBash_JockeyChance < 100) { - for (new sb = 1; sb <= MaxClients; sb++) { + for (int sb = 1; sb <= MaxClients; sb++) { if (isSurvivorBot(sb) && IsPlayerAlive(sb)) { - for (new x = 1; x <= MaxClients; x++) { + for (int x = 1; x <= MaxClients; x++) { if (isInfected(x) && IsPlayerAlive(x)) { - new zombieClass = getZombieClass(x); + int zombieClass = getZombieClass(x); if (zombieClass == ZC_HUNTER) { if (GetRandomInt(0, 100) <= c_iBash_HunterChance) g_bShove[sb][x] = true; else g_bShove[sb][x] = false; @@ -650,14 +652,14 @@ public Action:Timer_ShoveChance(Handle:Timer) /* * OnPlayerRunCmd is Runs 30 times per second. (every 0.03333... seconds) */ -public Action:OnPlayerRunCmd(client, &buttons, &impulse, - Float:vel[3], Float:angles[3], &weapon) +public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, + float vel[3], float angles[3], int &weapon) { if(GetTickInterval() < 0.03333) return Plugin_Continue; //Stop running on lag if (g_hEnabled) { if (isSurvivorBot(client) && IsPlayerAlive(client)) { if ((c_iSelectType == 0) || (c_iSelectType >= 1 && g_bFixTarget[client])) { - new Action:ret = Plugin_Continue; + Action ret = Plugin_Continue; ret = onSBRunCmd(client, buttons, vel, angles); if (c_bIncapacitated_Enabled) ret = onSBRunCmd_Incapacitated(client, buttons, vel, angles); ret = onSBSlotActionCmd(client, buttons, vel, angles); @@ -678,15 +680,15 @@ public Action:OnPlayerRunCmd(client, &buttons, &impulse, *= Weapon Switch *= ================================================================================================ */ -public OnClientPutInServer(client) +public void OnClientPutInServer(int client) { SDKHook(client, SDKHook_WeaponSwitch, WeaponSwitch); } -public OnClientDisconnect(client) +public void OnClientDisconnect(int client) { SDKUnhook(client, SDKHook_WeaponSwitch, WeaponSwitch); } -public Action:WeaponSwitch(client, weapon) +public Action WeaponSwitch(int client, int weapon) { if (!g_hEnabled) return Plugin_Continue; if (!isSurvivor(client) || !IsFakeClient(client) || !IsValidEntity(weapon)) return Plugin_Continue; @@ -700,8 +702,8 @@ public Action:WeaponSwitch(client, weapon) || isHaveItem(classname, "weapon_dual_pistol")) { if (c_bDontSwitchSecondary) { - new slot0 = GetPlayerWeaponSlot(client, 0); - new clip, extra_ammo; + int slot0 = GetPlayerWeaponSlot(client, 0); + int clip, extra_ammo; clip = GetEntProp(slot0, Prop_Send, "m_iClip1"); extra_ammo = PrimaryExtraAmmoCheck(client, slot0); // check @@ -722,7 +724,7 @@ public Action:WeaponSwitch(client, weapon) return Plugin_Continue; } -stock Action:onSBSlotActionCmd(client, &buttons, Float:vel[3], Float:angles[3]) +stock Action onSBSlotActionCmd(int client, int &buttons, float vel[3], float angles[3]) { if (!isIncapacitated(client) && GetPlayerWeaponSlot(client, 0) > -1) { int weapon = GetEntDataEnt2(client, g_ActiveWeapon); @@ -764,30 +766,30 @@ stock Action:onSBSlotActionCmd(client, &buttons, Float:vel[3], Float:angles[3]) *= SB Run Cmd *= ================================================================================================ */ -stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) +stock Action onSBRunCmd(int client, int &buttons, float vel[3], float angles[3]) { if (!isIncapacitated(client) && GetEntityMoveType(client) != MOVETYPE_LADDER) { // Find a nearest visible Special Infected - new new_target = -1; - new Float:min_dist = 100000.0; - new Float:self_pos[3], Float:target_pos[3]; + int int_target = -1; + float min_dist = 100000.0; + float self_pos[3], target_pos[3]; if ((c_bSI_Enabled || c_bTank_Enabled) && !NeedsTeammateHelp_ExceptSmoker(client)) { GetClientAbsOrigin(client, self_pos); - for (new x = 1; x <= MaxClients; ++x) { + for (int x = 1; x <= MaxClients; ++x) { if (isInfected(x) && IsPlayerAlive(x) && !isIncapacitated(x) && isVisibleTo(client, x)) { - new Float:dist; + float dist; GetClientAbsOrigin(x, target_pos); dist = GetVectorDistance(self_pos, target_pos); - new zombieClass = getZombieClass(x); + int zombieClass = getZombieClass(x); if ((c_bSI_Enabled && zombieClass != ZC_TANK && dist <= c_fSI_Range) || (c_bTank_Enabled && zombieClass == ZC_TANK && dist <= c_fTank_Range)) { @@ -795,14 +797,14 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) || (c_iSITank_PriorityType == 2 && zombieClass == ZC_TANK)) { if (dist < min_dist) { min_dist = dist; - new_target = x; + int_target = x; continue; } } if (dist < min_dist) { min_dist = dist; - new_target = x; + int_target = x; } } @@ -810,23 +812,23 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) } } - new aCap_Survivor = -1; - new Float:min_dist_CapSur = 100000.0; - new Float:target_pos_CapSur[3]; + int aCap_Survivor = -1; + float min_dist_CapSur = 100000.0; + float target_pos_CapSur[3]; - new aCap_Infected = -1; - new Float:min_dist_CapInf = 100000.0; - new Float:target_pos_CapInf[3]; + int aCap_Infected = -1; + float min_dist_CapInf = 100000.0; + float target_pos_CapInf[3]; if (c_bHelp_Enabled && !NeedsTeammateHelp_ExceptSmoker(client)) { // Find a Survivor who are pinned - for (new x = 1; x <= MaxClients; ++x) { + for (int x = 1; x <= MaxClients; ++x) { if (isSurvivor(x) && NeedsTeammateHelp(x) && (x != client) && (isVisibleTo(client, x) || isVisibleTo(x, client))) { - new Float:dist; + float dist; GetClientAbsOrigin(x, target_pos_CapSur); dist = GetVectorDistance(self_pos, target_pos_CapSur); @@ -840,12 +842,12 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) } // Find a Special Infected who are pinning - for (new x = 1; x <= MaxClients; ++x) { + for (int x = 1; x <= MaxClients; ++x) { if (isInfected(x) && CappingSuvivor(x) && (isVisibleTo(client, x) || isVisibleTo(x, client))) { - new Float:dist; + float dist; GetClientAbsOrigin(x, target_pos_CapInf); dist = GetVectorDistance(self_pos, target_pos_CapInf); @@ -861,17 +863,17 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) /* // Find aCapSmoker - new aCapSmoker = -1; - new Float:min_dist_CapSmo = 100000.0; - new Float:target_pos_CapSmo[3]; + int aCapSmoker = -1; + float min_dist_CapSmo = 100000.0; + float target_pos_CapSmo[3]; - for (new x = 1; x <= MaxClients; ++x) { + for (int x = 1; x <= MaxClients; ++x) { if (isSpecialInfectedBot(x) && IsPlayerAlive(x) && HasValidEnt(x, "m_tongueVictim") - && isVisibleTo(client, x)) + && isVisibleTo(int client, x)) { - new Float:dist; + float dist; GetClientAbsOrigin(x, target_pos_CapSmo); dist = GetVectorDistance(self_pos, target_pos_CapSmo); @@ -886,19 +888,19 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) */ // Find a Smoker who is tongued self - new aCapSmoker = -1; + int aCapSmoker = -1; if (c_bPrioritize_OwnerSmoker) { - new Float:min_dist_CapSmo = 100000.0; - new Float:target_pos_CapSmo[3]; + float min_dist_CapSmo = 100000.0; + float target_pos_CapSmo[3]; - for (new x = 1; x <= MaxClients; ++x) { + for (int x = 1; x <= MaxClients; ++x) { if (isInfected(x) && IsPlayerAlive(x) && HasValidEnt(x, "m_tongueVictim")) { if (GetEntPropEnt(x, Prop_Send, "m_tongueVictim") == client) { - new Float:dist; + float dist; GetClientAbsOrigin(x, target_pos_CapSmo); dist = GetVectorDistance(self_pos, target_pos_CapSmo); @@ -914,12 +916,12 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) } // Find a flying Hunter and Jockey - new aHunterJockey = -1; - new Float:hunjoc_pos[3]; - new Float:min_dist_HunJoc = 100000.0; + int aHunterJockey = -1; + float hunjoc_pos[3]; + float min_dist_HunJoc = 100000.0; if (c_bBash_Enabled && !NeedsTeammateHelp_ExceptSmoker(client)) { - for (new x = 1; x <= MaxClients; ++x) { + for (int x = 1; x <= MaxClients; ++x) { if (isInfected(x) && IsPlayerAlive(x) && !isStagger(x) @@ -927,12 +929,12 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) { if (getZombieClass(x) == ZC_HUNTER) { if (c_iBash_HunterChance == 100 || (c_iBash_HunterChance < 100 && g_bShove[client][x])) { - new Float:hunterVelocity[3]; + float hunterVelocity[3]; GetEntDataVector(x, g_Velo, hunterVelocity); if ((GetClientButtons(x) & IN_DUCK) && hunterVelocity[2] != 0.0) { GetClientAbsOrigin(x, hunjoc_pos); - new Float:hundist; + float hundist; hundist = GetVectorDistance(self_pos, hunjoc_pos); if (hundist < c_fBash_HunterRange) { // 145.0 best @@ -946,12 +948,12 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) } else if (getZombieClass(x) == ZC_JOCKEY) { if (c_iBash_JockeyChance == 100 || (c_iBash_JockeyChance < 100 && g_bShove[client][x])) { - new Float:jockeyVelocity[3]; + float jockeyVelocity[3]; GetEntDataVector(x, g_Velo, jockeyVelocity); if (jockeyVelocity[2] != 0.0) { GetClientAbsOrigin(x, hunjoc_pos); - new Float:jocdist; + float jocdist; jocdist = GetVectorDistance(self_pos, hunjoc_pos); if (jocdist < c_fBash_JockeyRange) { // 125.0 best @@ -968,24 +970,24 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) } // Find a Common Infected - //new iMaxEntities = GetMaxEntities(); - new aCommonInfected = -1; - new iCI_MeleeCount = 0; - new Float:min_dist_CI = 100000.0; - new Float:ci_pos[3]; + //int iMaxEntities = GetMaxEntities(); + int aCommonInfected = -1; + int iCI_MeleeCount = 0; + float min_dist_CI = 100000.0; + float ci_pos[3]; if (c_bCI_Enabled && !NeedsTeammateHelp(client)) { - for (new iEntity = MaxClients+1; iEntity <= MAXENTITIES; ++iEntity) { + for (int iEntity = MaxClients+1; iEntity <= MAXENTITIES; ++iEntity) { if (IsCommonInfected(iEntity) && GetEntProp(iEntity, Prop_Data, "m_iHealth") > 0 && isVisibleToEntity(iEntity, client)) { - new Float:dist; + float dist; GetEntPropVector(iEntity, Prop_Data, "m_vecAbsOrigin", ci_pos); dist = GetVectorDistance(self_pos, ci_pos); if (dist < c_fCI_Range) { - new iSeq = GetEntProp(iEntity, Prop_Send, "m_nSequence", 2); + int iSeq = GetEntProp(iEntity, Prop_Send, "m_nSequence", 2); // Stagger 122, 123, 126, 127, 128, 133, 134 // Down Stagger 128, 129, 130, 131 // Object Climb (Very Low) 182, 183, 184, 185 @@ -1009,18 +1011,18 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) } // Fina a rage Witch - new aWitch = -1; - new Float:min_dist_Witch = 100000.0; - new Float:witch_pos[3]; + int aWitch = -1; + float min_dist_Witch = 100000.0; + float witch_pos[3]; if (g_bWitchActive && c_bWitch_Enabled && !NeedsTeammateHelp(client)) { - for (new iEntity = MaxClients+1; iEntity <= MAXENTITIES; ++iEntity) + for (int iEntity = MaxClients+1; iEntity <= MAXENTITIES; ++iEntity) { if (IsWitch(iEntity) && GetEntProp(iEntity, Prop_Data, "m_iHealth") > 0 && IsWitchRage(iEntity) && isVisibleToEntity(iEntity, client)) { - new Float:witch_dist; + float witch_dist; GetEntPropVector(iEntity, Prop_Data, "m_vecAbsOrigin", witch_pos); witch_dist = GetVectorDistance(self_pos, witch_pos); @@ -1037,16 +1039,16 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) } // Find a tank rock - new aTankRock = -1; - new Float:rock_min_dist = 100000.0; - new Float:rock_pos[3]; + int aTankRock = -1; + float rock_min_dist = 100000.0; + float rock_pos[3]; if (c_bRock_Enabled && !NeedsTeammateHelp(client)) { - for (new iEntity = MaxClients+1; iEntity <= MAXENTITIES; ++iEntity) + for (int iEntity = MaxClients+1; iEntity <= MAXENTITIES; ++iEntity) { if (IsTankRock(iEntity) && isVisibleToEntity(iEntity, client)) { - new Float:rock_dist; + float rock_dist; GetEntPropVector(iEntity, Prop_Data, "m_vecAbsOrigin", rock_pos); rock_dist = GetVectorDistance(self_pos, rock_pos); @@ -1068,13 +1070,13 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) ***************************** --------------------------------------------------------------------------------------------------------------------------------------------------------------- */ - new weapon = GetEntDataEnt2(client, g_ActiveWeapon); + int weapon = GetEntDataEnt2(client, g_ActiveWeapon); static char AW_Classname[32]; if (weapon > MAXPLAYERS) GetEntityClassname(weapon, AW_Classname, sizeof(AW_Classname)); // Exception reported: Entity -1 (-1) is invalid static char main_weapon[32]; - new slot0 = GetPlayerWeaponSlot(client, 0); + int slot0 = GetPlayerWeaponSlot(client, 0); if (slot0 > -1) { GetEntityClassname(slot0, main_weapon, sizeof(main_weapon)); } @@ -1109,12 +1111,12 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) if (g_bCommonWithinMelee[client]) { if (aCommonInfected < 1) g_bCommonWithinMelee[client] = false; if (aCommonInfected > 0) { - new Float:c_pos[3], Float:common_e_pos[3]; + float c_pos[3], common_e_pos[3]; GetClientAbsOrigin(client, c_pos); GetEntPropVector(aCommonInfected, Prop_Data, "m_vecOrigin", common_e_pos); - new Float:aimdist = GetVectorDistance(c_pos, common_e_pos); + float aimdist = GetVectorDistance(c_pos, common_e_pos); if (aimdist > c_fCI_MeleeRange) g_bCommonWithinMelee[client] = false; } @@ -1130,8 +1132,8 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) if (aHunterJockey > 0) { if (!g_bDanger[client]) g_bDanger[client] = true; - new Float:c_pos[3], Float:e_pos[3]; - new Float:lookat[3]; + float c_pos[3], e_pos[3]; + float lookat[3]; GetClientAbsOrigin(client, c_pos); GetClientAbsOrigin(aHunterJockey, e_pos); @@ -1158,8 +1160,8 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) if (aCapSmoker > 0) { // Shoot even if client invisible the smoker if (!g_bDanger[client]) g_bDanger[client] = true; - new Float:c_pos[3], Float:e_pos[3]; - new Float:lookat[3]; + float c_pos[3], e_pos[3]; + float lookat[3]; GetClientAbsOrigin(client, c_pos); GetEntPropVector(aCapSmoker, Prop_Data, "m_vecOrigin", e_pos); @@ -1179,7 +1181,7 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) TeleportEntity(client, NULL_VECTOR, angles, NULL_VECTOR); - new Float:aimdist = GetVectorDistance(c_pos, e_pos); + float aimdist = GetVectorDistance(c_pos, e_pos); if (aimdist < 100.0) buttons |= IN_ATTACK2; else { @@ -1202,8 +1204,8 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) if (aCap_Survivor > 0) { // Pass if the client and target are "visible" to each other. so aCap Smoker doesn't pass if (!g_bDanger[client]) g_bDanger[client] = true; - new Float:c_pos[3], Float:e_pos[3]; - new Float:lookat[3]; + float c_pos[3], e_pos[3]; + float lookat[3]; GetClientEyePosition(client, c_pos); GetClientEyePosition(aCap_Survivor, e_pos); @@ -1214,7 +1216,7 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) e_pos[2] += -10.0; } - new Float:aimdist = GetVectorDistance(c_pos, e_pos); + float aimdist = GetVectorDistance(c_pos, e_pos); MakeVectorFromPoints(c_pos, e_pos, lookat); GetVectorAngles(lookat, angles); @@ -1258,10 +1260,10 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) else if (aCap_Infected > 0 && aCap_Survivor < 1) { if (!g_bDanger[client]) g_bDanger[client] = true; - new zombieClass = getZombieClass(aCap_Infected); + int zombieClass = getZombieClass(aCap_Infected); - new Float:c_pos[3], Float:e_pos[3]; - new Float:lookat[3]; + float c_pos[3], e_pos[3]; + float lookat[3]; GetClientEyePosition(client, c_pos); @@ -1275,7 +1277,7 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) else if (zombieClass == ZC_HUNTER) e_pos[2] += -14.0; } - new Float:aimdist = GetVectorDistance(c_pos, e_pos); + float aimdist = GetVectorDistance(c_pos, e_pos); if (zombieClass == ZC_CHARGER && aimdist < 300.0) e_pos[2] += 10.0; @@ -1330,8 +1332,8 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) * ==================================================================================================== */ if (aTankRock > 1 && !HasValidEnt(client, "m_reviveTarget")) { - new Float:c_pos[3], Float:rock_e_pos[3]; - new Float:lookat[3]; + float c_pos[3], rock_e_pos[3]; + float lookat[3]; GetClientAbsOrigin(client, c_pos); GetEntPropVector(aTankRock, Prop_Data, "m_vecAbsOrigin", rock_e_pos); @@ -1346,7 +1348,7 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) // PrintToChatAll("---"); } - new Float:aimdist = GetVectorDistance(c_pos, rock_e_pos); + float aimdist = GetVectorDistance(c_pos, rock_e_pos); if (aimdist > 40.0 && !isHaveItem(AW_Classname, "weapon_melee")) { //�ߐڂ������Ă��Ȃ��ꍇ TeleportEntity(client, NULL_VECTOR, angles, NULL_VECTOR); @@ -1359,8 +1361,8 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) } if (aWitch > 1) { - new Float:c_pos[3], Float:witch_e_pos[3]; - new Float:lookat[3]; + float c_pos[3], witch_e_pos[3]; + float lookat[3]; GetClientEyePosition(client, c_pos); GetEntPropVector(aWitch, Prop_Data, "m_vecAbsOrigin", witch_e_pos); @@ -1373,7 +1375,7 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) TeleportEntity(client, NULL_VECTOR, angles, NULL_VECTOR); - new Float:aimdist = GetVectorDistance(c_pos, witch_e_pos); + float aimdist = GetVectorDistance(c_pos, witch_e_pos); if (c_bWitch_Shotgun_Control && isHaveItem(AW_Classname, "shotgun")) { if (aimdist < 150.0) buttons |= IN_DUCK; @@ -1407,21 +1409,21 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) // Even if aCommonInfected dies and disappears, the Entity may not disappear for a while.(Bot keeps shooting the place)�B Even with InValidEntity(), true appears... // When the entity disappears, m_nNextThinkTick will not advance, so skip that if NextThinkTick has the same value as before. - new iNextThinkTick = GetEntProp(aCommonInfected, Prop_Data, "m_nNextThinkTick"); + int iNextThinkTick = GetEntProp(aCommonInfected, Prop_Data, "m_nNextThinkTick"); if (g_Stock_NextThinkTick[client] != iNextThinkTick) // If visible aCommonInfected { - new Float:c_pos[3], Float:common_e_pos[3]; - new Float:lookat[3]; + float c_pos[3], common_e_pos[3]; + float lookat[3]; GetClientEyePosition(client, c_pos); GetEntPropVector(aCommonInfected, Prop_Data, "m_vecOrigin", common_e_pos); - //new Float:height_difference = (c_pos[2] - common_e_pos[2]) - 60.0; + //float height_difference = (c_pos[2] - common_e_pos[2]) - 60.0; common_e_pos[2] += 40.0; - new Float:aimdist = GetVectorDistance(c_pos, common_e_pos); + float aimdist = GetVectorDistance(c_pos, common_e_pos); //common_e_pos[2] += (25.0 + (aimdist * 0.05) - (height_difference * 0.1)); @@ -1429,7 +1431,7 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) // GetEntPropVector(aCommonInfected, Prop_Data, "m_vecOrigin", common_e_pos); // common_e_pos[2] += -30.0; - new iSeq = GetEntProp(aCommonInfected, Prop_Send, "m_nSequence", 2); + int iSeq = GetEntProp(aCommonInfected, Prop_Send, "m_nSequence", 2); // Stagger 122, 123, 126, 127, 128, 133, 134 // Down Stagger 128, 129, 130, 131 // Object Climb (Very Low) 182, 183, 184, 185 @@ -1453,7 +1455,7 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) g_bCommonWithinMelee[client] = true; static char sub_weapon[16]; - new slot1 = GetPlayerWeaponSlot(client, 1); + int slot1 = GetPlayerWeaponSlot(client, 1); if (slot1 > -1) { GetEntityClassname(slot1, sub_weapon, sizeof(sub_weapon)); // SubWeapon } @@ -1465,7 +1467,7 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) } } - if (new_target > 0) { + if (int_target > 0) { if (aimdist <= 90.0) TeleportEntity(client, NULL_VECTOR, angles, NULL_VECTOR); } else { if (isHaveItem(AW_Classname, "weapon_melee")) { @@ -1475,7 +1477,7 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) } } - if (new_target < 1 || (new_target > 0 && aimdist <= 90.0)) { // If new_target and common at the same time, prioritize to new_target. Attack only when within 90.0 dist. + if (int_target < 1 || (int_target > 0 && aimdist <= 90.0)) { // If int_target and common at the same time, prioritize to int_target. Attack only when within 90.0 dist. if (isHaveItem(AW_Classname, "weapon_melee")) { if (GetRandomInt(0, 6) == 0) { if (aimdist <= 50.0) buttons |= IN_ATTACK2; @@ -1523,24 +1525,24 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) /* ==================================================================================================== * - * �D��xF : Special Infected and Tank (new_target) + * �D��xF : Special Infected and Tank (int_target) * ==================================================================================================== */ - if (new_target > 0) { - new Float:c_pos[3], Float:e_pos[3]; - new Float:lookat[3]; + if (int_target > 0) { + float c_pos[3], e_pos[3]; + float lookat[3]; GetClientAbsOrigin(client, c_pos); - new zombieClass = getZombieClass(new_target); + int zombieClass = getZombieClass(int_target); if (aCapSmoker > 0) { // Prioritize aCapSmoker GetClientAbsOrigin(aCapSmoker, e_pos); e_pos[2] += -10.0; } else { - GetClientAbsOrigin(new_target, e_pos); + GetClientAbsOrigin(int_target, e_pos); if (zombieClass == ZC_HUNTER - && (GetClientButtons(new_target) & IN_DUCK)) { + && (GetClientButtons(int_target) & IN_DUCK)) { if (GetVectorDistance(c_pos, e_pos) > 250.0) e_pos[2] += -30.0; else e_pos[2] += -35.0; } else if (zombieClass == ZC_JOCKEY) { @@ -1552,7 +1554,7 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) if (zombieClass == ZC_TANK && aTankRock > 0) return Plugin_Continue; // If the Tank and tank rock are visible at the same time, prioritize the tank rock - new Float:aimdist = GetVectorDistance(c_pos, e_pos); + float aimdist = GetVectorDistance(c_pos, e_pos); if (aimdist < 200.0) {if (!g_bDanger[client]) g_bDanger[client] = true;} @@ -1581,20 +1583,20 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) /****************************************************************************************************/ - new bool:isTargetBoomer = false; // Is new_target Boomer - new bool:isBoomer_Shoot_OK = false; + bool isTargetBoomer = false; + bool isBoomer_Shoot_OK = false; if (c_bSI_IgnoreBoomer && zombieClass == ZC_BOOMER) { - new Float:voS_pos[3]; - for (new s = 1; s <= MaxClients; ++s) { + float voS_pos[3]; + for (int s = 1; s <= MaxClients; ++s) { if (isSurvivor(s) && IsPlayerAlive(s)) { - new Float:fVomit = GetEntPropFloat(s, Prop_Send, "m_vomitStart"); + float fVomit = GetEntPropFloat(s, Prop_Send, "m_vomitStart"); if (GetGameTime() - fVomit > 10.0) { // Survivors without vomit GetClientAbsOrigin(s, voS_pos); - new Float:dist = GetVectorDistance(voS_pos, e_pos); // Distance between the Survivor without vomit and the Boomer + float dist = GetVectorDistance(voS_pos, e_pos); // Distance between the Survivor without vomit and the Boomer if (dist >= c_fSI_IgnoreBoomerRange) { isBoomer_Shoot_OK = true; } // If the survivor without vomit is farther than dist "c_fSI_IgnoreBoomerRange (def: 200)" else { isBoomer_Shoot_OK = false; break; } // If False appears even once, break } @@ -1603,15 +1605,15 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) isTargetBoomer = true; } - if ((zombieClass == ZC_JOCKEY && g_bShove[client][new_target]) + if ((zombieClass == ZC_JOCKEY && g_bShove[client][int_target]) || zombieClass == ZC_SMOKER || (isTargetBoomer && !isBoomer_Shoot_OK)) { - if (aimdist < 90.0 && !isStagger(new_target)) { + if (aimdist < 90.0 && !isStagger(int_target)) { TeleportEntity(client, NULL_VECTOR, angles, NULL_VECTOR); buttons |= IN_ATTACK2; if (c_bDebug_Enabled) { - PrintToChatAll("\x01[%.2f] \x05%N\x01 new_target shoved: \x04%N (%d)", GetGameTime(), client, new_target, new_target); + PrintToChatAll("\x01[%.2f] \x05%N\x01 int_target shoved: \x04%N (%d)", GetGameTime(), client, int_target, int_target); EmitSoundToAll(SOUND_SWING, client); } return Plugin_Changed; @@ -1622,8 +1624,8 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) || (aimdist < 100.0 && isHaveItem(AW_Classname, "weapon_melee"))) { if (c_bDebug_Enabled) { - if (!isTargetBoomer) PrintToChatAll("\x01[%.2f] \x05%N\x01 new_target: \x04%N (%d)", GetGameTime(), client, new_target, new_target); - else PrintToChatAll("\x01[%.2f] \x05%N\x01 new_target: \x04%N (%d) (Shoot: %s)", GetGameTime(), client, new_target, new_target, (isBoomer_Shoot_OK) ? "OK" : "NO"); + if (!isTargetBoomer) PrintToChatAll("\x01[%.2f] \x05%N\x01 int_target: \x04%N (%d)", GetGameTime(), client, int_target, int_target); + else PrintToChatAll("\x01[%.2f] \x05%N\x01 int_target: \x04%N (%d) (Shoot: %s)", GetGameTime(), client, int_target, int_target, (isBoomer_Shoot_OK) ? "OK" : "NO"); } if (!isTargetBoomer || (isTargetBoomer && isBoomer_Shoot_OK)) { @@ -1651,16 +1653,16 @@ stock Action:onSBRunCmd(client, &buttons, Float:vel[3], Float:angles[3]) *= Incapacitated Run Cmd *= ================================================================================================ */ -stock Action:onSBRunCmd_Incapacitated(client, &buttons, Float:vel[3], Float:angles[3]) +stock Action onSBRunCmd_Incapacitated(int client, int &buttons, float vel[3], float angles[3]) { if (isIncapacitated(client)) { - new aCapper = -1; - new Float:min_dist_Cap = 100000.0; - new Float:self_pos[3], Float:target_pos[3]; + int aCapper = -1; + float min_dist_Cap = 100000.0; + float self_pos[3], target_pos[3]; GetClientEyePosition(client, self_pos); if (!NeedsTeammateHelp(client)) { - for (new x = 1; x <= MaxClients; ++x) { + for (int x = 1; x <= MaxClients; ++x) { // �S������Ă��鐶���҂�T�� if (isSurvivor(x) && NeedsTeammateHelp(x) @@ -1668,7 +1670,7 @@ stock Action:onSBRunCmd_Incapacitated(client, &buttons, Float:vel[3], Float:angl && (isVisibleTo(client, x) || isVisibleTo(x, client))) { GetClientAbsOrigin(x, target_pos); - new Float:dist = GetVectorDistance(self_pos, target_pos); + float dist = GetVectorDistance(self_pos, target_pos); if (dist < min_dist_Cap) { min_dist_Cap = dist; aCapper = x; @@ -1681,7 +1683,7 @@ stock Action:onSBRunCmd_Incapacitated(client, &buttons, Float:vel[3], Float:angl && (isVisibleTo(client, x) || isVisibleTo(x, client))) { GetClientAbsOrigin(x, target_pos); - new Float:dist = GetVectorDistance(self_pos, target_pos); + float dist = GetVectorDistance(self_pos, target_pos); if (dist < min_dist_Cap) { min_dist_Cap = dist; aCapper = x; @@ -1691,8 +1693,8 @@ stock Action:onSBRunCmd_Incapacitated(client, &buttons, Float:vel[3], Float:angl } if (aCapper > 0) { - new Float:c_pos[3], Float:e_pos[3]; - new Float:lookat[3]; + float c_pos[3], e_pos[3]; + float lookat[3]; GetClientEyePosition(client, c_pos); GetClientEyePosition(aCapper, e_pos); @@ -1723,40 +1725,40 @@ stock Action:onSBRunCmd_Incapacitated(client, &buttons, Float:vel[3], Float:angl } - new new_target = -1; - new aCommonInfected = -1; + int int_target = -1; + int aCommonInfected = -1; if (aCapper < 1 && !NeedsTeammateHelp(client)) { - new Float:min_dist = 100000.0; - new Float:ci_pos[3]; + float min_dist = 100000.0; + float ci_pos[3]; - for (new x = 1; x <= MaxClients; ++x){ + for (int x = 1; x <= MaxClients; ++x){ if (isInfected(x) && IsPlayerAlive(x) && (isVisibleTo(client, x) || isVisibleTo(x, client))) { GetClientAbsOrigin(x, target_pos); - new Float:dist = GetVectorDistance(self_pos, target_pos); + float dist = GetVectorDistance(self_pos, target_pos); if (dist < min_dist) { min_dist = dist; - new_target = x; + int_target = x; aCommonInfected = -1; } } } if (c_bCI_Enabled) { - for (new iEntity = MaxClients+1; iEntity <= MAXENTITIES; ++iEntity) { + for (int iEntity = MaxClients+1; iEntity <= MAXENTITIES; ++iEntity) { if (IsCommonInfected(iEntity) && GetEntProp(iEntity, Prop_Data, "m_iHealth") > 0 && isVisibleToEntity(iEntity, client)) { GetEntPropVector(iEntity, Prop_Data, "m_vecAbsOrigin", ci_pos); - new Float:dist = GetVectorDistance(self_pos, ci_pos); + float dist = GetVectorDistance(self_pos, ci_pos); if (dist < min_dist) { min_dist = dist; aCommonInfected = iEntity; - new_target = -1; + int_target = -1; } } } @@ -1764,8 +1766,8 @@ stock Action:onSBRunCmd_Incapacitated(client, &buttons, Float:vel[3], Float:angl } if (aCommonInfected > 0) { - new Float:c_pos[3], Float:common_e_pos[3]; - new Float:lookat[3]; + float c_pos[3], common_e_pos[3]; + float lookat[3]; GetClientEyePosition(client, c_pos); GetEntPropVector(aCommonInfected, Prop_Data, "m_vecOrigin", common_e_pos); @@ -1774,7 +1776,7 @@ stock Action:onSBRunCmd_Incapacitated(client, &buttons, Float:vel[3], Float:angl MakeVectorFromPoints(c_pos, common_e_pos, lookat); GetVectorAngles(lookat, angles); - new Float:aimdist = GetVectorDistance(c_pos, common_e_pos); + float aimdist = GetVectorDistance(c_pos, common_e_pos); /****************************************************************************************************/ @@ -1788,26 +1790,26 @@ stock Action:onSBRunCmd_Incapacitated(client, &buttons, Float:vel[3], Float:angl return Plugin_Changed; } - if (new_target > 0) { - new Float:c_pos[3], Float:e_pos[3]; - new Float:lookat[3]; + if (int_target > 0) { + float c_pos[3], e_pos[3]; + float lookat[3]; GetClientEyePosition(client, c_pos); - GetClientEyePosition(new_target, e_pos); + GetClientEyePosition(int_target, e_pos); e_pos[2] += -15.0 - new zombieClass = getZombieClass(new_target); + int zombieClass = getZombieClass(int_target); if (zombieClass == ZC_JOCKEY) { e_pos[2] += -30.0; } else if (zombieClass == ZC_HUNTER) { - if ((GetClientButtons(new_target) & IN_DUCK) || HasValidEnt(new_target, "m_pounceVictim")) e_pos[2] += -25.0; + if ((GetClientButtons(int_target) & IN_DUCK) || HasValidEnt(int_target, "m_pounceVictim")) e_pos[2] += -25.0; } MakeVectorFromPoints(c_pos, e_pos, lookat); GetVectorAngles(lookat, angles); - if (c_bDebug_Enabled) PrintToChatAll("\x01[%.2f] \x05%N \x01new target Incapacitated: \x04%N", GetGameTime(), client, new_target); + if (c_bDebug_Enabled) PrintToChatAll("\x01[%.2f] \x05%N \x01int target Incapacitated: \x04%N", GetGameTime(), client, int_target); TeleportEntity(client, NULL_VECTOR, angles, NULL_VECTOR); @@ -1827,14 +1829,14 @@ stock Action:onSBRunCmd_Incapacitated(client, &buttons, Float:vel[3], Float:angl *= Events *= ================================================================================================ */ -public Action:Event_PlayerIncapacitated(Handle:event, const char[] name, bool:dontBroadcast) +public Action Event_PlayerIncapacitated(Handle event, const char[] name, bool dontBroadcast) { if (!g_hEnabled) return Plugin_Handled; - new victim = GetClientOfUserId(GetEventInt(event, "userid")); - new attackerentid = GetEventInt(event, "attackerentid"); + int victim = GetClientOfUserId(GetEventInt(event, "userid")); + int attackerentid = GetEventInt(event, "attackerentid"); - // new type = GetEventInt(event, "type"); + // int type = GetEventInt(event, "type"); // PrintToChatAll("\x04PlayerIncapacitated"); // PrintToChatAll("type %i", type); @@ -1843,22 +1845,22 @@ public Action:Event_PlayerIncapacitated(Handle:event, const char[] name, bool:do g_iWitch_Process[attackerentid] = WITCH_INCAPACITATED; // PrintToChatAll("attackerentid %i attacked %N", attackerentid, victim); - // new health = GetEventInt(event, "health"); - // new dmg_health = GetEventInt(event, "dmg_health"); + // int health = GetEventInt(event, "health"); + // int dmg_health = GetEventInt(event, "dmg_health"); // PrintToChatAll("health: %i, damage: %i", health, dmg_health); } return Plugin_Handled; } -public Action:Event_PlayerDeath(Handle:event, const char[] name, bool:dontBroadcast) +public Action Event_PlayerDeath(Handle event, const char[] name, bool dontBroadcast) { if (!g_hEnabled) return Plugin_Handled; - new victim = GetClientOfUserId(GetEventInt(event, "userid")); - new attackerentid = GetEventInt(event, "attackerentid"); + int victim = GetClientOfUserId(GetEventInt(event, "userid")); + int attackerentid = GetEventInt(event, "attackerentid"); - // new type = GetEventInt(event, "type"); + // int type = GetEventInt(event, "type"); // PrintToChatAll("\x04PlayerDeath"); // PrintToChatAll("type %i", type); @@ -1867,8 +1869,8 @@ public Action:Event_PlayerDeath(Handle:event, const char[] name, bool:dontBroadc g_iWitch_Process[attackerentid] = WITCH_KILLED; // PrintToChatAll("attackerentid %i attacked %N", attackerentid, victim); - // new health = GetEventInt(event, "health"); - // new dmg_health = GetEventInt(event, "dmg_health"); + // int health = GetEventInt(event, "health"); + // int dmg_health = GetEventInt(event, "dmg_health"); // PrintToChatAll("health: %i, damage: %i", health, dmg_health); } @@ -1878,9 +1880,9 @@ public Action:Event_PlayerDeath(Handle:event, const char[] name, bool:dontBroadc return Plugin_Handled; } -public Action:Event_WitchRage(Handle:event, const char[] name, bool:dontBroadcast) +public Action Event_WitchRage(Handle event, const char[] name, bool dontBroadcast) { - new attacker = GetClientOfUserId(GetEventInt(event, "userid")); + int attacker = GetClientOfUserId(GetEventInt(event, "userid")); if (isSurvivor(attacker)) { // CallBotstoWitch(attacker); @@ -1888,7 +1890,7 @@ public Action:Event_WitchRage(Handle:event, const char[] name, bool:dontBroadcas } } -public OnEntityCreated(entity, const char[] classname) +public void OnEntityCreated(int entity, const char[] classname) { if (entity >= MaxClients && g_hEnabled && strcmp(classname, "witch") == 0) { @@ -1896,15 +1898,15 @@ public OnEntityCreated(entity, const char[] classname) } } -public OnEntityDestroyed(entity) { +public void OnEntityDestroyed(int entity) { if(entity == -1) return; static char classname[32]; GetEntityClassname(entity, classname, sizeof(classname)); if (StrEqual(classname, "witch", false)) { if (g_bWitchActive) { - new iWitch_Count = 0; - for (new iEntity = MaxClients+1; iEntity <= MAXENTITIES; ++iEntity) + int iWitch_Count = 0; + for (int iEntity = MaxClients+1; iEntity <= MAXENTITIES; ++iEntity) { if (IsWitch(iEntity) && GetEntProp(iEntity, Prop_Data, "m_iHealth") > 0 && IsWitchRage(iEntity)) { @@ -1925,18 +1927,18 @@ public OnEntityDestroyed(entity) { *= Stock any *= ================================================================================================ */ -stock ScriptCommand(client, const char[] command, const char[] arguments, any:...) +stock void ScriptCommand(int client, const char[] command, const char[] arguments, any ...) { static char vscript[PLATFORM_MAX_PATH]; VFormat(vscript, sizeof(vscript), arguments, 4); - new flags = GetCommandFlags(command); + int flags = GetCommandFlags(command); SetCommandFlags(command, flags & ~FCVAR_CHEAT); FakeClientCommand(client, "%s %s", command, vscript); SetCommandFlags(command, flags); } -stock L4D2_RunScript(const char[] sCode, any:...) +stock void L4D2_RunScript(const char[] sCode, any ...) { static iScriptLogic = INVALID_ENT_REFERENCE; if(iScriptLogic == INVALID_ENT_REFERENCE || !IsValidEntity(iScriptLogic)) { @@ -1960,7 +1962,7 @@ stock L4D2_RunScript(const char[] sCode, any:...) * Bool * */ -stock bool:NeedsTeammateHelp(client) +stock bool NeedsTeammateHelp(int client) { if (HasValidEnt(client, "m_tongueOwner") || HasValidEnt(client, "m_pounceAttacker") @@ -1974,7 +1976,7 @@ stock bool:NeedsTeammateHelp(client) return false; } -stock bool:NeedsTeammateHelp_ExceptSmoker(client) +stock bool NeedsTeammateHelp_ExceptSmoker(int client) { if (HasValidEnt(client, "m_pounceAttacker") || HasValidEnt(client, "m_jockeyAttacker") @@ -1987,7 +1989,7 @@ stock bool:NeedsTeammateHelp_ExceptSmoker(client) return false; } -stock bool:CappingSuvivor(client) +stock bool CappingSuvivor(int client) { if (HasValidEnt(client, "m_tongueVictim") || HasValidEnt(client, "m_pounceVictim") @@ -2001,20 +2003,20 @@ stock bool:CappingSuvivor(client) return false; } -stock bool:HasValidEnt(client, const char[] entprop) +stock bool HasValidEnt(int client, const char[] entprop) { - new ent = GetEntPropEnt(client, Prop_Send, entprop); + int ent = GetEntPropEnt(client, Prop_Send, entprop); return (ent > 0 && IsClientInGame(ent)); } -stock bool:IsWitchRage(id) { +stock bool IsWitchRage(int id) { if (GetEntPropFloat(id, Prop_Send, "m_rage") >= 1.0) return true; return false; } -stock bool:IsCommonInfected(iEntity) +stock bool IsCommonInfected(int iEntity) { if (iEntity && IsValidEntity(iEntity)) { @@ -2027,7 +2029,7 @@ stock bool:IsCommonInfected(iEntity) return false; } -stock bool:IsWitch(iEntity) +stock bool IsWitch(int iEntity) { if (iEntity && IsValidEntity(iEntity)) { @@ -2039,7 +2041,7 @@ stock bool:IsWitch(iEntity) return false; } -stock bool:IsTankRock(iEntity) +stock bool IsTankRock(int iEntity) { if (iEntity && IsValidEntity(iEntity)) { @@ -2051,53 +2053,53 @@ stock bool:IsTankRock(iEntity) return false; } -stock bool:isGhost(i) +stock bool isGhost(int i) { - return bool:GetEntProp(i, Prop_Send, "m_isGhost"); + return GetEntProp(i, Prop_Send, "m_isGhost") != 0; } -stock bool:isSpecialInfectedBot(i) +stock bool isSpecialInfectedBot(int i) { return i > 0 && i <= MaxClients && IsClientInGame(i) && IsFakeClient(i) && GetClientTeam(i) == 3; } -stock bool:isSurvivorBot(i) +stock bool isSurvivorBot(int i) { return isSurvivor(i) && IsFakeClient(i); } -stock bool:isInfected(i) +stock bool isInfected(int i) { return i > 0 && i <= MaxClients && IsClientInGame(i) && GetClientTeam(i) == 3 && !isGhost(i); } -stock bool:isSurvivor(i) +stock bool isSurvivor(int i) { return i > 0 && i <= MaxClients && IsClientInGame(i) && GetClientTeam(i) == 2; } -stock any:getZombieClass(client) +stock any getZombieClass(int client) { return GetEntProp(client, Prop_Send, "m_zombieClass"); } -stock bool:isIncapacitated(client) +stock bool isIncapacitated(int client) { return GetEntProp(client, Prop_Send, "m_isIncapacitated", 1) == 1; } -stock bool:isReloading(client) +stock bool isReloading(int client) { - new slot0 = GetPlayerWeaponSlot(client, 0); + int slot0 = GetPlayerWeaponSlot(client, 0); if (slot0 > -1) { return GetEntProp(slot0, Prop_Data, "m_bInReload") > 0; } return false; } -stock bool:isStagger(client) // Client Only +stock bool isStagger(int client) // Client Only { - new Float:staggerPos[3]; + float staggerPos[3]; GetEntPropVector(client, Prop_Send, "m_staggerStart", staggerPos); if (staggerPos[0] != 0.0 && staggerPos[1] != 0.0 && staggerPos[2] != 0.0) return true; @@ -2105,27 +2107,27 @@ stock bool:isStagger(client) // Client Only return false; } -stock bool:isJockeyLeaping(client) +stock bool isJockeyLeaping(int client) { - new Float:jockeyVelocity[3]; + float jockeyVelocity[3]; GetEntDataVector(client, g_Velo, jockeyVelocity); if (jockeyVelocity[2] != 0.0) return true; return false; } -stock bool:isHaveItem(const char[] FItem, const char[] SItem) +stock bool isHaveItem(const char[] FItem, const char[] SItem) { if (StrContains(FItem, SItem, false) > -1) return true; return false; } -stock UseItem(client, const char[] FItem) +stock void UseItem(int client, const char[] FItem) { FakeClientCommand(client, "use %s", FItem); } -stock any:PrimaryExtraAmmoCheck(client, weapon_index) +stock any PrimaryExtraAmmoCheck(int client, int weapon_index) { // Offset: // 12: Rifle ALL (Other than M60) @@ -2148,7 +2150,7 @@ stock any:PrimaryExtraAmmoCheck(client, weapon_index) else if (isHaveItem(sWeaponName, "weapon_sniper")) offset = 40; else if (isHaveItem(sWeaponName, "weapon_grenade_launcher")) offset = 68; - new extra_ammo = GetEntData(client, (g_iAmmoOffset + offset)); + int extra_ammo = GetEntData(client, (g_iAmmoOffset + offset)); //PrintToChatAll("%N Gun Name: %s, Offset: %i, ExtraAmmo: %i:", client, sWeaponName, offset, extra_ammo); return extra_ammo; @@ -2158,30 +2160,30 @@ stock any:PrimaryExtraAmmoCheck(client, weapon_index) --------------------------------------------------------------------------------------------------------------------------------------------------------------------- */ -public bool:traceFilter(entity, mask, any:self) +public bool traceFilter(int entity, int mask, any self) { return entity != self; } -public bool:TraceRayDontHitPlayers(entity, mask) +public bool TraceRayDontHitPlayers(int entity, int mask) { // Check if the beam hit a player and tell it to keep tracing if it did return (entity <= 0 || entity > MaxClients); } // Determine if the head of the target can be seen from the client -stock bool:isVisibleTo(client, target) +stock bool isVisibleTo(int client, int target) { - new bool:ret = false; - new Float:aim_angles[3]; - new Float:self_pos[3]; + bool ret = false; + float aim_angles[3]; + float self_pos[3]; GetClientEyePosition(client, self_pos); computeAimAngles(client, target, aim_angles); - new Handle:trace = TR_TraceRayFilterEx(self_pos, aim_angles, MASK_VISIBLE, RayType_Infinite, traceFilter, client); + Handle trace = TR_TraceRayFilterEx(self_pos, aim_angles, MASK_VISIBLE, RayType_Infinite, traceFilter, client); if (TR_DidHit(trace)) { - new hit = TR_GetEntityIndex(trace); + int hit = TR_GetEntityIndex(trace); if (hit == target) { ret = true; } @@ -2191,12 +2193,12 @@ stock bool:isVisibleTo(client, target) } /* Determine if the head of the entity can be seen from the client */ -stock bool:isVisibleToEntity(target, client) +stock bool isVisibleToEntity(int target, int client) { - new bool:ret = false; - new Float:aim_angles[3]; - new Float:self_pos[3], Float:target_pos[3]; - new Float:lookat[3]; + bool ret = false; + float aim_angles[3]; + float self_pos[3], target_pos[3]; + float lookat[3]; GetEntPropVector(target, Prop_Data, "m_vecAbsOrigin", target_pos); GetClientEyePosition(client, self_pos); @@ -2204,29 +2206,29 @@ stock bool:isVisibleToEntity(target, client) MakeVectorFromPoints(target_pos, self_pos, lookat); GetVectorAngles(lookat, aim_angles); - new Handle:trace = TR_TraceRayFilterEx(target_pos, aim_angles, MASK_VISIBLE, RayType_Infinite, traceFilter, target); + Handle trace = TR_TraceRayFilterEx(target_pos, aim_angles, MASK_VISIBLE, RayType_Infinite, traceFilter, target); if (TR_DidHit(trace)) { - new hit = TR_GetEntityIndex(trace); + int hit = TR_GetEntityIndex(trace); if (hit == client) { ret = true; } } - CloseHandle(trace); + delete trace; return ret; } /* From the client to the target's head, whether it is blocked by mesh */ -stock bool:isInterruptTo(client, target) +stock bool isInterruptTo(int client, int target) { - new bool:ret = false; - new Float:aim_angles[3]; - new Float:self_pos[3]; + bool ret = false; + float aim_angles[3]; + float self_pos[3]; GetClientEyePosition(client, self_pos); computeAimAngles(client, target, aim_angles); - new Handle:trace = TR_TraceRayFilterEx(self_pos, aim_angles, MASK_SOLID, RayType_Infinite, traceFilter, client); + int Handle trace = TR_TraceRayFilterEx(self_pos, aim_angles, MASK_SOLID, RayType_Infinite, traceFilter, client); if (TR_DidHit(trace)) { - new hit = TR_GetEntityIndex(trace); + int hit = TR_GetEntityIndex(trace); if (hit == target) { ret = true; } @@ -2236,11 +2238,11 @@ stock bool:isInterruptTo(client, target) } // Calculate the angles from client to target -stock computeAimAngles(client, target, Float:angles[3], type = 1) +stock void computeAimAngles(int client, int target, float angles[3], int type = 1) { - new Float:target_pos[3]; - new Float:self_pos[3]; - new Float:lookat[3]; + float target_pos[3]; + float self_pos[3]; + float lookat[3]; GetClientEyePosition(client, self_pos); switch (type) { diff --git a/scripting/l4d2_tank_priority.sp b/scripting/l4d2_tank_priority.sp new file mode 100644 index 0000000..8a636a0 --- /dev/null +++ b/scripting/l4d2_tank_priority.sp @@ -0,0 +1,107 @@ +#pragma semicolon 1 +#pragma newdecls required + +//#define DEBUG + +#define PLUGIN_VERSION "1.0" + +#include +#include +//#include + +public Plugin myinfo = +{ + name = "L4D2 Tank Priority", + author = "jackzmc", + description = "", + version = PLUGIN_VERSION, + url = "" +}; + +#define TANK_CLASS_ID 8 + +static int tankChooseVictimTicks[MAXPLAYERS+1]; //Per tank +static int totalTankDamage[MAXPLAYERS+1]; //Per survivor +static ArrayList clients; + +public void OnPluginStart() { + EngineVersion g_Game = GetEngineVersion(); + if(g_Game != Engine_Left4Dead && g_Game != Engine_Left4Dead2) { + SetFailState("This plugin is for L4D/L4D2 only."); + } + + clients = new ArrayList(2); + + HookEvent("player_hurt", Event_PlayerHurt); + HookEvent("tank_spawn", Event_TankSpawn); +} + + +public Action L4D2_OnChooseVictim(int attacker, int &curTarget) { + int class = GetEntProp(attacker, Prop_Send, "m_zombieClass"); + if(class != TANK_CLASS_ID) return Plugin_Continue; + + //Find a new victim + if(++tankChooseVictimTicks[attacker] >= 200) { + tankChooseVictimTicks[attacker] = 0; + clients.Clear(); + float tankPos[3], clientPos[3]; + GetClientAbsOrigin(attacker, tankPos); + + for(int i = 1; i <= MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) { + //If a player does less than 50 damage, and has green health add them to list + if(totalTankDamage[i] < 100 && GetClientHealth(i) > 40) { + GetClientAbsOrigin(i, clientPos); + float dist = GetVectorDistance(clientPos, tankPos); + // Only add targets who are far enough away from tank + if(dist > 5000.0) { + PrintToConsoleAll("Adding player %N to possible victim list. Dist=%f, Dmg=%d", i, dist, totalTankDamage[i]); + int index = clients.Push(i); + clients.Set(index, dist, 1); + } + } + } + } + + if(clients.Length == 0) return Plugin_Continue; + + clients.SortCustom(Sort_TankTargetter); + /*curTarget = clients.Get(0);*/ + PrintToConsoleAll("[TankPriority] Player Selected to target: %N", curTarget); + //TODO: Possibly clear totalTankDamage + //return Plugin_Changed; + } + return Plugin_Continue; +} + +int Sort_TankTargetter(int index1, int index2, Handle array, Handle hndl) { + int client1 = GetArrayCell(array, index1); + int client2 = GetArrayCell(array, index2); + float distance1 = GetArrayCell(array, index2, 0); + float distance2 = GetArrayCell(array, index2, 1); + /*500 units away, 0 damage vs 600 units away, 0 damage + -> target closest 500 + 500 units away, 10 damage, vs 600 units away 0 damage + 500 - 10 = 450 vs 600 + */ + return (totalTankDamage[client1] + RoundFloat(distance1)) - (totalTankDamage[client2] + RoundFloat(distance2)); +} + +public void Event_PlayerHurt(Event event, const char[] name, bool dontBroadcast) { + int victim = GetClientOfUserId(event.GetInt("userid")); + int attacker = GetClientOfUserId(event.GetInt("attacker")); + int dmg = event.GetInt("dmg_health"); + if(dmg > 0 && attacker > 0 && victim > 0 && IsFakeClient(victim) && GetEntProp(victim, Prop_Send, "m_zombieClass") == TANK_CLASS_ID) { + if(GetClientTeam(victim) == 3 && GetClientTeam(attacker) == 2) { + totalTankDamage[victim] += dmg; + } + } +} + +public void Event_TankSpawn(Event event, const char[] name, bool dontBroadcast) { + int tank = GetClientOfUserId(GetEventInt(event, "userid")); + if(tank > 0 && IsFakeClient(tank)) { + tankChooseVictimTicks[tank] = -20; + } +} \ No newline at end of file diff --git a/scripting/sm_player_notes.sp b/scripting/sm_player_notes.sp new file mode 100644 index 0000000..cd835d2 --- /dev/null +++ b/scripting/sm_player_notes.sp @@ -0,0 +1,291 @@ +#pragma semicolon 1 +#pragma newdecls required + +//#define DEBUG + +#define PLUGIN_VERSION "1.0" +#define MAX_PLAYER_HISTORY 25 + +#include +#include +//#include + +public Plugin myinfo = +{ + name = "Noob DB", + author = "jackzmc", + description = "", + version = PLUGIN_VERSION, + url = "" +}; + +static Database DB; +static char query[1024]; +static char reason[256]; +static int WaitingForNotePlayer; +static char menuNoteTarget[32]; + +enum struct PlayerData { + char id[32]; + char name[32]; +} + +static ArrayList lastPlayers; + +public void OnPluginStart() { + if(!SQL_CheckConfig("stats")) { + SetFailState("No database entry for 'stats'; no database to connect to."); + } + if(!ConnectDB()) { + SetFailState("Failed to connect to database."); + } + + lastPlayers = new ArrayList(sizeof(PlayerData)); + + HookEvent("player_disconnect", Event_PlayerDisconnect); + HookEvent("player_first_spawn", Event_FirstSpawn); + + RegAdminCmd("sm_note", Command_AddNote, ADMFLAG_KICK, "Add a note to a player"); + RegAdminCmd("sm_notes", Command_ListNotes, ADMFLAG_KICK, "List notes for a player"); + RegAdminCmd("sm_notedisconnected", Command_AddNoteDisconnected, ADMFLAG_KICK, "Add a note to any disconnected players"); +} + +public Action Command_AddNoteDisconnected(int client, int args) { + if(lastPlayers.Length == 0) { + ReplyToCommand(client, "No disconnected players recorded."); + return Plugin_Handled; + } + Menu menu = new Menu(Menu_Disconnected); + menu.SetTitle("Add Note For Disconnected"); + for(int i = lastPlayers.Length + 1; i >= 0; i--) { + PlayerData data; + lastPlayers.GetArray(i, data, sizeof(data)); + menu.AddItem(data.id, data.name); + } + menu.Display(client, 0); + return Plugin_Handled; +} + +public int Menu_Disconnected(Menu menu, MenuAction action, int client, int item) { + if (action == MenuAction_Select) { + menu.GetItem(item, menuNoteTarget, sizeof(menuNoteTarget)); + PrintToChat(client, "Enter a note for %s:", menuNoteTarget); + WaitingForNotePlayer = client; + } else if (action == MenuAction_End) + delete menu; +} + +public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs) { + if(WaitingForNotePlayer == client) { + WaitingForNotePlayer = 0; + static char buffer[32]; + GetClientAuthId(client, AuthId_Steam2, buffer, sizeof(buffer)); + DB.Format(query, sizeof(query), "INSERT INTO `notes` (steamid, markedBy, content) VALUES ('%s', '%s', '%s')", menuNoteTarget, buffer, sArgs); + DB.Query(DB_AddNote, query); + LogAction(client, -1, "\"%L\" added note for \"%s\": \"%s\"", client, menuNoteTarget, sArgs); + Format(buffer, sizeof(buffer), "%N: ", client); + ShowActivity2(client, buffer, "added a note for %s: \"%s\"", menuNoteTarget, sArgs); + return Plugin_Stop; + } + return Plugin_Continue; +} + +public Action Command_AddNote(int client, int args) { + if(args < 2) { + ReplyToCommand(client, "Syntax: sm_note "); + } else { + static char target_name[MAX_TARGET_LENGTH]; + GetCmdArg(1, target_name, sizeof(target_name)); + GetCmdArg(2, reason, sizeof(reason)); + + int target_list[MAXPLAYERS], target_count; + bool tn_is_ml; + if ((target_count = ProcessTargetString( + target_name, + client, + target_list, + 1, + COMMAND_FILTER_NO_MULTI, + target_name, + sizeof(target_name), + tn_is_ml)) <= 0 + ) { + ReplyToTargetError(client, target_count); + return Plugin_Handled; + } + static char auth[32]; + GetClientAuthId(target_list[0], AuthId_Steam2, auth, sizeof(auth)); + static char authMarker[32]; + if(client > 0) + GetClientAuthId(client, AuthId_Steam2, authMarker, sizeof(authMarker)); + DB.Format(query, sizeof(query), "INSERT INTO `notes` (steamid, markedBy, content) VALUES ('%s', '%s', '%s')", auth, authMarker, reason); + DB.Query(DB_AddNote, query); + LogAction(client, target_list[0], "\"%L\" added note for \"%L\": \"%s\"", client, target_list[0], reason); + ShowActivity(client, "added a note for \"%N\": \"%s\"", target_list[0], reason); + } + return Plugin_Handled; +} + +public Action Command_ListNotes(int client, int args) { + if(args < 1) { + ReplyToCommand(client, "Syntax: sm_notes "); + } else { + static char target_name[MAX_TARGET_LENGTH]; + GetCmdArg(1, target_name, sizeof(target_name)); + GetCmdArg(2, reason, sizeof(reason)); + + int target_list[MAXPLAYERS], target_count; + bool tn_is_ml; + if ((target_count = ProcessTargetString( + target_name, + client, + target_list, + 1, + COMMAND_FILTER_NO_MULTI, + target_name, + sizeof(target_name), + tn_is_ml)) <= 0 + ) { + ReplyToTargetError(client, target_count); + return Plugin_Handled; + } + static char auth[32]; + GetClientAuthId(target_list[0], AuthId_Steam2, auth, sizeof(auth)); + + DB.Format(query, sizeof(query), "SELECT notes.content, stats_users.last_alias FROM `notes` JOIN stats_users ON markedBy = stats_users.steamid WHERE notes.`steamid` = '%s'", auth); + ReplyToCommand(client, "Fetching notes..."); + DataPack pack = new DataPack(); + pack.WriteCell(GetClientUserId(client)); + pack.WriteCell(GetClientUserId(target_list[0])); + pack.WriteString(auth); + DB.Query(DB_ListNotesForPlayer, query, pack); + } + return Plugin_Handled; +} + +bool ConnectDB() { + static char error[255]; + DB = SQL_Connect("stats", true, error, sizeof(error)); + if (DB== null) { + LogError("Database error %s", error); + delete DB; + return false; + } else { + PrintToServer("Connected to database stats"); + SQL_LockDatabase(DB); + SQL_FastQuery(DB, "SET NAMES \"UTF8mb4\""); + SQL_UnlockDatabase(DB); + DB.SetCharset("utf8mb4"); + return true; + } +} + +public Action Event_FirstSpawn(Event event, const char[] name, bool dontBroadcast) { + int client = GetClientUserId(event.GetInt("userid")); + if(client > 0 && client <= MaxClients && !IsFakeClient(client)) { + static char auth[32]; + GetClientAuthId(client, AuthId_Steam2, auth, sizeof(auth)); + DB.Format(query, sizeof(query), "SELECT notes.content, stats_users.last_alias FROM `notes` JOIN stats_users ON markedBy = stats_users.steamid WHERE notes.`steamid` = '%s'", auth); + DB.Query(DB_FindNotes, query, GetClientUserId(client)); + } +} + +public Action Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast) { + if(!event.GetBool("bot")) { + PlayerData data; + event.GetString("networkid", data.id, sizeof(data.id)); + if(!StrEqual(data.id, "BOT")) { + if(!IsPlayerInHistory(data.id)) { + event.GetString("name", data.name, sizeof(data.name)); + lastPlayers.PushArray(data); + if(lastPlayers.Length > MAX_PLAYER_HISTORY) { + lastPlayers.Erase(0); + } + } + } + } +} + +bool IsPlayerInHistory(const char[] id) { + static PlayerData data; + for(int i = 0; i < lastPlayers.Length; i++) { + lastPlayers.GetArray(i, data, sizeof(data)); + if(StrEqual(data.id, id)) + return true; + } + return false; +} + +public void DB_FindNotes(Database db, DBResultSet results, const char[] error, any data) { + if(db == null || results == null) { + LogError("DB_FindNotes returned error: %s", error); + return; + } + //initialize variables + int client = GetClientOfUserId(data); + if(client && results.RowCount > 0) { + static char noteCreator[32]; + PrintChatToAdmins("Notes for %s", client); + while(results.FetchRow()) { + results.FetchString(0, reason, sizeof(reason)); + results.FetchString(1, noteCreator, sizeof(noteCreator)); + PrintChatToAdmins("%s: %s", noteCreator, reason); + } + } +} + + +public void DB_ListNotesForPlayer(Database db, DBResultSet results, const char[] error, DataPack pack) { + if(db == null || results == null) { + LogError("DB_ListNotesForPlayer returned error: %s", error); + return; + } + //initialize variables + static char auth[32]; + pack.Reset(); + int client = GetClientOfUserId(pack.ReadCell()); + int target = GetClientOfUserId(pack.ReadCell()); + pack.ReadString(auth, sizeof(auth)); + delete pack; + if(client > 0) { + if(results.RowCount > 0) { + if(target > 0) { + PrintToChat(client, "Notes for %N:", target); + } else { + PrintToChat(client, "Notes for %s:", auth); + } + char noteCreator[32]; + while(results.FetchRow()) { + results.FetchString(0, reason, sizeof(reason)); + results.FetchString(1, noteCreator, sizeof(noteCreator)); + PrintToChat(client, "%s: %s", noteCreator, reason); + } + } else { + if(target > 0) + PrintToChat(client, "No notes found for %N", target); + else + PrintToChat(client, "No notes found for %s", auth); + } + } +} + +public void DB_AddNote(Database db, DBResultSet results, const char[] error, any data) { + if(db == null || results == null) { + LogError("DB_AddNote returned error: %s", error); + return; + } +} + +stock void PrintChatToAdmins(const char[] format, any ...) { + char buffer[254]; + VFormat(buffer, sizeof(buffer), format, 2); + for(int i = 1; i < MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i)) { + AdminId admin = GetUserAdmin(i); + if(admin != INVALID_ADMIN_ID) { + PrintToChat(i, "%s", buffer); + } + } + } + PrintToServer("%s", buffer); +}