v1.2.3.b2 - Part 2
## GENERAL - Added a css_entity admin command to check whether an entity with a given index/handle exists (prints the designer name to chat or console). - Added a TakeDamage post-hook (OnTakeDamagePost) alongside the existing pre-hook, so skills can now react after damage has actually been applied, not just before. - Added CreateMolotovProjectile (new CMolotovProjectile_CreateFunc signature) and CreateTrackedChicken entity helpers. - Added a weapon_mp7 → weapon_mp5sd fallback mapping. - Added class for KillfeedIcons ## SKILL IMPROVEMENTS - Aimbot: -- Only forces a headshot hitgroup once (skips if it's already a head or an invalid hitgroup), and now restores the original hitgroup value in the new post-damage hook instead of leaving it overwritten. - Tripwire: -- Reduced the default wire width from 1.5 to 0.7. ## NEW SKILLS: - Berserker: You deal more damage and move faster as your health gets lower. - Blast Shot: Press Attack2 with the MP5 to fire an HE grenade. - Demon Eye: You deal damage to every enemy you are looking at. - Fire Rain: Throw a decoy to call down a rain of Molotovs. - Flashlight: Click [css_useSkill] to turn the flashlight on or off; its light can blind enemies. - Healing Chicken: Your chickens heal you while you are nearby. - Jetkick: Select a player to jetkick - every shot they fire knocks them backwards until disabled. - Last Gasp: After you die, you deal damage to the enemy who killed you. - Take Ammo: Click [css_useSkill] to take the active weapon's magazine from a random enemy. - Team Teleport: Press [css_useSkill] to teleport to the teammate you're looking at.
This commit is contained in:
parent
203a0c3986
commit
8038a4d646
57 changed files with 3663 additions and 553 deletions
257
jRandomSkills - SRC Files/src/player/skills/TeamTeleport.cs
Normal file
257
jRandomSkills - SRC Files/src/player/skills/TeamTeleport.cs
Normal file
|
|
@ -0,0 +1,257 @@
|
|||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using src.utils;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace src.player.skills
|
||||
{
|
||||
public class TeamTeleport : ISkill
|
||||
{
|
||||
private const Skills skillName = Skills.TeamTeleport;
|
||||
private static readonly ConcurrentDictionary<uint, PlayerSkillInfo> SkillPlayerInfo = [];
|
||||
|
||||
public class PlayerSkillInfo
|
||||
{
|
||||
public ulong SteamID { get; set; }
|
||||
public bool CanUse { get; set; }
|
||||
public DateTime Cooldown { get; set; }
|
||||
public string? TeamateName { get; set; }
|
||||
public uint? TeamateIndex { get; set; }
|
||||
public Vector? TeamatePosition { get; set; }
|
||||
public int NoSpace { get; set; }
|
||||
public int NoEnemy { get; set; }
|
||||
}
|
||||
|
||||
public static void LoadSkill()
|
||||
{
|
||||
SkillUtils.RegisterSkill(skillName, SkillsInfo.GetValue<string>(skillName, "color"));
|
||||
}
|
||||
|
||||
public static void NewRound()
|
||||
{
|
||||
SkillPlayerInfo.Clear();
|
||||
}
|
||||
|
||||
public static void OnTick()
|
||||
{
|
||||
foreach (var player in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
if (player == null || !player.IsValid) continue;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
|
||||
if (playerInfo?.Skill != skillName) continue;
|
||||
|
||||
if (!SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo)) continue;
|
||||
|
||||
GetTeamate(player, skillInfo);
|
||||
UpdateHUD(player, skillInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EnableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
SkillPlayerInfo.TryAdd(player.Index, new PlayerSkillInfo
|
||||
{
|
||||
SteamID = player.Index,
|
||||
CanUse = true,
|
||||
Cooldown = DateTime.MinValue,
|
||||
TeamateName = null,
|
||||
TeamateIndex = null,
|
||||
TeamatePosition = null,
|
||||
NoSpace = int.MinValue,
|
||||
NoEnemy = int.MinValue
|
||||
});
|
||||
}
|
||||
|
||||
public static void DisableSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null) return;
|
||||
SkillPlayerInfo.TryRemove(player.Index, out _);
|
||||
SkillUtils.ResetPrintHTML(player);
|
||||
}
|
||||
|
||||
public static void UseSkill(CCSPlayerController player)
|
||||
{
|
||||
if (player == null || !player.IsValid) return;
|
||||
|
||||
var playerPawn = player.PlayerPawn?.Value;
|
||||
if (playerPawn == null || !playerPawn.IsValid || playerPawn.Health <= 0) return;
|
||||
|
||||
if (!SkillPlayerInfo.TryGetValue(player.Index, out var skillInfo)) return;
|
||||
if (!skillInfo.CanUse) return;
|
||||
|
||||
skillInfo.NoEnemy = int.MinValue;
|
||||
skillInfo.NoSpace = int.MinValue;
|
||||
|
||||
if (skillInfo.TeamateIndex == null || skillInfo.TeamatePosition == null)
|
||||
{
|
||||
skillInfo.NoEnemy = Server.TickCount + (64 * 2);
|
||||
return;
|
||||
}
|
||||
|
||||
var victim = PlayerManager.GetTickPlayers().FirstOrDefault(p => p.Index == skillInfo.TeamateIndex.Value);
|
||||
if (victim == null || !victim.IsValid)
|
||||
{
|
||||
skillInfo.NoEnemy = Server.TickCount + (64 * 2);
|
||||
return;
|
||||
}
|
||||
|
||||
TeleportToTeamate(player, victim, skillInfo.TeamatePosition, skillInfo);
|
||||
}
|
||||
|
||||
private static void GetTeamate(CCSPlayerController player, PlayerSkillInfo skillInfo)
|
||||
{
|
||||
var playerPawn = player.PlayerPawn?.Value;
|
||||
if (playerPawn == null || !playerPawn.IsValid || playerPawn.AbsOrigin == null || playerPawn.V_angle == null || playerPawn.ViewOffset == null)
|
||||
return;
|
||||
|
||||
Vector eyePos = new(playerPawn.AbsOrigin.X, playerPawn.AbsOrigin.Y, playerPawn.AbsOrigin.Z + playerPawn.ViewOffset.Z);
|
||||
Vector playerForward = SkillUtils.GetForwardVector(playerPawn.V_angle);
|
||||
|
||||
float teleportAngle = SkillsInfo.GetValue<float>(skillName, "teleportAngle");
|
||||
float minDot = MathF.Cos(teleportAngle * MathF.PI / 180.0f);
|
||||
|
||||
skillInfo.TeamateIndex = null;
|
||||
skillInfo.TeamateName = null;
|
||||
skillInfo.TeamatePosition = null;
|
||||
|
||||
foreach (var teammate in PlayerManager.GetTickPlayers())
|
||||
{
|
||||
if (teammate == null || !teammate.IsValid || teammate.Index == player.Index || teammate.Team != player.Team)
|
||||
continue;
|
||||
|
||||
var teammatePawn = teammate.PlayerPawn?.Value;
|
||||
if (teammatePawn == null || !teammatePawn.IsValid || teammatePawn.Health <= 0 || teammatePawn.AbsOrigin == null)
|
||||
continue;
|
||||
|
||||
Vector targetPos = new(teammatePawn.AbsOrigin.X, teammatePawn.AbsOrigin.Y, teammatePawn.AbsOrigin.Z + (teammatePawn.ViewOffset.Z * 0.5f));
|
||||
Vector toTarget = new(targetPos.X - eyePos.X, targetPos.Y - eyePos.Y, targetPos.Z - eyePos.Z);
|
||||
|
||||
float distanceSq = toTarget.X * toTarget.X + toTarget.Y * toTarget.Y + toTarget.Z * toTarget.Z;
|
||||
if (distanceSq <= 0.0001f)
|
||||
continue;
|
||||
|
||||
float distance = MathF.Sqrt(distanceSq);
|
||||
|
||||
float invLength = 1.0f / distance;
|
||||
|
||||
toTarget.X *= invLength;
|
||||
toTarget.Y *= invLength;
|
||||
toTarget.Z *= invLength;
|
||||
|
||||
float dot = playerForward.X * toTarget.X + playerForward.Y * toTarget.Y + playerForward.Z * toTarget.Z;
|
||||
|
||||
if (distance > 30.0f && dot < minDot)
|
||||
continue;
|
||||
|
||||
skillInfo.TeamateIndex = teammate.Index;
|
||||
skillInfo.TeamateName = teammate.PlayerName;
|
||||
skillInfo.TeamatePosition = new Vector(teammatePawn.AbsOrigin.X, teammatePawn.AbsOrigin.Y, teammatePawn.AbsOrigin.Z);
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe static bool CheckTeleport(CCSPlayerController attacker, CCSPlayerController victim, Vector startPos, Vector endPos, QAngle angle)
|
||||
{
|
||||
var attackerPawn = attacker.PlayerPawn.Value;
|
||||
if (attackerPawn == null || !attackerPawn.IsValid) return false;
|
||||
|
||||
var victimPawn = victim.PlayerPawn.Value;
|
||||
if (victimPawn == null || !victimPawn.IsValid) return false;
|
||||
|
||||
var result = RayTrace.TraceHullShape(
|
||||
startPos,
|
||||
endPos,
|
||||
victim,
|
||||
attackerPawn.Collision.Mins,
|
||||
attackerPawn.Collision.Maxs,
|
||||
null,
|
||||
null,
|
||||
angle
|
||||
);
|
||||
|
||||
if (!result.HasValue)
|
||||
return false;
|
||||
|
||||
return !result.Value.DidHit;
|
||||
}
|
||||
|
||||
private static void TeleportToTeamate(CCSPlayerController player, CCSPlayerController victim, Vector position, PlayerSkillInfo skillInfo)
|
||||
{
|
||||
var playerPawn = player.PlayerPawn?.Value;
|
||||
if (playerPawn == null || !playerPawn.IsValid || player.AbsRotation == null) return;
|
||||
|
||||
QAngle playerAngles = new(player.AbsRotation.X, player.AbsRotation.Y, player.AbsRotation.Z);
|
||||
float distance = SkillsInfo.GetValue<float>(skillName, "teleportDistance");
|
||||
|
||||
int[] angles = [0, 90, -90, 179];
|
||||
bool teleported = false;
|
||||
|
||||
foreach (int extraAngle in angles)
|
||||
{
|
||||
QAngle targetAngle = new(0, playerAngles.Y + extraAngle, 0);
|
||||
Vector direction = SkillUtils.GetForwardVector(targetAngle);
|
||||
|
||||
Vector targetPos = position - (direction * distance);
|
||||
Vector traceStart = position - (direction * 20f);
|
||||
|
||||
if (CheckTeleport(player, victim, traceStart, targetPos, targetAngle))
|
||||
{
|
||||
playerPawn.Teleport(targetPos, targetAngle, Vector.Zero);
|
||||
teleported = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!teleported)
|
||||
skillInfo.NoSpace = Server.TickCount + (64 * 2);
|
||||
else
|
||||
{
|
||||
skillInfo.NoSpace = int.MinValue;
|
||||
skillInfo.NoEnemy = int.MinValue;
|
||||
skillInfo.CanUse = false;
|
||||
skillInfo.Cooldown = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdateHUD(CCSPlayerController player, PlayerSkillInfo skillInfo)
|
||||
{
|
||||
float cooldown = 0;
|
||||
|
||||
float time = (float)Math.Ceiling((skillInfo.Cooldown.AddSeconds(SkillsInfo.GetValue<float>(skillName, "cooldown")) - DateTime.Now).TotalSeconds);
|
||||
cooldown = Math.Max(time, 0);
|
||||
|
||||
if (cooldown == 0 && !skillInfo.CanUse)
|
||||
skillInfo.CanUse = true;
|
||||
|
||||
var playerInfo = PlayerManager.GetPlayerByIndex(player.Index);
|
||||
if (playerInfo == null) return;
|
||||
|
||||
if (cooldown != 0)
|
||||
playerInfo.PrintHTML = $"{player.GetTranslation("hud_info", $"<font color='#FF0000'>{cooldown}</font>")}";
|
||||
else if (skillInfo.NoSpace >= Server.TickCount)
|
||||
playerInfo.PrintHTML = $"<font color='#FF0000'>{player.GetTranslation("shade_nospace")}</font>";
|
||||
else if (skillInfo.NoEnemy >= Server.TickCount)
|
||||
playerInfo.PrintHTML = $"<font color='#FF0000'>{player.GetTranslation("teamteleport_noenemy")}</font>";
|
||||
else
|
||||
{
|
||||
if (skillInfo.TeamateName == null)
|
||||
playerInfo.PrintHTML = null;
|
||||
else
|
||||
{
|
||||
string color = player.Team == CsTeam.Terrorist ? "#FFA500" : "#ADD8E6";
|
||||
playerInfo.PrintHTML = $"{player.GetTranslation("teamteleport_hud_info", $"<font color='{color}'>{System.Net.WebUtility.HtmlEncode(skillInfo.TeamateName)}</font>")}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SkillConfig(Skills skill = skillName, bool active = true, string color = "#bcf542", CsTeam onlyTeam = CsTeam.None, bool disableOnFreezeTime = true, bool needsTeammates = true, string requiredPermission = "", float? hudDuration = null, float? descriptionHudDuration = null, int maxPerServer = 2, Rarity rarity = Rarity.Common, float cooldown = 15f, float teleportAngle = 10.0f, float teleportDistance = 100f) : SkillsInfo.DefaultSkillInfo(skill, active, color, onlyTeam, disableOnFreezeTime, needsTeammates, requiredPermission, hudDuration, descriptionHudDuration, maxPerServer, rarity)
|
||||
{
|
||||
public float Cooldown { get; set; } = cooldown;
|
||||
public float TeleportAngle { get; set; } = teleportAngle;
|
||||
public float TeleportDistance { get; set; } = teleportDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue