diff --git a/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt b/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt index 85f40c9..1f39ba8 100644 --- a/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt +++ b/cstrike/addons/sourcemod/gamedata/plugin.zombiereloaded.txt @@ -9,13 +9,6 @@ "Offsets" { - - "EyeAngles" - { - "windows" "206" - "linux" "207" - } - "TraceAttack" { "windows" "58" diff --git a/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt b/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt index e5f32e7..0ef27ce 100644 --- a/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt +++ b/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt @@ -848,6 +848,46 @@ "en" "Force ZTele" } + // =========================== + // AntiStick (module) + // =========================== + + // Commands + + "AntiStick command set width syntax" + { + "en" "Sets the width of a model's hull. (See zr_antistick_list_models) Usage: zr_antistick_set_width " + } + + "AntiStick command list models list" + { + "en" "Showing all players' model data...\n------------------------------------------------" + } + + "AntiStick command list models name" + { + "#format" "{1:s},{2:s},{3:f}" + "en" "Player Name: {1} | Model Name: {2} | Model Hull Width: {3}" + } + + "AntiStick command set width successful" + { + "#format" "{1:s},{2:f}" + "en" "Model hull width for model \"{1}\" has been changed to \"{2}.\"" + } + + "AntiStick command set width invalid model" + { + "#format" "{1:s}" + "en" "Invalid model/player specified: \"{1}\"" + } + + "AntiStick command set width invalid width" + { + "#format" "{1:f}" + "en" "Invalid model hull width specified: \"{1}\"" + } + // =========================== // Spawn Protect (module) // =========================== diff --git a/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg b/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg index f01ac0e..1002564 100644 --- a/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg +++ b/cstrike/cfg/sourcemod/zombiereloaded/zombiereloaded.cfg @@ -507,9 +507,9 @@ zr_ambientsounds_volume "0.8" // Default: "1" zr_antistick "1" -// Time between each check for stuck players. [Dependency: zr_antistick] -// Default: "0.5" -zr_antistick_interval "0.5" +// File to store antistick model hull data. [Dependency: zr_antistick] +// Default: "data/antistick.dat" +zr_antistick_file_path "data/antistick.dat" // ---------------------------------------------------------------------------- diff --git a/src/zombiereloaded.sp b/src/zombiereloaded.sp index 5e923d9..ed98428 100644 --- a/src/zombiereloaded.sp +++ b/src/zombiereloaded.sp @@ -135,7 +135,6 @@ public OnMapStart() RoundEndOnMapStart(); InfectOnMapStart(); SEffectsOnMapStart(); - AntiStickOnMapStart(); ZSpawnOnMapStart(); } @@ -161,6 +160,7 @@ public OnConfigsExecuted() InfectLoad(); VEffectsLoad(); SEffectsLoad(); + AntiStickLoad(); ClassLoad(); VolLoad(); @@ -183,6 +183,7 @@ public OnClientPutInServer(client) InfectClientInit(client); DamageClientInit(client); SEffectsClientInit(client); + AntiStickClientInit(client); SpawnProtectClientInit(client); RespawnClientInit(client); ZTeleClientInit(client); @@ -201,6 +202,7 @@ public OnClientDisconnect(client) WeaponsOnClientDisconnect(client); InfectOnClientDisconnect(client); DamageOnClientDisconnect(client); + AntiStickOnClientDisconnect(client); ZSpawnOnClientDisconnect(client); VolOnPlayerDisconnect(client); } diff --git a/src/zr/antistick.inc b/src/zr/antistick.inc index f6c3cf8..2e58be9 100644 --- a/src/zr/antistick.inc +++ b/src/zr/antistick.inc @@ -35,58 +35,58 @@ */ /** - * @section Offsets relating to player hull dimensions. -*/ -#define ANTISTICK_PLAYER_HULL_XY_OFFSET 32 -#define ANTISTICK_PLAYER_HULL_Z_OFFSET 12 -#define ANTISTICK_PLAYER_HULL_STACK_OFFSET 14 -/** - * @endsection -*/ + * Default player hull width. + */ +#define ANTISTICK_DEFAULT_HULL_WIDTH 32.0 /** - * Variable to store antistick offset value. + * Handle to keyvalue structure where data is stored. */ -new g_iToolsCollisionGroup; +new Handle:g_kvAntiStick = INVALID_HANDLE; /** - * Handle to keep track of AntiStickTimer. + * Stores "StartTouch" HookID's for each client. */ -new Handle:tAntiStick = INVALID_HANDLE; +new g_iStartTouchHookID[MAXPLAYERS + 1] = {-1, ...}; /** - * Find antistick-specific offsets here. + * List of components that make up the model's rectangular boundaries. + * + * F = Front + * B = Back + * L = Left + * R = Right + * U = Upper + * D = Down */ -AntiStickOnOffsetsFound() +enum AntiStickBoxBound { - // If offset "m_CollisionGroup" can't be found, then stop the plugin. - g_iToolsCollisionGroup = FindSendPropInfo("CBaseEntity", "m_CollisionGroup"); - if (g_iToolsCollisionGroup == -1) - { - LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Antistick, "Offsets", "Offset \"CBaseEntity::m_CollisionGroup\" was not found."); - } + BoxBound_FUR = 0, /** Front upper right */ + BoxBound_FUL, /** etc.. */ + BoxBound_FDR, + BoxBound_FDL, + BoxBound_BUR, + BoxBound_BUL, + BoxBound_BDR, + BoxBound_BDL, } - /** - * Map is starting. + * Create commands related to antistick here. */ -AntiStickOnMapStart() +AntiStickOnCommandsCreate() { - // Reset timer handle. - tAntiStick = INVALID_HANDLE; -} - -/** - * The round is starting. - */ -AntiStickOnRoundStart() -{ - // If timer is running, kill it. - if (tAntiStick != INVALID_HANDLE) - { - KillTimer(tAntiStick); - } + // Create public command to list model data. + RegConsoleCmd("zr_antistick_list_models", AntiStickListModelsCommand, "Lists all players and their model data in console. Usage: zr_antistick_list_models"); + // Create admin command to set model hull width. + RegAdminCmd("zr_antistick_set_width", AntiStickSetWidthCommand, ADMFLAG_GENERIC, "Sets the width of a model's hull. (See zr_antistick_list_models) Usage: zr_antistick_set_width "); +} + +/** + * Creates/loads antistick data file. + */ +AntiStickLoad() +{ // If antistick is disabled, then stop. new bool:antistick = GetConVarBool(g_hCvarsList[CVAR_ANTISTICK]); if (!antistick) @@ -94,118 +94,441 @@ AntiStickOnRoundStart() return; } - new Float:interval = GetConVarFloat(g_hCvarsList[CVAR_ANTISTICK_INTERVAL]); - tAntiStick = CreateTimer(interval, AntiStickTimer, _, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); + // Create antistick keyvalues if it hasn't been created yet. + if (g_kvAntiStick == INVALID_HANDLE) + { + g_kvAntiStick = CreateKeyValues("antistick"); + } + + // Initialize keyvalues. + if (!AntiStickLoadData()) + { + AntiStickSaveData(); + } +} + +/** + * Client is joining the server. + * + * @param client The client index. + */ +AntiStickClientInit(client) +{ + // Hook "StartTouch" and "EndTouch" on client. + g_iStartTouchHookID[client] = ZRTools_HookStartTouch(client, AntiStickStartTouch); +} + +/** + * Unhook StartTouch and EndTouch function on a client. + * + * @param client The client index. + */ +AntiStickOnClientDisconnect(client) +{ + // Unhook "StartTouch" callback, and reset variable. + if (g_iStartTouchHookID[client] != -1) + { + ZRTools_UnhookStartTouch(g_iStartTouchHookID[client]); + g_iStartTouchHookID[client] = -1; + } +} + +/** + * Load antistick data from file. + * + * @return True if loaded successfully, false if file wasn't found. + */ +stock bool:AntiStickLoadData() +{ + // Get cvar's path. + decl String:filepath[PLATFORM_MAX_PATH]; + GetConVarString(g_hCvarsList[CVAR_ANTISTICK_FILE_PATH], filepath, sizeof(filepath)); + + // Build full path in return string. + decl String:fullpath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, fullpath, PLATFORM_MAX_PATH, filepath); + + // Log action to game events. + LogEvent(false, LogType_Normal, LOG_GAME_EVENTS, LogModule_AntiStick, "Loaded Data", "Antistick data has been loaded from \"%s\"", fullpath); + + // Retrieve keyvalue data from a file, and store in server's memory. + KvRewind(g_kvAntiStick); + return FileToKeyValues(g_kvAntiStick, fullpath); +} + +/** + * Save antistick data to file. + */ +stock AntiStickSaveData() +{ + // Get cvar's path. + decl String:filepath[PLATFORM_MAX_PATH]; + GetConVarString(g_hCvarsList[CVAR_ANTISTICK_FILE_PATH], filepath, sizeof(filepath)); + + // Build full path in return string. + decl String:fullpath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, fullpath, PLATFORM_MAX_PATH, filepath); + + // Log action to game events. + LogEvent(false, LogType_Normal, LOG_GAME_EVENTS, LogModule_AntiStick, "Saved Data", "Antistick data has been saved to \"%s\"", fullpath); + + // Dump keyvalue structure into a file from the server's memory. + KvRewind(g_kvAntiStick); + KeyValuesToFile(g_kvAntiStick, fullpath); +} + +/** + * Get hull width on a client's model. (or return default) + * + * @param client The client index. + * @param model If a client index of 0 is given, this model is used. + */ +stock Float:AntiStickGetModelHullWidth(client, const String:model[] = "") +{ + decl String:clientmodel[PLATFORM_MAX_PATH]; + + if (ZRIsClientValid(client)) + { + // Get client's model. + GetClientModel(client, clientmodel, sizeof(clientmodel)); + } + else + { + // Copy given model to 'clientmodel.' + strcopy(clientmodel, sizeof(clientmodel), model); + } + + // Find model in antistick data. + KvRewind(g_kvAntiStick); + if (KvJumpToKey(g_kvAntiStick, clientmodel)) + { + // Return value from file. + return KvGetFloat(g_kvAntiStick, "hull_width", ANTISTICK_DEFAULT_HULL_WIDTH); + } + else + { + // Return default CS:S hull width. + return ANTISTICK_DEFAULT_HULL_WIDTH; + } +} + +/** + * Set hull width on a client's model. + * + * @param client The client index. + * @param model If a client index of 0 is given, this model is used. + * @param hull_width The width of the model hull. + */ +stock AntiStickSetModelHullWidth(client, const String:model[] = "", Float:hull_width) +{ + decl String:clientmodel[PLATFORM_MAX_PATH]; + + if (ZRIsClientValid(client)) + { + // Get client's model. + GetClientModel(client, clientmodel, sizeof(clientmodel)); + } + else + { + // Copy given model to 'clientmodel.' + strcopy(clientmodel, sizeof(clientmodel), model); + } + + // Replace "/" with "-" because a slash indicates a new level in keyvalues. + ReplaceString(clientmodel, sizeof(clientmodel), "/", "-"); + + // Find model in antistick data. + KvRewind(g_kvAntiStick); + + // Create key if it doesn't already exist. + KvJumpToKey(g_kvAntiStick, clientmodel, true); + + // Set value. + KvSetFloat(g_kvAntiStick, "hull_width", hull_width); +} + +/** + * Callback function for StartTouch. + * + * @param client The client index. + * @param entity The entity index of the entity being touched. + */ +public ZRTools_Action:AntiStickStartTouch(client, entity) +{ + // If client isn't in-game, then stop. + if (!IsClientInGame(client)) + { + return; + } + + // If client is touching themselves, then leave them alone :P + if (client == entity) + { + return; + } + + // If touched entity isn't a valid client, then stop. + if (!ZRIsClientValid(entity)) + { + return; + } + + // If the clients aren't colliding, then stop. + if (!AntiStickIsModelBoxColliding(client, entity)) + { + return; + } + + // Disable collisions to unstick, and start timers to re-solidify. + if (AntiStickClientCollisionGroup(client) == ANTISTICK_COLLISIONS_ON) + { + AntiStickClientCollisionGroup(client, true, ANTISTICK_COLLISIONS_OFF); + CreateTimer(0.0, AntiStickSolidifyTimer, client, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT); + } + + if (AntiStickClientCollisionGroup(entity) == ANTISTICK_COLLISIONS_ON) + { + AntiStickClientCollisionGroup(entity, true, ANTISTICK_COLLISIONS_OFF); + CreateTimer(0.0, AntiStickSolidifyTimer, entity, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT); + } +} + +/** + * Callback function for EndTouch. + * + * @param client The client index. + * @param entity The entity index of the entity being touched. + */ +public Action:AntiStickSolidifyTimer(Handle:timer, any:client) +{ + // If client has left, then stop the timer. + if (!IsClientInGame(client)) + { + return Plugin_Stop; + } + + // If the client's collisions are already on, then stop. + if (AntiStickClientCollisionGroup(client) == ANTISTICK_COLLISIONS_ON) + { + return Plugin_Stop; + } + + // Loop through all client's and check if client is stuck in them. + for (new x = 1; x <= MaxClients; x++) + { + // Don't compare the same clients. + if (client == x) + { + continue; + } + + // If client isn't in-game, then stop. + if (!IsClientInGame(x)) + { + continue; + } + + // If the client is colliding with a client, then allow timer to continue. + if (AntiStickIsModelBoxColliding(client, x)) + { + return Plugin_Continue; + } + } + + // Change collisions back to normal. + AntiStickClientCollisionGroup(client, true, ANTISTICK_COLLISIONS_ON); + + return Plugin_Stop; +} + +/** + * Build the model box by finding all vertices. + * + * @param client The client index. + * @param boundaries Array with 'AntiStickBoxBounds' for indexes to return bounds into. + * @param width The width of the model box. + */ +stock AntiStickBuildModelBox(client, Float:boundaries[AntiStickBoxBound][3], Float:width) +{ + new Float:clientloc[3]; + new Float:twistang[3]; + new Float:cornerang[3]; + new Float:sideloc[3]; + new Float:finalloc[4][3]; + + // Get needed vector info. + GetClientAbsOrigin(client, clientloc); + + // Set the pitch to 0. + twistang[1] = 90.0; + cornerang[1] = 0.0; + + for (new x = 0; x < 4; x++) + { + // Jump to point on player's left side. + AntiStickJumpToPoint(clientloc, twistang, width / 2, sideloc); + + // From this point, jump to the corner, which would be half the width from the middle of a side. + AntiStickJumpToPoint(sideloc, cornerang, width / 2, finalloc[x]); + + // Twist 90 degrees to find next side/corner. + twistang[1] += 90.0; + cornerang[1] += 90.0; + + // Fix angles. + if (twistang[1] > 180.0) + { + twistang[1] -= 360.0; + } + + if (cornerang[1] > 180.0) + { + cornerang[1] -= 360.0; + } + } + + // Copy all horizontal model box data to array. + boundaries[BoxBound_FUR][0] = finalloc[3][0]; + boundaries[BoxBound_FUR][1] = finalloc[3][1]; + boundaries[BoxBound_FUL][0] = finalloc[0][0]; + boundaries[BoxBound_FUL][1] = finalloc[0][1]; + boundaries[BoxBound_FDR][0] = finalloc[3][0]; + boundaries[BoxBound_FDR][1] = finalloc[3][1]; + boundaries[BoxBound_FDL][0] = finalloc[0][0]; + boundaries[BoxBound_FDL][1] = finalloc[0][1]; + boundaries[BoxBound_BUR][0] = finalloc[2][0]; + boundaries[BoxBound_BUR][1] = finalloc[2][1]; + boundaries[BoxBound_BUL][0] = finalloc[1][0]; + boundaries[BoxBound_BUL][1] = finalloc[1][1]; + boundaries[BoxBound_BDR][0] = finalloc[2][0]; + boundaries[BoxBound_BDR][1] = finalloc[2][1]; + boundaries[BoxBound_BDL][0] = finalloc[1][0]; + boundaries[BoxBound_BDL][1] = finalloc[1][1]; + + // Set Z bounds. + new Float:eyeloc[3]; + GetClientEyePosition(client, eyeloc); + + boundaries[BoxBound_FUR][2] = eyeloc[2] / 1.1; // Scale box down a bit to prevent weird false triggers. + boundaries[BoxBound_FUL][2] = eyeloc[2] / 1.1; + boundaries[BoxBound_FDR][2] = clientloc[2] + 3.0; // Raise this a hair up to be safe. + boundaries[BoxBound_FDL][2] = clientloc[2] + 3.0; + boundaries[BoxBound_BUR][2] = eyeloc[2] / 1.1; + boundaries[BoxBound_BUL][2] = eyeloc[2] / 1.1; + boundaries[BoxBound_BDR][2] = clientloc[2] + 3.0; + boundaries[BoxBound_BDL][2] = clientloc[2] + 3.0; +} + +/** + * Jumps from a point to another based off angle and distance. + * + * @param vec Point to jump from. + * @param ang Angle to base jump off of. + * @param distance Distance to jump + * @param result Resultant point. + */ +stock AntiStickJumpToPoint(const Float:vec[3], const Float:ang[3], Float:distance, Float:result[3]) +{ + new Float:viewvec[3]; + + // Turn client angle, into a vector. + GetAngleVectors(ang, viewvec, NULL_VECTOR, NULL_VECTOR); + + // Normalize vector. + NormalizeVector(viewvec, viewvec); + + // Scale to the given distance. + ScaleVector(viewvec, distance); + + // Add the vectors together. + AddVectors(vec, viewvec, result); +} + +/** + * Get the max/min value of a 3D box on any axis. + * + * @param axis The axis to check. + * @param boundaries The boundaries to check. + * @param min Return the min value instead. + */ +stock Float:AntiStickGetBoxMaxBoundary(axis, Float:boundaries[AntiStickBoxBound][3], bool:min = false) +{ + // Create 'outlier' with initial value of first boundary. + new Float:outlier = boundaries[0][axis]; + + // x = Boundary index. (Start at 1 because we initialized 'outlier' with the 0 index's value) + new size = sizeof(boundaries); + for (new x = 1; x < size; x++) + { + if (!min && boundaries[x][axis] > outlier) + { + outlier = boundaries[x][axis]; + } + else if (min && boundaries[x][axis] < outlier) + { + outlier = boundaries[x][axis]; + } + } + + // Return value. + return outlier; } /** * Checks if a player is currently stuck within another player. * - * @param client The client index. - * @return The client index of the other stuck player, -1 when - * player is not stuck. + * @param client1 The first client index. + * @param client2 The second client index. + * @return True if they are stuck together, false if not. */ -AntiStickIsStuck(client) +stock bool:AntiStickIsModelBoxColliding(client1, client2) { - new Float:clientloc[3]; - new Float:stuckloc[3]; + new Float:client1modelbox[AntiStickBoxBound][3]; + new Float:client2modelbox[AntiStickBoxBound][3]; - GetClientAbsOrigin(client, clientloc); + // Get model hull widths. + new Float:hull_width1 = AntiStickGetModelHullWidth(client1); + new Float:hull_width2 = AntiStickGetModelHullWidth(client2); - // x = client index. - for (new x = 1; x <= MaxClients; x++) + // Build model boxes for each client. + AntiStickBuildModelBox(client1, client1modelbox, hull_width1); + AntiStickBuildModelBox(client2, client2modelbox, hull_width2); + + // Compare x values. + new Float:max1x = AntiStickGetBoxMaxBoundary(0, client1modelbox); + new Float:max2x = AntiStickGetBoxMaxBoundary(0, client2modelbox); + new Float:min1x = AntiStickGetBoxMaxBoundary(0, client1modelbox, true); + new Float:min2x = AntiStickGetBoxMaxBoundary(0, client2modelbox, true); + + if (max1x < min2x || min1x > max2x) { - // Validate player is in-game, alive, and isn't the player being checked. ('client') - if (!IsClientInGame(x) || !IsPlayerAlive(x) || x == client) - { - continue; - } - - GetClientAbsOrigin(x, stuckloc); - - // x-y plane distance formula: sqrt((x2-x1)^2 + (y2-y1)^2) - new Float:xydistance = SquareRoot(Pow(stuckloc[0] - clientloc[0], 2.0) + Pow(stuckloc[1] - clientloc[1], 2.0)); - if (xydistance < ANTISTICK_PLAYER_HULL_XY_OFFSET) - { - if (clientloc[2] <= stuckloc[2]) - { - new Float:eyeloc[3]; - GetClientEyePosition(client, eyeloc); - - // Get the distance between the eyes and feet and subtract the stack "view crush." - new Float:eyedistance = FloatAbs(eyeloc[2] - clientloc[2]) - ANTISTICK_PLAYER_HULL_STACK_OFFSET; - new Float:zdistance = FloatAbs(stuckloc[2] - clientloc[2]); - - if (zdistance <= eyedistance + ANTISTICK_PLAYER_HULL_Z_OFFSET) - { - return x; - } - } - } + return false; } - return -1; -} - -/** - * Timer callback, automatically unsticks players that are stuck together. - */ -public Action:AntiStickTimer(Handle:timer) -{ - // x = client index - for (new x = 1; x <= MaxClients; x++) + // Compare y values. + new Float:max1y = AntiStickGetBoxMaxBoundary(1, client1modelbox); + new Float:max2y = AntiStickGetBoxMaxBoundary(1, client2modelbox); + new Float:min1y = AntiStickGetBoxMaxBoundary(1, client1modelbox, true); + new Float:min2y = AntiStickGetBoxMaxBoundary(1, client2modelbox, true); + + if (max1y < min2y || min1y > max2y) { - // Validate player is in-game and alive. - if (!IsClientInGame(x) || !IsPlayerAlive(x)) - { - continue; - } - - // Stop if the player isn't stuck. - new stuckindex = AntiStickIsStuck(x); - if (stuckindex == -1) - { - continue; - } - - if (AntiStickClientCollisionGroup(x, false) == ANTISTICK_COLLISIONS_ON) - { - AntiStickClientCollisionGroup(x, true, ANTISTICK_COLLISIONS_OFF); - CreateTimer(0.5, AntiStickSolidify, x, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); - } - - if (AntiStickClientCollisionGroup(stuckindex, false) == ANTISTICK_COLLISIONS_ON) - { - AntiStickClientCollisionGroup(stuckindex, true, ANTISTICK_COLLISIONS_OFF); - CreateTimer(0.5, AntiStickSolidify, stuckindex, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); - } - } -} - -/** - * Repeated timer function. - * Re-solidifies a player being unstuck. - * - * @param timer The timer handle. - * @param client The client index. - */ -public Action:AntiStickSolidify(Handle:timer, any:client) -{ - // Validate player is in-game, alive, and is being unstuck. - if (!IsClientInGame(client) || !IsPlayerAlive(client) || AntiStickClientCollisionGroup(client, false) == ANTISTICK_COLLISIONS_ON) - { - return Plugin_Stop; + return false; } - // Stop if the player is still stuck. - if (AntiStickIsStuck(client) > -1) + // Compare z values. + new Float:max1z = AntiStickGetBoxMaxBoundary(2, client1modelbox); + new Float:max2z = AntiStickGetBoxMaxBoundary(2, client2modelbox); + new Float:min1z = AntiStickGetBoxMaxBoundary(2, client1modelbox, true); + new Float:min2z = AntiStickGetBoxMaxBoundary(2, client2modelbox, true); + + if (max1z < min2z || min1z > max2z) { - return Plugin_Continue; + return false; } - AntiStickClientCollisionGroup(client, true, ANTISTICK_COLLISIONS_ON); - - return Plugin_Stop; + // They are intersecting. + return true; } /** @@ -214,14 +537,107 @@ public Action:AntiStickSolidify(Handle:timer, any:client) * @param collisiongroup Collision group flag. * @return The collision group on the client, -1 if applying collision group. */ -AntiStickClientCollisionGroup(client, bool:apply = true, collisiongroup = 0) +AntiStickClientCollisionGroup(client, bool:apply = false, collisiongroup = 0) { if (apply) { - SetEntData(client, g_iToolsCollisionGroup, collisiongroup, 1, true); + SetEntProp(client, Prop_Data, "m_CollisionGroup", collisiongroup); return -1; } - return GetEntData(client, g_iToolsCollisionGroup, 1); + return GetEntProp(client, Prop_Data, "m_CollisionGroup"); } + +/** + * Command callback (zr_antistick_list_models) + * Lists all player's models and model hull data. + * + * @param client The client index. + * @param argc Argument count. + */ +public Action:AntiStickListModelsCommand(client, argc) +{ + // Tell client we are listing model data. + TranslationPrintToConsole(client, "AntiStick command list models list"); + + decl String:clientname[MAX_NAME_LENGTH]; + decl String:modelname[PLATFORM_MAX_PATH]; + new Float:hull_width; + + // x = Client index. + for (new x = 1; x <= MaxClients; x++) + { + // If client isn't in-game, then stop. + if (!IsClientInGame(x)) + { + continue; + } + + // Get all needed data. + GetClientName(x, clientname, sizeof(clientname)); + GetClientModel(x, modelname, sizeof(modelname)); + hull_width = AntiStickGetModelHullWidth(x); + + TranslationPrintToConsole(client, "AntiStick command list models name", clientname, modelname, hull_width); + } + + return Plugin_Handled; +} + +/** + * Command callback (zr_antistick_set_width) + * Set the hull width on any model. + * + * @param client The client index. + * @param argc Argument count. + */ +public Action:AntiStickSetWidthCommand(client, argc) +{ + // If not enough arguments given, then stop. + if (argc < 2) + { + TranslationReplyToCommand(client, "AntiStick command set width syntax"); + return Plugin_Handled; + } + + // Get target model. + decl String:model[PLATFORM_MAX_PATH]; + GetCmdArg(1, model, sizeof(model)); + + // If model doesn't exist, then stop. + if (!FileExists(model)) + { + new target = FindTarget(client, model); + if (target <= 0) + { + TranslationReplyToCommand(client, "AntiStick command set width invalid model", model); + return Plugin_Handled; + } + else + { + // Get the target's model. + GetClientModel(target, model, sizeof(model)); + } + } + + // Get the given hull width.. + decl String:strHullwidth[PLATFORM_MAX_PATH]; + GetCmdArg(2, strHullwidth, sizeof(strHullwidth)); + + new Float:hull_width = StringToFloat(strHullwidth); + if (hull_width <= 0.0) + { + TranslationReplyToCommand(client, "AntiStick command set width invalid width", hull_width); + return Plugin_Handled; + } + + // Set hull width. + AntiStickSetModelHullWidth(0, model, hull_width); + + // Save data. + AntiStickSaveData(); + + return Plugin_Handled; +} + \ No newline at end of file diff --git a/src/zr/commands.inc b/src/zr/commands.inc index 7e6fdbc..7c97b35 100644 --- a/src/zr/commands.inc +++ b/src/zr/commands.inc @@ -39,6 +39,7 @@ CommandsInit() InfectOnCommandsCreate(); MenuOnCommandsCreate(); ZAdminOnCommandsCreate(); + AntiStickOnCommandsCreate(); ZCookiesOnCommandsCreate(); ZSpawnOnCommandsCreate(); ZTeleOnCommandsCreate(); @@ -48,201 +49,4 @@ CommandsInit() // Forward event to modules. (hook commands) ClassOnCommandsHook(); DamageOnCommandsHook(); -} - -/*CreateCommands() -{ - RegAdminCmd("zr_infect", Command_Infect, ADMFLAG_GENERIC, "Infects the specified player"); - RegAdminCmd("zr_spawn", Command_Respawn, ADMFLAG_GENERIC, "Respawns the specified player following auto-respawning rules"); - - - //RegAdminCmd("zr_set_class_knockback", Command_SetClassKnockback, ADMFLAG_GENERIC, "Sets the knockback to the specified class. Usage: zr_set_class_knockback "); - //RegAdminCmd("zr_get_class_knockback", Command_GetClassKnockback, ADMFLAG_GENERIC, "Gets the knockback to the specified class. Usage: zr_get_class_knockback "); - - RegAdminCmd("zr_admin", Command_AdminMenu, ADMFLAG_GENERIC, "Displays the admin menu for Zombie: Reloaded."); - //RegAdminCmd("zr_knockback_m", Command_KnockbackMMenu, ADMFLAG_GENERIC, "Displays the knockback multiplier menu."); - - RegAdminCmd("zr_anticamp_create_volume", Command_AnticampCreateVolume, ADMFLAG_GENERIC, "Creates a rectangular hurt volume between two points. Usage: ht_create_volume "); - RegAdminCmd("zr_anticamp_remove_volume", Command_AnticampRemoveVolume, ADMFLAG_GENERIC, "Removes a volume. Use zr_anticamp_list to list volumes. Usage: zr_anticamp_remove_volume "); - RegAdminCmd("zr_anticamp_list", Command_AnticampList, ADMFLAG_GENERIC, "List current volumes."); - - RegConsoleCmd("zr_log_flags", Command_LogFlags, "List available logging flags."); -}*/ - -/*public Action:Command_Infect(client, argc) -{ - new bool:enabled = GetConVarBool(g_hCvarsList[CVAR_ENABLE]); - if (argc < 1 || !enabled) - { - return Plugin_Handled; - } - - decl String:arg1[32]; - GetCmdArg(1, arg1, sizeof(arg1)); - - decl String:target_name_list[MAX_TARGET_LENGTH]; - new targets[MAXPLAYERS]; - new bool:tn_is_ml; - - new tcount = ProcessTargetString(arg1, client, targets, MAXPLAYERS, COMMAND_FILTER_ALIVE, target_name_list, sizeof(target_name_list), tn_is_ml); - if (tcount <= 0) - { - ReplyToTargetError(client, tcount); - return Plugin_Handled; - } - - decl String:target_name[64]; - decl String:client_name[64]; - - if (client > 0) - { - GetClientName(client, client_name, sizeof(client_name)); - } - else - { - client_name = "Console\0"; - } - - for (new x = 0; x < tcount; x++) - { - InfectHumanToZombie(targets[x]); - if (LogCheckFlag(LOG_GAME_EVENTS, LOG_MODULE_COMMANDS)) - { - GetClientName(targets[x], target_name, sizeof(target_name)); - LogMessageFormatted(client, "admin commands", "infect", "\"%s\" infected \"%s\".", true, client_name, target_name); - } - } - - return Plugin_Handled; -} - -public Action:Command_Respawn(client, argc) -{ - new bool:enabled = GetConVarBool(g_hCvarsList[CVAR_ENABLE]); - if (argc < 1 || !enabled) - { - return Plugin_Handled; - } - - decl String:arg1[32]; - GetCmdArg(1, arg1, sizeof(arg1)); - - decl String:target_name_list[MAX_TARGET_LENGTH]; - new targets[MAXPLAYERS]; - new bool:tn_is_ml; - - new tcount = ProcessTargetString(arg1, client, targets, MAXPLAYERS, COMMAND_FILTER_DEAD, target_name_list, sizeof(target_name_list), tn_is_ml); - if (tcount <= 0) - { - ReplyToTargetError(client, tcount); - return Plugin_Handled; - } - - decl String:client_name[64]; - decl String:target_name[64]; - - if (client > 0) - { - GetClientName(client, client_name, sizeof(client_name)); - } - else - { - client_name = "Console\0"; - } - - new team; - for (new x = 0; x < tcount; x++) - { - team = GetClientTeam(targets[x]); - if (team == CS_TEAM_T || team == CS_TEAM_CT) - { - if (LogCheckFlag(LOG_GAME_EVENTS, LOG_MODULE_COMMANDS)) - { - GetClientName(targets[x], target_name, sizeof(target_name)); - LogMessageFormatted(targets[x], "admin commands", "spawn", "\"%s\" spawned player \"%s\".", true, client_name, target_name); - } - - RespawnSpawnClient(targets[x]); - } - } - - return Plugin_Handled; -}*/ - -/*public Action:Command_AdminMenu(client, argc) -{ - if (ZRIsClientValid(client)) - { - ZAdminMenu(client); - } - else - { - // BAD! - // ReplyToCommand(client, "This menu cannot be used from the console."); - } - return Plugin_Handled; -} - -public Action:Command_KnockbackMMenu(client, argc) -{ - if (ZRIsClientValid(client)) - { - // Disabled, under construction. - // ZRKnockbackMMenu(client); - } - else - { - // Tsk tsk no translation? :P - //ReplyToCommand(client, "This menu cannot be used from the console."); - } - return Plugin_Handled; -} - -public Action:Command_TeleMenu(client, argc) -{ - if (ZRIsClientValid(client)) - { - ZRZTeleMenu(client); - } - else - { - // BAD! - ReplyToCommand(client, "This menu cannot be used from the console."); - } - return Plugin_Handled; -} - -public Action:Command_LogFlags(client, argc) -{ - decl String:message[2048]; - message[0] = 0; - - StrCat(message, sizeof(message), "LOG_CORE_EVENTS (1) - Log core events like executing files, error messages, etc.\n"); - StrCat(message, sizeof(message), "LOG_GAME_EVENTS (2) - Log game events like admin commands, suicide prevention and anticamp kills.\n"); - StrCat(message, sizeof(message), "LOG_PLAYER_COMMANDS (4) - Log commands made by the player.\n"); - StrCat(message, sizeof(message), "LOG_DEBUG (8) - Enable debug messages (if they exist).\n"); - StrCat(message, sizeof(message), "LOG_DEBUG_DETAIL (16) - Detailed debug messages. May cause spam.\n"); - StrCat(message, sizeof(message), "LOG_DEBUG_MAX_DETAIL (32) - Low level detailed debug messages. Causes spam! Only enable right before and after testing.\n"); - StrCat(message, sizeof(message), "LOG_LOG_TO_ADMINS (64) - Display log messages to admin chat.\n"); - StrCat(message, sizeof(message), "LOG_LOG_TO_CLIENT (128) - Display log messages to the client that executed the event/command.\n"); - StrCat(message, sizeof(message), "LOG_IGNORE_CONSOLE (256) - Don't log messages from client 0 (console).\n"); - StrCat(message, sizeof(message), "LOG_MODULES_ENABLED (512) - Enable detailed log control for developers. Module logs overrides previous flags.\n"); - StrCat(message, sizeof(message), "LOG_MODULE_ZOMBIE (1024) - zombie.inc"); - - ReplyToCommand(client, message); - message[0] = 0; - - StrCat(message, sizeof(message), "LOG_MODULE_AMBIENTSOUNDS (2048) - ambientsounds.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_OVERLAYS (4096) - overlays.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_SAYTRIGGERS (8192) - sayhooks.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_TELEPORT (16384) - teleport.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_CLASSES (32768) - classes.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_WEAPONRESTICT (65536) - weaponrestrict.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_COMMANDS (131072) - commands.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_ANTICAMP (262144) - anticamp.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_DAMAGE (524288) - damage.inc\n"); - StrCat(message, sizeof(message), "LOG_MODULE_OFFSETS (524288) - offsets.inc"); - - ReplyToCommand(client, message); - return Plugin_Handled; -}*/ +} \ No newline at end of file diff --git a/src/zr/cvars.inc b/src/zr/cvars.inc index c6fa464..58dad9d 100644 --- a/src/zr/cvars.inc +++ b/src/zr/cvars.inc @@ -126,7 +126,7 @@ enum CvarsList Handle:CVAR_AMBIENTSOUNDS_LENGTH, Handle:CVAR_AMBIENTSOUNDS_VOLUME, Handle:CVAR_ANTISTICK, - Handle:CVAR_ANTISTICK_INTERVAL, + Handle:CVAR_ANTISTICK_FILE_PATH, Handle:CVAR_SPAWNPROTECT, Handle:CVAR_SPAWNPROTECT_TIME, Handle:CVAR_SPAWNPROTECT_SPEED, @@ -387,8 +387,8 @@ CvarsCreate() // =========================== // Anti-Stick (module) // =========================== - g_hCvarsList[CVAR_ANTISTICK] = CreateConVar("zr_antistick", "1", "Automatically unstick players when stuck within each others' collision hull."); - g_hCvarsList[CVAR_ANTISTICK_INTERVAL] = CreateConVar("zr_antistick_interval", "0.5", "Time between each check for stuck players. [Dependency: zr_antistick]"); + g_hCvarsList[CVAR_ANTISTICK] = CreateConVar("zr_antistick", "1", "Automatically unstick players when stuck within each others' collision hull."); + g_hCvarsList[CVAR_ANTISTICK_FILE_PATH] = CreateConVar("zr_antistick_file_path", "data/antistick.dat", "File to store antistick model hull data. [Dependency: zr_antistick]"); // =========================== // Spawn Protect (module) diff --git a/src/zr/event.inc b/src/zr/event.inc index 40fc65c..40aa674 100644 --- a/src/zr/event.inc +++ b/src/zr/event.inc @@ -87,7 +87,6 @@ public Action:EventRoundStart(Handle:event, const String:name[], bool:dontBroadc RoundEndOnRoundStart(); InfectOnRoundStart(); SEffectsOnRoundStart(); - AntiStickOnRoundStart(); ZSpawnOnRoundStart(); VolOnRoundStart(); diff --git a/src/zr/knockback.inc b/src/zr/knockback.inc index 0cf2edd..e1b9cab 100644 --- a/src/zr/knockback.inc +++ b/src/zr/knockback.inc @@ -78,7 +78,7 @@ KnockbackOnClientHurt(client, attacker, const String:weapon[], hitgroup, dmg_hea // Get attackers eye angles. new Float:attackerang[3]; - KnockbackGetClientEyeAngles(attacker, attackerang); + GetClientEyeAngles(attacker, attackerang); // Calculate knockback end-vector. TR_TraceRayFilter(attackerloc, attackerang, MASK_ALL, RayType_Infinite, KnockbackTRFilter); @@ -198,15 +198,4 @@ KnockbackFindExplodingGrenade(Float:heLoc[3]) // Didn't find the grenade. return -1; -} - -/** - * Get client's eye angles. - * - * @param client The client index. - * @param vecAngles The angle vector of the client's eyes. - */ -KnockbackGetClientEyeAngles(client, Float:vecAngles[3]) -{ - SDKCall(g_hToolsEyeAngles, client, vecAngles); -} +} \ No newline at end of file diff --git a/src/zr/log.h.inc b/src/zr/log.h.inc index b6ce517..2b29a71 100644 --- a/src/zr/log.h.inc +++ b/src/zr/log.h.inc @@ -70,7 +70,7 @@ enum LogModules bool:LogModule_Invalid = 0, /** Used as return value when an error occoured.*/ bool:LogModule_Account, - bool:LogModule_Antistick, + bool:LogModule_AntiStick, bool:LogModule_Config, bool:LogModule_Cvars, bool:LogModule_Damage, diff --git a/src/zr/log.inc b/src/zr/log.inc index 8ab6d71..77d9e19 100644 --- a/src/zr/log.inc +++ b/src/zr/log.inc @@ -59,7 +59,7 @@ LogGetModuleNameString(String:buffer[], maxlen, LogModules:module, bool:shortNam { return shortName ? strcopy(buffer, maxlen, "account") : strcopy(buffer, maxlen, "Account"); } - case LogModule_Antistick: + case LogModule_AntiStick: { return shortName ? strcopy(buffer, maxlen, "antistick") : strcopy(buffer, maxlen, "Anti-Stick"); } @@ -148,7 +148,7 @@ LogModules:LogGetModule(const String:moduleName[]) } else if (StrEqual(moduleName, "antistick", false)) { - return LogModule_Antistick; + return LogModule_AntiStick; } else if (StrEqual(moduleName, "config", false)) { diff --git a/src/zr/tools.inc b/src/zr/tools.inc index d630172..38c5d39 100644 --- a/src/zr/tools.inc +++ b/src/zr/tools.inc @@ -42,7 +42,6 @@ new g_iToolsDefaultFOV; * Initialize global SDKTools handles. */ new Handle:g_hToolsGameConfig = INVALID_HANDLE; -new Handle:g_hToolsEyeAngles = INVALID_HANDLE; new Handle:g_hToolsTerminateRound = INVALID_HANDLE; new Handle:g_hToolsCSWeaponDrop = INVALID_HANDLE; /** @@ -108,7 +107,6 @@ ToolsFindOffsets() WeaponsOnOffsetsFound(); AccountOnOffsetsFound(); VEffectsOnOffsetsFound(); - AntiStickOnOffsetsFound(); ZMarketOnOffsetsFound(); } @@ -126,18 +124,6 @@ ToolsSetupGameData() LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Tools, "GameData", "Can't load game config file (plugin.zombiereloaded.txt) from the gamedata directory."); } - // Prep the SDKCall for "EyeAngles." - StartPrepSDKCall(SDKCall_Player); - PrepSDKCall_SetFromConf(g_hToolsGameConfig, SDKConf_Virtual, "EyeAngles"); - PrepSDKCall_SetReturnInfo(SDKType_QAngle, SDKPass_ByValue); - g_hToolsEyeAngles = EndPrepSDKCall(); - - // If offset "EyeAngles" can't be found, then stop the plugin. - if(g_hToolsEyeAngles == INVALID_HANDLE) - { - LogEvent(false, LogType_Fatal, LOG_CORE_EVENTS, LogModule_Tools, "GameData", "Offset \"EyeAngles\" was not found."); - } - // Prep the SDKCall for "TerminateRound." StartPrepSDKCall(SDKCall_GameRules); PrepSDKCall_SetFromConf(g_hToolsGameConfig, SDKConf_Signature, "TerminateRound");