diff --git a/README.md b/README.md index da732f0..4c34957 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ The radar uses SourceMod's HUD text functionality for rendering, making it a lig 3. **Player Position Calculation**: For each update, the plugin: - Gets the position and angle of the player - - Calculates the relative positions of all teammates + - Calculates the relative positions/health of all teammates 4. **Radar Display**: The plugin then: - Creates a radar background in the top-left corner of the screen @@ -37,6 +37,11 @@ The radar uses SourceMod's HUD text functionality for rendering, making it a lig - Teammate dots change color based on health: - Green: Above 50% health - Red: 50% health or below +- Ping System: Players can mark locations on the radar for their teammates + - Use `!mapping` or `sm_mapping` to ping the location you're looking at, ideally use `bind "say /mapping"`. + - Pings appear as yellow exclamation marks (!) on the radar + - Pings last for 5 seconds and have a 3-second cooldown + ## Requirements @@ -55,7 +60,7 @@ The radar uses SourceMod's HUD text functionality for rendering, making it a lig 2. Edit these commented lines: ``` -// Customizable settings +// Core settings #define UPDATE_INTERVAL 0.1 // How often the radar updates (in seconds) #define RADAR_SIZE 2560.0 // The in-game units the radar covers #define RADAR_SCALE 0.225 // The size of the radar on the screen (0-1) @@ -68,6 +73,11 @@ The radar uses SourceMod's HUD text functionality for rendering, making it a lig // Radar position #define RADAR_X 0.01 // X position of the radar (0-1) #define RADAR_Y 0.01 // Y position of the radar (0-1) + +// Ping system settings +#define MAX_PINGS 5 +#define PING_DURATION 5.0 +#define PING_COOLDOWN 3.0 ``` diff --git a/plugins/team_radar.smx b/plugins/team_radar.smx index 08fa92b..b044004 100644 Binary files a/plugins/team_radar.smx and b/plugins/team_radar.smx differ diff --git a/scripting/team_radar.sp b/scripting/team_radar.sp index a41200a..b955bfc 100644 --- a/scripting/team_radar.sp +++ b/scripting/team_radar.sp @@ -1,38 +1,55 @@ #include #include +#include #include #include #pragma newdecls required -// Customizable settings + +//╭──────────────────────────────────.★..─╮ + +// Core Settings #define UPDATE_INTERVAL 0.1 // How often the radar updates (in seconds) -#define RADAR_SIZE 2560.0 // The in-game units the radar covers -#define RADAR_SCALE 0.225 // The size of the radar on the screen (0-1) +#define RADAR_SIZE 2560.0 // The in-game units the radar covers +#define RADAR_SCALE 0.225 // The size of the radar on the screen (0-1) // Colors (RGBA format) -#define COLOR_SELF {255, 255, 0, 255} // Default {255, 255, 0, 255} Yellow -#define COLOR_TEAMMATE_HEALTHY {0, 255, 0, 255} // Default {0, 255, 0, 255} Green -#define COLOR_TEAMMATE_LOW {255, 0, 0, 255} // Default {255, 0, 0, 255} Red +#define COLOR_SELF {255, 255, 0, 255} // Yellow +#define COLOR_TEAMMATE_HEALTHY {0, 255, 0, 255} // Green +#define COLOR_TEAMMATE_LOW {255, 0, 0, 255} // Red +#define COLOR_PING {255, 255, 0, 255} // Yellow -// Radar position +// Customizable radar position #define RADAR_X 0.01 // X position of the radar (0-1) #define RADAR_Y 0.01 // Y position of the radar (0-1) +// Ping system settings +#define MAX_PINGS 5 +#define PING_DURATION 5.0 +#define PING_COOLDOWN 3.0 + +//╰─..★.───────────────────────────────────╯ + + public Plugin myinfo = { name = "TF2 Team Radar", author = "vexx-sm", description = "Adds a basic team-only radar to Team Fortress 2.", - version = "1.1", + version = "1.2", url = "https://github.com/vexx-sm/tf2-team-radar" }; Handle g_hUpdateTimer; bool g_bRadarEnabled[MAXPLAYERS + 1] = {true, ...}; +float g_PingPositions[MAXPLAYERS + 1][MAX_PINGS][3]; +float g_PingTimes[MAXPLAYERS + 1][MAX_PINGS]; +float g_LastPingTime[MAXPLAYERS + 1]; public void OnPluginStart() { g_hUpdateTimer = CreateTimer(UPDATE_INTERVAL, Timer_UpdateMiniMap, _, TIMER_REPEAT); RegConsoleCmd("sm_radar", Command_ToggleRadar, "Toggle the radar on/off"); + RegConsoleCmd("sm_mapping", Command_Ping, "Ping the location you're looking at."); } public void OnPluginEnd() { @@ -54,6 +71,59 @@ public Action Command_ToggleRadar(int client, int args) { return Plugin_Handled; } +public Action Command_Ping(int client, int args) +{ + if (!IsValidClient(client) || !IsPlayerAlive(client)) + return Plugin_Handled; + + float currentTime = GetGameTime(); + if (currentTime - g_LastPingTime[client] < PING_COOLDOWN) + { + PrintToChat(client, "You must wait before pinging again."); + return Plugin_Handled; + } + + float eyePos[3], eyeAng[3], endPos[3]; + GetClientEyePosition(client, eyePos); + GetClientEyeAngles(client, eyeAng); + + TR_TraceRayFilter(eyePos, eyeAng, MASK_SOLID, RayType_Infinite, TraceEntityFilterPlayer, client); + + if (TR_DidHit()) + { + TR_GetEndPosition(endPos); + + // Find the oldest ping slot and replace it + int oldestIndex = 0; + float oldestTime = g_PingTimes[client][0]; + for (int i = 1; i < MAX_PINGS; i++) + { + if (g_PingTimes[client][i] < oldestTime) + { + oldestIndex = i; + oldestTime = g_PingTimes[client][i]; + } + } + + g_PingPositions[client][oldestIndex] = endPos; + g_PingTimes[client][oldestIndex] = currentTime; + g_LastPingTime[client] = currentTime; + + PrintToTeam(client, "Teammate has pinged a location!"); + } + else + { + PrintToChat(client, "Couldn't find a valid position to ping."); + } + + return Plugin_Handled; +} + +public bool TraceEntityFilterPlayer(int entity, int contentsMask, any data) +{ + return entity != data; +} + public Action Timer_UpdateMiniMap(Handle timer) { for (int i = 1; i <= MaxClients; i++) { if (IsValidClient(i) && IsClientInGame(i) && g_bRadarEnabled[i]) { @@ -74,13 +144,15 @@ void UpdateMiniMap(int client) { float y = RADAR_Y; float w = RADAR_SCALE; float h = RADAR_SCALE; + float centerX = x + (w / 2); + float centerY = y + (h / 2); DrawPanel(client, x, y); + + int selfColor[4] = COLOR_SELF; + DrawArrow(client, centerX, centerY, selfColor); - // Draw player's arrow in the center - float centerX = x + (w / 2); - float centerY = y + (h / 2); - DrawArrow(client, centerX, centerY, COLOR_SELF); + float currentTime = GetGameTime(); for (int i = 1; i <= MaxClients; i++) { if (i != client && IsValidClient(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == GetClientTeam(client)) { @@ -110,8 +182,39 @@ void UpdateMiniMap(int client) { } } } + + // Draw pings + int pingColor[4] = COLOR_PING; + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i) && IsClientInGame(i) && GetClientTeam(i) == GetClientTeam(client)) + { + for (int j = 0; j < MAX_PINGS; j++) + { + if (currentTime - g_PingTimes[i][j] < PING_DURATION) + { + float pingPos[3], relativePos[3]; + pingPos = g_PingPositions[i][j]; + SubtractVectors(pingPos, playerPos, relativePos); + + float angle = ThisDegToRad(-playerAng[1] - 270); + float rotatedX = relativePos[0] * Cosine(angle) - relativePos[1] * Sine(angle); + float rotatedY = relativePos[0] * Sine(angle) + relativePos[1] * Cosine(angle); + + float pingX = centerX + (rotatedX / RADAR_SIZE) * w; + float pingY = centerY - (rotatedY / RADAR_SIZE) * h; + + if (pingX >= x && pingX <= x + w && pingY >= y && pingY <= y + h) + { + DrawPing(client, pingX, pingY, pingColor); + } + } + } + } + } } + void DrawPanel(int client, float x, float y) { Handle hud = CreateHudSynchronizer(); SetHudTextParams(x, y, UPDATE_INTERVAL + 0.1, 255, 255, 255, 0); @@ -142,6 +245,27 @@ void DrawArrow(int client, float x, float y, int color[4]) { delete hud; } +void DrawPing(int client, float x, float y, int color[4]) +{ + Handle hud = CreateHudSynchronizer(); + SetHudTextParams(x, y, UPDATE_INTERVAL + 0.1, color[0], color[1], color[2], color[3]); + ShowSyncHudText(client, hud, "!"); + delete hud; +} + + +void PrintToTeam(int client, const char[] message) +{ + int team = GetClientTeam(client); + for (int i = 1; i <= MaxClients; i++) + { + if (IsValidClient(i) && IsClientInGame(i) && GetClientTeam(i) == team) + { + PrintToChat(i, message); + } + } +} + bool IsValidClient(int client) { return (client > 0 && client <= MaxClients && IsClientConnected(client)); }