mirror of
https://github.com/MSWS/TTT.git
synced 2025-12-07 23:06:33 -08:00
Compare commits
17 Commits
0.21.0-dev
...
0.22.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6b79ef038 | ||
|
|
57ef5e3e24 | ||
|
|
9c99d316aa | ||
|
|
e679c5193b | ||
|
|
6ece0450bb | ||
|
|
daa24a0e87 | ||
|
|
1c8785b388 | ||
|
|
cc52d19108 | ||
|
|
a80c36e3c5 | ||
|
|
ba6b6c448f | ||
|
|
a1d595ce8a | ||
|
|
d30e916319 | ||
|
|
9f275fa189 | ||
|
|
40bdcac4b0 | ||
|
|
6b3ae03ab3 | ||
|
|
9e8e1d1fb0 | ||
|
|
23f502a381 |
@@ -1,8 +1,8 @@
|
||||
namespace SpecialRoundAPI;
|
||||
|
||||
public record SpeedRoundConfig : SpecialRoundConfig {
|
||||
public override float Weight { get; init; } = 0.4f;
|
||||
public override float Weight { get; init; } = 0.5f;
|
||||
|
||||
public TimeSpan InitialSeconds { get; init; } = TimeSpan.FromSeconds(60);
|
||||
public TimeSpan InitialSeconds { get; init; } = TimeSpan.FromSeconds(40);
|
||||
public TimeSpan SecondsPerKill { get; init; } = TimeSpan.FromSeconds(10);
|
||||
}
|
||||
@@ -24,10 +24,6 @@ public class SetTargetCommand(IServiceProvider provider) : ICommand {
|
||||
Execute(IOnlinePlayer? executor, ICommandInfo info) {
|
||||
if (executor == null) return Task.FromResult(CommandResult.PLAYER_ONLY);
|
||||
|
||||
var name = "TRAITOR";
|
||||
|
||||
if (info.ArgCount == 2) name = info.Args[1];
|
||||
|
||||
Server.NextWorldUpdate(() => {
|
||||
var gamePlayer = converter.GetPlayer(executor);
|
||||
if (gamePlayer == null) return;
|
||||
|
||||
@@ -52,6 +52,17 @@ public class CombatHandler(IServiceProvider provider) : IPluginModule {
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
[GameEventHandler(HookMode.Pre)]
|
||||
public HookResult OnPlayerDamage(EventPlayerHurt ev, GameEventInfo info) {
|
||||
var player = ev.Userid;
|
||||
if (player == null) return HookResult.Continue;
|
||||
|
||||
hideAndTrackStats(ev);
|
||||
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
private void hideAndTrackStats(EventPlayerDeath ev,
|
||||
CCSPlayerController player) {
|
||||
var victimStats = player.ActionTrackingServices?.MatchStats;
|
||||
@@ -89,6 +100,16 @@ public class CombatHandler(IServiceProvider provider) : IPluginModule {
|
||||
"m_pActionTrackingServices");
|
||||
}
|
||||
|
||||
private void hideAndTrackStats(EventPlayerHurt ev) {
|
||||
var attackerStats = ev.Attacker?.ActionTrackingServices?.MatchStats;
|
||||
|
||||
if (attackerStats == null) return;
|
||||
if (ev.Attacker == null) return;
|
||||
attackerStats.Damage -= ev.DmgHealth;
|
||||
Utilities.SetStateChanged(ev.Attacker, "CCSPlayerController",
|
||||
"m_pActionTrackingServices");
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
[GameEventHandler]
|
||||
public HookResult OnPlayerHurt(EventPlayerHurt ev, GameEventInfo _) {
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TTT.API;
|
||||
using TTT.API.Messages;
|
||||
|
||||
namespace TTT.CS2.GameHandlers;
|
||||
|
||||
public class EntityTargetHandlers(IServiceProvider provider) : IPluginModule {
|
||||
private readonly IMessenger messenger =
|
||||
provider.GetRequiredService<IMessenger>();
|
||||
|
||||
public void Dispose() { }
|
||||
public void Start() { }
|
||||
|
||||
public void Start(BasePlugin? plugin) {
|
||||
plugin?.HookEntityOutput("*", "*", handler);
|
||||
}
|
||||
|
||||
private HookResult handler(CEntityIOOutput output, string name,
|
||||
CEntityInstance activator, CEntityInstance caller, CVariant value,
|
||||
float delay) {
|
||||
if (caller.DesignerName == "prop_dynamic") return HookResult.Continue;
|
||||
messenger.Debug("Entity Output Triggered: " + name);
|
||||
messenger.Debug("Activator: " + activator.DesignerName);
|
||||
messenger.Debug("Caller: " + caller.DesignerName);
|
||||
messenger.Debug("Value: " + value + " " + value.GetType());
|
||||
caller.AcceptInput("OnPass");
|
||||
activator.AcceptInput("OnPass");
|
||||
if (caller.DesignerName != "filter_activator_name")
|
||||
return HookResult.Continue;
|
||||
var csPlayer =
|
||||
Utilities.GetPlayerFromIndex((int)activator.EntityHandle.Index);
|
||||
if (csPlayer != null && csPlayer.IsValid) {
|
||||
messenger.DebugAnnounce(
|
||||
$"Filter Activator Name triggered by player: {csPlayer.PlayerName} {(int)csPlayer.Index}");
|
||||
}
|
||||
|
||||
var ptrPlayer = new CCSPlayerController(activator.Handle);
|
||||
if (ptrPlayer.IsValid) {
|
||||
messenger.DebugAnnounce(
|
||||
$"Filter Activator Name triggered by player controller: {ptrPlayer.PlayerName} {(int)ptrPlayer.Index}");
|
||||
}
|
||||
|
||||
messenger.DebugAnnounce(output + " - " + output.Description);
|
||||
|
||||
var connections = output.Connections;
|
||||
if (connections != null) debugConnection(connections);
|
||||
|
||||
caller.AcceptInput("OnPass");
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
private void debugConnection(EntityIOConnection_t connection) {
|
||||
messenger.DebugAnnounce("Connection:");
|
||||
messenger.DebugAnnounce(" Target: " + connection.Target);
|
||||
messenger.DebugAnnounce(" Input: " + connection.TargetInput);
|
||||
messenger.DebugAnnounce(" Parameter: " + connection.ValueOverride);
|
||||
messenger.DebugAnnounce(" Delay: " + connection.Delay);
|
||||
messenger.DebugAnnounce(" Times to fire: " + connection.TimesToFire);
|
||||
|
||||
if (connection.Next != null) debugConnection(connection.Next);
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public class TraitorChatHandler(IServiceProvider provider) : IPluginModule {
|
||||
|
||||
private HookResult onSay(CCSPlayerController? player,
|
||||
CommandInfo commandInfo) {
|
||||
if (mutedPlayers != null
|
||||
if (mutedPlayers != null && player != null && player.GetHealth() > 0
|
||||
&& mutedPlayers.Contains(player?.SteamID.ToString() ?? ""))
|
||||
return HookResult.Handled;
|
||||
|
||||
|
||||
@@ -20,8 +20,14 @@ public class PlayerStatsTracker(IServiceProvider provider) : IListener {
|
||||
|
||||
private readonly ISet<int> revealedDeaths = new HashSet<int>();
|
||||
|
||||
private readonly IDictionary<int, (int, int)> roundKillsAndAssists =
|
||||
new Dictionary<int, (int, int)>();
|
||||
private readonly IDictionary<int, RoundData> roundStats =
|
||||
new Dictionary<int, RoundData>();
|
||||
|
||||
record RoundData {
|
||||
public int Kills;
|
||||
public int Assists;
|
||||
public int Damage;
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
@@ -50,24 +56,39 @@ public class PlayerStatsTracker(IServiceProvider provider) : IListener {
|
||||
ev.Assister == null ? null : converter.GetPlayer(ev.Assister);
|
||||
|
||||
if (killer != null) {
|
||||
roundKillsAndAssists.TryGetValue(killer.Slot, out var def);
|
||||
def.Item1++;
|
||||
roundKillsAndAssists[killer.Slot] = def;
|
||||
roundStats.TryGetValue(killer.Slot, out var def);
|
||||
def ??= new RoundData();
|
||||
def.Kills++;
|
||||
roundStats[killer.Slot] = def;
|
||||
}
|
||||
|
||||
if (assister != null && assister != killer) {
|
||||
roundKillsAndAssists.TryGetValue(assister.Slot, out var def);
|
||||
def.Item2++;
|
||||
roundKillsAndAssists[assister.Slot] = def;
|
||||
roundStats.TryGetValue(assister.Slot, out var def);
|
||||
def ??= new RoundData();
|
||||
def.Assists++;
|
||||
roundStats[assister.Slot] = def;
|
||||
}
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
[EventHandler(Priority = Priority.HIGH)]
|
||||
public void OnDamage(PlayerDamagedEvent ev) {
|
||||
var attacker =
|
||||
ev.Attacker == null ? null : converter.GetPlayer(ev.Attacker);
|
||||
if (attacker == null) return;
|
||||
|
||||
roundStats.TryGetValue(attacker.Slot, out var def);
|
||||
def ??= new RoundData();
|
||||
def.Damage += ev.DmgDealt;
|
||||
roundStats[attacker.Slot] = def;
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
[EventHandler]
|
||||
public void OnRoundEnd(GameStateUpdateEvent ev) {
|
||||
if (ev.NewState == State.IN_PROGRESS) {
|
||||
revealedDeaths.Clear();
|
||||
roundKillsAndAssists.Clear();
|
||||
roundStats.Clear();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -100,15 +121,16 @@ public class PlayerStatsTracker(IServiceProvider provider) : IListener {
|
||||
var online = finder.GetOnline()
|
||||
.Select(p => converter.GetPlayer(p))
|
||||
.OfType<CCSPlayerController>()
|
||||
.Where(p => p.IsValid && roundKillsAndAssists.ContainsKey(p.Slot));
|
||||
.Where(p => p.IsValid && roundStats.ContainsKey(p.Slot));
|
||||
|
||||
foreach (var player in online) {
|
||||
var stats = player.ActionTrackingServices?.MatchStats;
|
||||
if (stats == null) continue;
|
||||
|
||||
var (kills, assists) = roundKillsAndAssists[player.Slot];
|
||||
stats.Kills += kills;
|
||||
stats.Assists += assists;
|
||||
if (!roundStats.TryGetValue(player.Slot, out var data)) continue;
|
||||
|
||||
stats.Kills += data.Kills;
|
||||
stats.Assists += data.Assists;
|
||||
Utilities.SetStateChanged(player, "CCSPlayerController",
|
||||
"m_pActionTrackingServices");
|
||||
}
|
||||
|
||||
@@ -114,14 +114,7 @@ public class CS2Player : IOnlinePlayer, IEquatable<CS2Player> {
|
||||
|
||||
// Goal: Pad the name to a fixed width for better alignment in logs
|
||||
// Left-align ID, right-align name
|
||||
private string createPaddedName() {
|
||||
var onlineLengths = Utilities.GetPlayers()
|
||||
.Select(p => p.PlayerName.Length)
|
||||
.ToList();
|
||||
if (onlineLengths.Count == 0) return CreatePaddedName(Id, Name, 13);
|
||||
var namePadding = Math.Min(onlineLengths.Max(), 24);
|
||||
return CreatePaddedName(Id, Name, namePadding + 8);
|
||||
}
|
||||
private string createPaddedName() { return CreatePaddedName(Id, Name, 24); }
|
||||
|
||||
public static string CreatePaddedName(string id, string name, int len) {
|
||||
var suffix = id.Length > 5 ? id[^5..] : id.PadLeft(5, '0');
|
||||
|
||||
@@ -26,9 +26,10 @@ public class DamagedAction(IRoleAssigner roles, IPlayer victim,
|
||||
public string Details => $"for {Damage} damage with {Weapon}";
|
||||
|
||||
public string Prefix
|
||||
=> PlayerRole is TraitorRole != OtherRole is TraitorRole ?
|
||||
"" :
|
||||
"[BAD ACTION]";
|
||||
=> PlayerRole != null && OtherRole != null
|
||||
&& PlayerRole is TraitorRole != OtherRole is TraitorRole ?
|
||||
"" :
|
||||
"[BAD] ";
|
||||
|
||||
#region ConstructorAliases
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using TTT.API.Game;
|
||||
using TTT.API.Player;
|
||||
using TTT.API.Role;
|
||||
using TTT.Game.Events.Player;
|
||||
using TTT.Game.Roles;
|
||||
|
||||
namespace TTT.Game.Actions;
|
||||
|
||||
@@ -34,10 +35,16 @@ public class DeathAction(IRoleAssigner roles, IPlayer victim, IPlayer? killer)
|
||||
$" [{OtherRole.Name.First(char.IsAsciiLetter)}]" :
|
||||
"";
|
||||
return Other is not null ?
|
||||
$"{Other}{oRole} {Verb} {Player}{pRole} {Details}" :
|
||||
$"{Player}{pRole} {Verb} {Details}";
|
||||
$"{Prefix}{Other}{oRole} {Verb} {Player}{pRole} {Details}" :
|
||||
$"{Prefix}{Player}{pRole} {Verb} {Details}";
|
||||
}
|
||||
|
||||
public string Prefix
|
||||
=> PlayerRole != null && OtherRole != null
|
||||
&& PlayerRole is TraitorRole != OtherRole is TraitorRole ?
|
||||
"" :
|
||||
"[BAD] ";
|
||||
|
||||
#region ConstructorAliases
|
||||
|
||||
public DeathAction(IServiceProvider provider, IPlayer victim, IPlayer? killer)
|
||||
|
||||
@@ -11,5 +11,7 @@ public class RoleAssignedAction(IPlayer player, IRole role) : IAction {
|
||||
public IRole? OtherRole { get; } = null;
|
||||
public string Id => "basegame.action.roleassigned";
|
||||
public string Verb => "was assigned";
|
||||
public string Details { get; } = role.Name;
|
||||
|
||||
public string Details { get; } =
|
||||
new(role.Name.Where(char.IsAsciiLetter).ToArray());
|
||||
}
|
||||
@@ -12,7 +12,7 @@ public class ShopItemReward<TItem>(IServiceProvider provider)
|
||||
=> shop.Items.OfType<TItem>().FirstOrDefault()?.Name ?? typeof(TItem).Name;
|
||||
|
||||
public override string Description
|
||||
=> $"you will receive {("aeiou".Contains(Name.ToLower()[0]) ? "an" : "a")} {typeof(TItem).Name} item next round";
|
||||
=> $"you will receive {("aeiou".Contains(Name.ToLower()[0]) ? "an" : "a")} {Name} item next round";
|
||||
|
||||
public override void GiveOnRound(IOnlinePlayer player) {
|
||||
var instance = shop.Items.OfType<TItem>().FirstOrDefault();
|
||||
|
||||
@@ -34,7 +34,7 @@ SHOP_CANNOT_PURCHASE_WITH_REASON: "%SHOP_PREFIX%You cannot purchase this item: {
|
||||
SHOP_PURCHASED: "%SHOP_PREFIX%You purchased {white}{0}{grey}."
|
||||
SHOP_LIST_FOOTER: "%SHOP_PREFIX%You are %an% {0}{grey}, you have {yellow}{1}{grey} %CREDITS_NAME%%s%."
|
||||
|
||||
CREDITS_NAME: "credit"
|
||||
CREDITS_NAME: "point"
|
||||
CREDITS_GIVEN: "%SHOP_PREFIX%{0}{1} %CREDITS_NAME%%s%"
|
||||
CREDITS_GIVEN_REASON: "%SHOP_PREFIX%{0}{1} %CREDITS_NAME%%s% {grey}({white}{2}{grey})"
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ using ShopAPI.Events;
|
||||
using SpecialRound.lang;
|
||||
using SpecialRoundAPI;
|
||||
using TTT.API.Events;
|
||||
using TTT.API.Messages;
|
||||
using TTT.API.Storage;
|
||||
using TTT.Game.Events.Game;
|
||||
using TTT.Locale;
|
||||
@@ -15,6 +16,12 @@ public class VanillaRound(IServiceProvider provider)
|
||||
public override string Name => "Vanilla";
|
||||
public override IMsg Description => RoundMsgs.SPECIAL_ROUND_VANILLA;
|
||||
|
||||
private readonly IMessenger messenger =
|
||||
provider.GetRequiredService<IMessenger>();
|
||||
|
||||
private readonly IMsgLocalizer locale =
|
||||
provider.GetRequiredService<IMsgLocalizer>();
|
||||
|
||||
private VanillaRoundConfig config
|
||||
=> Provider.GetService<IStorage<VanillaRoundConfig>>()
|
||||
?.Load()
|
||||
@@ -32,5 +39,7 @@ public class VanillaRound(IServiceProvider provider)
|
||||
public void OnPurchase(PlayerPurchaseItemEvent ev) {
|
||||
if (Tracker.CurrentRound != this) return;
|
||||
ev.IsCanceled = true;
|
||||
|
||||
messenger.Message(ev.Player, locale[RoundMsgs.VANILLA_ROUND_REMINDER]);
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,10 @@ public class RoundMsgs {
|
||||
|
||||
public static IMsg SPECIAL_ROUND_BHOP
|
||||
=> MsgFactory.Create(nameof(SPECIAL_ROUND_BHOP));
|
||||
|
||||
|
||||
public static IMsg SPECIAL_ROUND_VANILLA
|
||||
=> MsgFactory.Create(nameof(SPECIAL_ROUND_VANILLA)); }
|
||||
=> MsgFactory.Create(nameof(SPECIAL_ROUND_VANILLA));
|
||||
|
||||
public static IMsg VANILLA_ROUND_REMINDER
|
||||
=> MsgFactory.Create(nameof(VANILLA_ROUND_REMINDER));
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
SPECIAL_ROUND_STARTED: "%PREFIX%This round is a {purple}Special Round{grey}! This round is a {lightpurple}{0}{grey} round!"
|
||||
SPECIAL_ROUND_SPEED: " {yellow}SPEED{grey}: The round is faster than usual! {red}Traitors{grey} must kill to gain more time."
|
||||
SPECIAL_ROUND_BHOP: " {Yellow}BHOP{grey}: Bunny hopping is enabled! Hold jump to move faster!"
|
||||
SPECIAL_ROUND_VANILLA: " {green}VANILLA{grey}: The shop has been disabled!"
|
||||
SPECIAL_ROUND_VANILLA: " {green}VANILLA{grey}: The shop has been disabled!"
|
||||
VANILLA_ROUND_REMINDER: "%SHOP_PREFIX%This is a {purple}Vanilla{grey} round. The shop is disabled."
|
||||
Reference in New Issue
Block a user