mirror of
https://github.com/MSWS/TTT.git
synced 2025-12-06 14:33:52 -08:00
Compare commits
16 Commits
0.21.0-dev
...
0.22.3-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acb3be9132 | ||
|
|
bbcc998559 | ||
|
|
56781c6ae8 | ||
|
|
0ca983943d | ||
|
|
8cd8e14e18 | ||
|
|
57ef5e3e24 | ||
|
|
9c99d316aa | ||
|
|
e679c5193b | ||
|
|
6ece0450bb | ||
|
|
daa24a0e87 | ||
|
|
1c8785b388 | ||
|
|
a80c36e3c5 | ||
|
|
ba6b6c448f | ||
|
|
d30e916319 | ||
|
|
9f275fa189 | ||
|
|
40bdcac4b0 |
@@ -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);
|
||||
}
|
||||
@@ -7,7 +7,7 @@ public interface IPlayer : IEquatable<IPlayer> {
|
||||
/// </summary>
|
||||
string Id { get; }
|
||||
|
||||
string Name { get; }
|
||||
string Name { get; set; }
|
||||
|
||||
bool IEquatable<IPlayer>.Equals(IPlayer? other) {
|
||||
if (other is null) return false;
|
||||
|
||||
@@ -82,6 +82,7 @@ public static class CS2ServiceCollection {
|
||||
collection.AddModBehavior<TraitorChatHandler>();
|
||||
collection.AddModBehavior<PlayerMuter>();
|
||||
collection.AddModBehavior<MapChangeCausesEndListener>();
|
||||
collection.AddModBehavior<NameUpdater>();
|
||||
// collection.AddModBehavior<EntityTargetHandlers>();
|
||||
|
||||
// Damage Cancelers
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -12,7 +12,7 @@ public class CS2ClusterGrenadeConfig : IStorage<ClusterGrenadeConfig>,
|
||||
IPluginModule {
|
||||
public static readonly FakeConVar<int> CV_PRICE = new(
|
||||
"css_ttt_shop_clustergrenade_price",
|
||||
"Price of the Cluster Grenade item (Traitor)", 90, ConVarFlags.FCVAR_NONE,
|
||||
"Price of the Cluster Grenade item (Traitor)", 100, ConVarFlags.FCVAR_NONE,
|
||||
new RangeValidator<int>(0, 10000));
|
||||
|
||||
public static readonly FakeConVar<int> CV_GRENADE_COUNT = new(
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace TTT.CS2.Configs.ShopItems;
|
||||
public class CS2OneShotDeagleConfig : IStorage<OneShotDeagleConfig>,
|
||||
IPluginModule {
|
||||
public static readonly FakeConVar<int> CV_PRICE = new(
|
||||
"css_ttt_shop_onedeagle_price", "Price of the One-Shot Deagle item", 125,
|
||||
"css_ttt_shop_onedeagle_price", "Price of the One-Shot Deagle item", 130,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<int>(0, 10000));
|
||||
|
||||
public static readonly FakeConVar<bool> CV_FRIENDLY_FIRE = new(
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace TTT.CS2.Configs.ShopItems;
|
||||
|
||||
public class CS2StickersConfig : IStorage<StickersConfig>, IPluginModule {
|
||||
public static readonly FakeConVar<int> CV_PRICE = new(
|
||||
"css_ttt_shop_stickers_price", "Price of the Stickers item (Detective)", 25,
|
||||
"css_ttt_shop_stickers_price", "Price of the Stickers item (Detective)", 35,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<int>(0, 10000));
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
24
TTT/CS2/GameHandlers/NameUpdater.cs
Normal file
24
TTT/CS2/GameHandlers/NameUpdater.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TTT.API;
|
||||
using TTT.API.Events;
|
||||
using TTT.API.Player;
|
||||
using TTT.Game.Events.Game;
|
||||
using TTT.Game.Listeners;
|
||||
|
||||
namespace TTT.CS2.GameHandlers;
|
||||
|
||||
public class NameUpdater(IServiceProvider provider) : BaseListener(provider) {
|
||||
private readonly IPlayerConverter<CCSPlayerController> converter =
|
||||
provider.GetRequiredService<IPlayerConverter<CCSPlayerController>>();
|
||||
|
||||
[UsedImplicitly]
|
||||
[EventHandler]
|
||||
public void OnGameInit(GameInitEvent ev) {
|
||||
foreach (var player in Utilities.GetPlayers()) {
|
||||
converter.GetPlayer(player).Name = player.PlayerName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using TTT.API.Player;
|
||||
|
||||
namespace TTT.CS2.Player;
|
||||
@@ -53,7 +54,7 @@ public class CS2Player : IOnlinePlayer, IEquatable<CS2Player> {
|
||||
}
|
||||
|
||||
public string Id { get; }
|
||||
public string Name { get; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public int Health {
|
||||
get => Player?.Pawn.Value != null ? Player.Pawn.Value.Health : 0;
|
||||
@@ -96,7 +97,11 @@ public class CS2Player : IOnlinePlayer, IEquatable<CS2Player> {
|
||||
}
|
||||
|
||||
public bool IsAlive {
|
||||
get => Player != null && Player.Pawn.Value is { Health: > 0 };
|
||||
get
|
||||
=> Player != null && Player is {
|
||||
Team : CsTeam.CounterTerrorist or CsTeam.Terrorist,
|
||||
Pawn.Value.Health: > 0
|
||||
};
|
||||
|
||||
set
|
||||
=> throw new NotSupportedException(
|
||||
@@ -114,14 +119,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');
|
||||
|
||||
@@ -29,7 +29,7 @@ public class DamagedAction(IRoleAssigner roles, IPlayer victim,
|
||||
=> PlayerRole != null && OtherRole != null
|
||||
&& PlayerRole is TraitorRole != OtherRole is TraitorRole ?
|
||||
"" :
|
||||
"[BAD ACTION] ";
|
||||
"[BAD] ";
|
||||
|
||||
#region ConstructorAliases
|
||||
|
||||
|
||||
@@ -35,15 +35,15 @@ 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 ACTION] ";
|
||||
"[BAD] ";
|
||||
|
||||
#region ConstructorAliases
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
@@ -8,28 +8,30 @@ using TTT.Game.Events.Player;
|
||||
namespace TTT.Game.Roles;
|
||||
|
||||
public class RoleAssigner(IServiceProvider provider) : IRoleAssigner {
|
||||
private readonly IDictionary<IPlayer, ICollection<IRole>> assignedRoles =
|
||||
new Dictionary<IPlayer, ICollection<IRole>>();
|
||||
private readonly IDictionary<string, ICollection<IRole>> assignedRoles =
|
||||
new Dictionary<string, ICollection<IRole>>();
|
||||
|
||||
private readonly IEventBus bus = provider.GetRequiredService<IEventBus>();
|
||||
|
||||
private readonly IMessenger? onlineMessenger =
|
||||
provider.GetService<IMessenger>();
|
||||
|
||||
private static readonly Random rng = new();
|
||||
|
||||
public void AssignRoles(ISet<IOnlinePlayer> players, IList<IRole> roles) {
|
||||
assignedRoles.Clear();
|
||||
var shuffled = players.OrderBy(_ => Guid.NewGuid()).ToHashSet();
|
||||
var shuffled = players.OrderBy(_ => rng.NextDouble()).ToHashSet();
|
||||
bool roleAssigned;
|
||||
do { roleAssigned = tryAssignRole(shuffled, roles); } while (roleAssigned);
|
||||
}
|
||||
|
||||
public Task<ICollection<IRole>?> Load(IPlayer key) {
|
||||
assignedRoles.TryGetValue(key, out var roles);
|
||||
assignedRoles.TryGetValue(key.Id, out var roles);
|
||||
return Task.FromResult(roles);
|
||||
}
|
||||
|
||||
public Task Write(IPlayer key, ICollection<IRole> newData) {
|
||||
assignedRoles[key] = newData;
|
||||
assignedRoles[key.Id] = newData;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -44,9 +46,9 @@ public class RoleAssigner(IServiceProvider provider) : IRoleAssigner {
|
||||
|
||||
if (ev.IsCanceled) continue;
|
||||
|
||||
if (!assignedRoles.ContainsKey(player))
|
||||
assignedRoles[player] = new List<IRole>();
|
||||
assignedRoles[player].Add(ev.Role);
|
||||
if (!assignedRoles.ContainsKey(player.Id))
|
||||
assignedRoles[player.Id] = new List<IRole>();
|
||||
assignedRoles[player.Id].Add(ev.Role);
|
||||
ev.Role.OnAssign(player);
|
||||
|
||||
onlineMessenger?.Debug(
|
||||
|
||||
@@ -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})"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace ShopAPI.Configs.Traitor;
|
||||
|
||||
public record OneHitKnifeConfig : ShopItemConfig {
|
||||
public override int Price { get; init; } = 70;
|
||||
public override int Price { get; init; } = 80;
|
||||
public bool FriendlyFire { get; init; } = true;
|
||||
}
|
||||
@@ -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."
|
||||
@@ -10,7 +10,7 @@ public class TestPlayer(string id, string name) : IOnlinePlayer {
|
||||
// public ICollection<IRole> Roles { get; } = [];
|
||||
|
||||
public string Id { get; } = id;
|
||||
public string Name { get; } = name;
|
||||
public string Name { get; set; } = name;
|
||||
|
||||
public int Health { get; set; } = 100;
|
||||
public int MaxHealth { get; set; } = 100;
|
||||
|
||||
Reference in New Issue
Block a user