Skip to content

Commit

Permalink
0.8.2: multiple coach, autoteam join, etc
Browse files Browse the repository at this point in the history
  • Loading branch information
shobhit-pathak committed Aug 24, 2024
1 parent e8047a1 commit d90e49c
Show file tree
Hide file tree
Showing 26 changed files with 499 additions and 314 deletions.
5 changes: 5 additions & 0 deletions BackupManagement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ public void OnStopCommand(CCSPlayerController? player, CommandInfo? command) {
ReplyToUserCommand(player, Localizer["matchzy.backup.stoptacticaltimeout"]);
return;
}
if (playerHasTakenDamage && stopCommandNoDamage.Value)
{
ReplyToUserCommand(player, Localizer["matchzy.restore.stopcommandrequiresnodamage"]);
return;
}
string stopTeamName = "";
string remainingStopTeam = "";
if (player.TeamNum == 2) {
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# MatchZy Changelog

# 0.8.2

#### August 25, 2024

- Added capability to have multiple coaches in a team.
- Coaches will now be invisible, they will drop the bomb on the spawn if they get it and will die 1 second before freezetime ends.
- If a match is loaded, player will directly join their respective team, skipping the join team menu.
- Fixed a bug where loading a saved nade would make the player stuck.
- Added `matchzy_stop_command_no_damage` convar to determine whether the stop command becomes unavailable if a player damages a player from the opposing team.
- `.map` command can now be used without "de_" prefix for maps. (Example: .map dust2)

# 0.8.1

#### August 17, 2024
Expand Down
209 changes: 209 additions & 0 deletions Coach.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Utils;
using CounterStrikeSharp.API.Modules.Cvars;

namespace MatchZy;

public partial class MatchZy
{

public CounterStrikeSharp.API.Modules.Timers.Timer? coachKillTimer = null;

public HashSet<CCSPlayerController> GetAllCoaches()
{
HashSet<CCSPlayerController> coaches = new(matchzyTeam1.coach);
coaches.UnionWith(matchzyTeam2.coach);

return coaches;
}

public void HandleCoachCommand(CCSPlayerController? player, string side)
{
if (!IsPlayerValid(player)) return;
if (isPractice)
{
ReplyToUserCommand(player, "Coach command can only be used in match mode!");
return;
}

side = side.Trim().ToLower();

if (side != "t" && side != "ct")
{
ReplyToUserCommand(player, "Usage: .coach t or .coach ct");
return;
}

if (matchzyTeam1.coach.Contains(player!) || matchzyTeam2.coach.Contains(player!))
{
ReplyToUserCommand(player, "You are already coaching a team!");
return;
}

Team matchZyCoachTeam;

if (side == "t")
{
matchZyCoachTeam = reverseTeamSides["TERRORIST"];
}
else if (side == "ct")
{
matchZyCoachTeam = reverseTeamSides["CT"];
}
else
{
return;
}

// if (matchZyCoachTeam.coach != null) {
// ReplyToUserCommand(player, "Coach slot for this team has been already taken!");
// return;
// }

matchZyCoachTeam.coach.Add(player!);
player!.Clan = $"[{matchZyCoachTeam.teamName} COACH]";
if (player.InGameMoneyServices != null) player.InGameMoneyServices.Account = 0;
ReplyToUserCommand(player, $"You are now coaching {matchZyCoachTeam.teamName}! Use .uncoach to stop coaching");
PrintToAllChat($"{ChatColors.Green}{player.PlayerName}{ChatColors.Default} is now coaching {ChatColors.Green}{matchZyCoachTeam.teamName}{ChatColors.Default}!");
}

public void HandleCoaches()
{
coachKillTimer?.Kill();
coachKillTimer = null;
int freezeTime = ConVar.Find("mp_freezetime")!.GetPrimitiveValue<int>();
coachKillTimer ??= AddTimer(freezeTime - 1.5f, KillCoaches);
HashSet<CCSPlayerController> coaches = GetAllCoaches();

foreach (var coach in coaches)
{
if (!IsPlayerValid(coach)) continue;
Team coachTeam = matchzyTeam1.coach.Contains(coach) ? matchzyTeam1 : matchzyTeam2;
int coachTeamNum = teamSides[coachTeam] == "CT" ? 3 : 2;
coach.InGameMoneyServices!.Account = 0;

AddTimer(0.5f, () => HandleCoachTeam(coach));

coach.ActionTrackingServices!.MatchStats.Kills = 0;
coach.ActionTrackingServices!.MatchStats.Deaths = 0;
coach.ActionTrackingServices!.MatchStats.Assists = 0;
coach.ActionTrackingServices!.MatchStats.Damage = 0;

bool isCompetitiveSpawn = false;

Position coachPosition = new(coach.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsOrigin, coach.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsRotation);
List<Position> teamPositions = spawnsData[(byte)coachTeamNum];

// Elevating the coach so that they don't block the players.
coach!.PlayerPawn.Value!.Teleport(new Vector(coach.PlayerPawn.Value.CBodyComponent!.SceneNode!.AbsOrigin.X, coach.PlayerPawn.Value.CBodyComponent!.SceneNode!.AbsOrigin.Y, coach.PlayerPawn.Value.CBodyComponent!.SceneNode!.AbsOrigin.Z + 75.0f), coach.PlayerPawn.Value.EyeAngles, new Vector(0, 0, 0));
coach.PlayerPawn.Value!.MoveType = MoveType_t.MOVETYPE_NONE;
coach.PlayerPawn.Value!.ActualMoveType = MoveType_t.MOVETYPE_NONE;

SetPlayerInvisible(player: coach, setWeaponsInvisible: false);

foreach (Position position in teamPositions)
{
if (position.Equals(coachPosition))
{
isCompetitiveSpawn = true;
break;
}
}
if (isCompetitiveSpawn)
{
foreach (var key in playerData.Keys)
{
CCSPlayerController player = playerData[key];
if (!IsPlayerValid(player) || coaches.Contains(player) || player.TeamNum != (byte)coachTeamNum) continue;
bool playerOnCompetitiveSpawn = false;
Position playerPosition = new(player.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsOrigin, player.PlayerPawn.Value!.CBodyComponent!.SceneNode!.AbsRotation);
foreach (Position position in teamPositions)
{
if (position.Equals(playerPosition))
{
playerOnCompetitiveSpawn = true;
break;
}
}
// No need to swap the player if they are already on a competitive spawn.
if (playerOnCompetitiveSpawn) continue;
// Swapping positions of the coach and the player so that the coach doesn't take any competitive spawn.
AddTimer(0.1f, () =>
{
coach!.PlayerPawn.Value.Teleport(new Vector(playerPosition.PlayerPosition.X, playerPosition.PlayerPosition.Y, playerPosition.PlayerPosition.Z + 150.0f), playerPosition.PlayerAngle, new Vector(0, 0, 0));
player!.PlayerPawn.Value.Teleport(coachPosition.PlayerPosition, coachPosition.PlayerAngle, new Vector(0, 0, 0));
});
}
}
HandleCoachWeapons(coach);
}
}

private void HandleCoachWeapons(CCSPlayerController coach)
{
if (!IsPlayerValid(coach)) return;
DropWeaponByDesignerName(coach, "weapon_c4");
coach.RemoveWeapons();
}

public CsTeam GetCoachTeam(CCSPlayerController coach)
{
if (matchzyTeam1.coach.Contains(coach))
{
if (teamSides[matchzyTeam1] == "CT")
{
return CsTeam.CounterTerrorist;
}
else if (teamSides[matchzyTeam1] == "TERRORIST")
{
return CsTeam.Terrorist;
}
}
if (matchzyTeam2.coach.Contains(coach))
{
if (teamSides[matchzyTeam2] == "CT")
{
return CsTeam.CounterTerrorist;
}
else if (teamSides[matchzyTeam2] == "TERRORIST")
{
return CsTeam.Terrorist;
}
}
return CsTeam.Spectator;
}

private void HandleCoachTeam(CCSPlayerController playerController)
{
CsTeam oldTeam = GetCoachTeam(playerController);
if (playerController.Team != oldTeam)
{
playerController.ChangeTeam(CsTeam.Spectator);
AddTimer(0.01f, () => playerController.ChangeTeam(oldTeam));
}
if (playerController.InGameMoneyServices != null) playerController.InGameMoneyServices.Account = 0;
}

private void KillCoaches()
{
HashSet<CCSPlayerController> coaches = GetAllCoaches();
string suicidePenalty = GetConvarStringValue(ConVar.Find("mp_suicide_penalty"));
string deathDropGunEnabled = GetConvarStringValue(ConVar.Find("mp_death_drop_gun"));
string specFreezeTime = GetConvarStringValue(ConVar.Find("spec_freeze_time"));
string specFreezeTimeLock = GetConvarStringValue(ConVar.Find("spec_freeze_time_lock"));
string specFreezeDeathanim = GetConvarStringValue(ConVar.Find("spec_freeze_deathanim_time"));
Server.ExecuteCommand("mp_suicide_penalty 0; mp_death_drop_gun 0;spec_freeze_time 0; spec_freeze_time_lock 0; spec_freeze_deathanim_time 0;");

// Adding timer to make sure above commands are executed successfully.
AddTimer(0.5f, () =>
{
foreach (var coach in coaches)
{
if (!IsPlayerValid(coach)) continue;
coach.PlayerPawn.Value!.CommitSuicide(explode: false, force: true);
}
Server.ExecuteCommand($"mp_suicide_penalty {suicidePenalty}; mp_death_drop_gun {deathDropGunEnabled}; spec_freeze_time {specFreezeTime}; spec_freeze_time_lock {specFreezeTimeLock}; spec_freeze_deathanim_time {specFreezeDeathanim};");
});
}
}
2 changes: 2 additions & 0 deletions ConfigConvars.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public partial class MatchZy

public FakeConVar<bool> enableDamageReport = new("matchzy_enable_damage_report", "Whether to show damage report after each round or not. Default: true", true);

public FakeConVar<bool> stopCommandNoDamage = new("matchzy_stop_command_no_damage", "Whether the stop command becomes unavailable if a player damages a player from the opposing team.", false);

[ConsoleCommand("matchzy_whitelist_enabled_default", "Whether Whitelist is enabled by default or not. Default value: false")]
public void MatchZyWLConvar(CCSPlayerController? player, CommandInfo command)
{
Expand Down
31 changes: 13 additions & 18 deletions ConsoleCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,37 +120,32 @@ public void OnPlayerUnReady(CCSPlayerController? player, CommandInfo? command)
[ConsoleCommand("css_stay", "Stays after knife round")]
public void OnTeamStay(CCSPlayerController? player, CommandInfo? command)
{
if (player == null) return;
if (player == null || !isSideSelectionPhase) return;

Log($"[!stay command] {player.UserId}, TeamNum: {player.TeamNum}, knifeWinner: {knifeWinner}, isSideSelectionPhase: {isSideSelectionPhase}");
if (isSideSelectionPhase)
if (player.TeamNum == knifeWinner)
{
if (player.TeamNum == knifeWinner)
{
PrintToAllChat(Localizer["matchzy.knife.decidedtostay", knifeWinnerName]);
// Server.PrintToChatAll($"{chatPrefix} {ChatColors.Green}{knifeWinnerName}{ChatColors.Default} has decided to stay!");
StartLive();
}
PrintToAllChat(Localizer["matchzy.knife.decidedtostay", knifeWinnerName]);
// Server.PrintToChatAll($"{chatPrefix} {ChatColors.Green}{knifeWinnerName}{ChatColors.Default} has decided to stay!");
StartLive();
}
}

[ConsoleCommand("css_switch", "Switch after knife round")]
[ConsoleCommand("css_swap", "Switch after knife round")]
public void OnTeamSwitch(CCSPlayerController? player, CommandInfo? command)
{
if (player == null) return;
if (player == null || !isSideSelectionPhase) return;

Log($"[!switch command] {player.UserId}, TeamNum: {player.TeamNum}, knifeWinner: {knifeWinner}, isSideSelectionPhase: {isSideSelectionPhase}");
if (isSideSelectionPhase)

if (player.TeamNum == knifeWinner)
{
if (player.TeamNum == knifeWinner)
{
Server.ExecuteCommand("mp_swapteams;");
SwapSidesInTeamData(true);
PrintToAllChat(Localizer["matchzy.knife.decidedtoswitch", knifeWinnerName]);
// Server.PrintToChatAll($"{chatPrefix} {ChatColors.Green}{knifeWinnerName}{ChatColors.Default} has decided to switch!");
StartLive();
}
Server.ExecuteCommand("mp_swapteams;");
SwapSidesInTeamData(true);
PrintToAllChat(Localizer["matchzy.knife.decidedtoswitch", knifeWinnerName]);
// Server.PrintToChatAll($"{chatPrefix} {ChatColors.Green}{knifeWinnerName}{ChatColors.Default} has decided to switch!");
StartLive();
}
}

Expand Down
1 change: 0 additions & 1 deletion DemoManagement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ public void StopDemoRecording(float delay, string activeDemoFile, long liveMatch
if (isDemoRecording)
{
Server.ExecuteCommand($"tv_stoprecord");
isDemoRecording = false;
}
isDemoRecording = false;
AddTimer(15, () =>
Expand Down
Loading

0 comments on commit d90e49c

Please sign in to comment.