mirror of
https://github.com/MSWS/TTT.git
synced 2025-12-07 23:06:33 -08:00
Compare commits
5 Commits
0.10.0-dev
...
0.11.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a4e5e3e77 | ||
|
|
b427dc370e | ||
|
|
ede9badbd9 | ||
|
|
5736588484 | ||
|
|
8a894c65e8 |
@@ -13,28 +13,16 @@ public static class ServiceCollectionExtensions {
|
||||
this IServiceCollection collection)
|
||||
where TExtension : class, ITerrorModule {
|
||||
if (typeof(TExtension).IsAssignableTo(typeof(IPluginModule))) {
|
||||
# if DEBUG
|
||||
Console.WriteLine(
|
||||
$"[DEBUG] Registering {typeof(TExtension).Name} as IPluginModule");
|
||||
# endif
|
||||
collection.AddTransient<IPluginModule>(provider
|
||||
=> (provider.GetRequiredService<TExtension>() as IPluginModule)!);
|
||||
}
|
||||
|
||||
if (typeof(TExtension).IsAssignableTo(typeof(IListener))) {
|
||||
#if DEBUG
|
||||
Console.WriteLine(
|
||||
$"[DEBUG] Registering {typeof(TExtension).Name} as IListener");
|
||||
# endif
|
||||
collection.AddTransient<IListener>(provider
|
||||
=> (provider.GetRequiredService<TExtension>() as IListener)!);
|
||||
}
|
||||
|
||||
if (typeof(TExtension).IsAssignableTo(typeof(ICommand))) {
|
||||
#if DEBUG
|
||||
Console.WriteLine(
|
||||
$"[DEBUG] Registering {typeof(TExtension).Name} as ICommand");
|
||||
#endif
|
||||
collection.AddTransient<ICommand>(provider
|
||||
=> (provider.GetRequiredService<TExtension>() as ICommand)!);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ public interface IWeapon {
|
||||
/// <summary>
|
||||
/// The internal ID of the weapon, should match the ID of the weapon in the underlying game.
|
||||
/// </summary>
|
||||
public string Id { get; }
|
||||
public string WeaponId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The amount of ammo that is in reserve for this weapon.
|
||||
|
||||
@@ -16,7 +16,7 @@ public interface IInventoryManager {
|
||||
void RemoveWeapon(IOnlinePlayer player, string weaponId);
|
||||
|
||||
void RemoveWeapon(IOnlinePlayer player, IWeapon weapon) {
|
||||
RemoveWeapon(player, weapon.Id);
|
||||
RemoveWeapon(player, weapon.WeaponId);
|
||||
}
|
||||
|
||||
void RemoveWeaponInSlot(IOnlinePlayer player, int slot);
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
namespace TTT.API.Player;
|
||||
|
||||
public interface IOnlinePlayer : IPlayer {
|
||||
// [Obsolete(
|
||||
// "Roles are now managed via IRoleAssigner. Use IRoleAssigner.GetRoles(IPlayer) instead.")]
|
||||
// ICollection<IRole> Roles { get; }
|
||||
|
||||
public int Health { get; set; }
|
||||
public int MaxHealth { get; set; }
|
||||
public int Armor { get; set; }
|
||||
|
||||
@@ -32,7 +32,8 @@ public static class PlayerExtensions {
|
||||
if (!player.IsValid || pawn == null || !pawn.IsValid) return;
|
||||
|
||||
if (color.A == 255)
|
||||
color = Color.FromArgb(pawn.Render.A, color.R, color.G, color.B);
|
||||
color = Color.FromArgb(pawn.Render.A == 255 ? 255 : 254, color.R, color.G,
|
||||
color.B);
|
||||
pawn.SetColor(color);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ public class BodySpawner(IServiceProvider provider) : IPluginModule {
|
||||
return HookResult.Continue;
|
||||
var player = ev.Userid;
|
||||
if (player == null || !player.IsValid) return HookResult.Continue;
|
||||
player.SetColor(Color.FromArgb(0, 0, 0, 0));
|
||||
player.SetColor(Color.FromArgb(0, 255, 255, 255));
|
||||
|
||||
var ragdollBody = makeGameRagdoll(player);
|
||||
var body = new CS2Body(provider, ragdollBody, converter.GetPlayer(player));
|
||||
@@ -54,7 +54,7 @@ public class BodySpawner(IServiceProvider provider) : IPluginModule {
|
||||
public HookResult OnStart(EventRoundStart ev, GameEventInfo _) {
|
||||
Server.NextWorldUpdate(() => {
|
||||
foreach (var player in Utilities.GetPlayers())
|
||||
player.SetColor(Color.FromArgb(254, 255, 255, 255));
|
||||
player.SetColor(Color.White);
|
||||
});
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public class PlayerStatsTracker(IServiceProvider provider) : IListener {
|
||||
|
||||
// Needs to be higher so we detect the kill before the game ends
|
||||
// in the case that this is the last player
|
||||
[EventHandler(Priority = Priority.HIGHER)]
|
||||
[EventHandler(Priority = Priority.HIGH)]
|
||||
public void OnKill(PlayerDeathEvent ev) {
|
||||
var killer = ev.Killer == null ? null : converter.GetPlayer(ev.Killer);
|
||||
var assister =
|
||||
|
||||
@@ -43,7 +43,7 @@ public class RoundTimerListener(IServiceProvider provider)
|
||||
player.Respawn();
|
||||
|
||||
foreach (var player in Utilities.GetPlayers())
|
||||
player.SetColor(Color.FromArgb(254, 255, 255, 255));
|
||||
player.SetColor(Color.White);
|
||||
});
|
||||
|
||||
return;
|
||||
|
||||
@@ -22,10 +22,10 @@ public class CS2InventoryManager(
|
||||
if (player.Team is CsTeam.None or CsTeam.Spectator) return;
|
||||
|
||||
// Give the weapon
|
||||
player.GiveNamedItem(weapon.Id);
|
||||
player.GiveNamedItem(weapon.WeaponId);
|
||||
|
||||
// Set ammo if applicable
|
||||
var weaponBase = player.GetWeaponBase(weapon.Id);
|
||||
var weaponBase = player.GetWeaponBase(weapon.WeaponId);
|
||||
if (weaponBase == null) return;
|
||||
if (weapon.CurrentAmmo != null) weaponBase.Clip1 = weapon.CurrentAmmo.Value;
|
||||
if (weapon.ReserveAmmo != null) weaponBase.Clip2 = weapon.ReserveAmmo.Value;
|
||||
|
||||
@@ -80,6 +80,6 @@ public class PlayerDamagedEvent(IOnlinePlayer player, IOnlinePlayer? attacker,
|
||||
}
|
||||
}
|
||||
|
||||
public string? Weapon { get; private set; }
|
||||
public string? Weapon { get; init; }
|
||||
public bool IsCanceled { get; set; }
|
||||
}
|
||||
@@ -9,7 +9,7 @@ namespace TTT.Game.Listeners.Loggers;
|
||||
public class PlayerActionsLogger(IServiceProvider provider)
|
||||
: BaseListener(provider) {
|
||||
// Needs to be higher so we detect the kill before the game ends
|
||||
[EventHandler(Priority = Priority.HIGHER)]
|
||||
[EventHandler(Priority = Priority.HIGH)]
|
||||
[UsedImplicitly]
|
||||
public void OnPlayerKill(PlayerDeathEvent ev) {
|
||||
if (Games.ActiveGame is not { State: State.IN_PROGRESS }) return;
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace TTT.Game.Roles;
|
||||
|
||||
public class BaseWeapon(string id, int? reserve = null,
|
||||
int? current = null) : IWeapon {
|
||||
public string Id { get; } = id;
|
||||
public string WeaponId { get; } = id;
|
||||
public int? ReserveAmmo { get; } = reserve;
|
||||
public int? CurrentAmmo { get; } = current;
|
||||
}
|
||||
@@ -5,7 +5,7 @@ the subsidiary projects (i.e. not [Versioning](../Versioning)).
|
||||
|
||||
# Structure
|
||||
## [API](./API)
|
||||
The public API for TTT. Use this to add-on extra features, modules, roles, etc.
|
||||
The public API for TTT. Include this to add-on extra features, modules, roles, etc.
|
||||
|
||||
## [CS2](./CS2)
|
||||
A linker for CS2 to TTT. This adds support for CS2 to TTT.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TTT.API.Events;
|
||||
using TTT.API.Game;
|
||||
@@ -18,6 +19,7 @@ public class DeagleDamageListener(IServiceProvider provider)
|
||||
|
||||
private readonly IShop shop = provider.GetRequiredService<IShop>();
|
||||
|
||||
[UsedImplicitly]
|
||||
[EventHandler]
|
||||
public void OnDamage(PlayerDamagedEvent ev) {
|
||||
Messenger.Debug("DeagleDamageListener: OnDamage");
|
||||
|
||||
@@ -47,7 +47,7 @@ public class OneShotDeagle(IServiceProvider provider) : IWeapon, IShopItem {
|
||||
|
||||
string IShopItem.Id => ID;
|
||||
|
||||
public string Id => deagleConfigStorage.Weapon;
|
||||
public string WeaponId => deagleConfigStorage.Weapon;
|
||||
|
||||
public int? ReserveAmmo { get; init; } = 0;
|
||||
public int? CurrentAmmo { get; init; } = 1;
|
||||
|
||||
@@ -12,7 +12,7 @@ public class RoundShopClearer(IServiceProvider provider) : IListener {
|
||||
|
||||
public void Dispose() { bus.UnregisterListener(this); }
|
||||
|
||||
[EventHandler(IgnoreCanceled = true, Priority = Priority.LOWER)]
|
||||
[EventHandler(IgnoreCanceled = true, Priority = Priority.LOW)]
|
||||
[UsedImplicitly]
|
||||
public void OnRoundStart(GameStateUpdateEvent ev) {
|
||||
// Only clear balances if the round is in progress
|
||||
|
||||
69
TTT/Test/Shop/Items/DeagleTests.cs
Normal file
69
TTT/Test/Shop/Items/DeagleTests.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TTT.API.Events;
|
||||
using TTT.API.Game;
|
||||
using TTT.API.Player;
|
||||
using TTT.Game.Events.Player;
|
||||
using TTT.Shop;
|
||||
using TTT.Shop.Items;
|
||||
using Xunit;
|
||||
|
||||
namespace TTT.Test.Shop.Items;
|
||||
|
||||
public class DeagleTests {
|
||||
private readonly IServiceProvider provider;
|
||||
private readonly IEventBus bus;
|
||||
private readonly TestPlayer testPlayer;
|
||||
private readonly IOnlinePlayer victim, survivor;
|
||||
private readonly IShop shop;
|
||||
private readonly OneShotDeagle item;
|
||||
|
||||
public DeagleTests(IServiceProvider provider) {
|
||||
this.provider = provider;
|
||||
var games = provider.GetRequiredService<IGameManager>();
|
||||
var finder = provider.GetRequiredService<IPlayerFinder>();
|
||||
shop = provider.GetRequiredService<IShop>();
|
||||
bus = provider.GetRequiredService<IEventBus>();
|
||||
item = new OneShotDeagle(provider);
|
||||
|
||||
testPlayer = (finder.AddPlayer(TestPlayer.Random()) as TestPlayer)!;
|
||||
victim = finder.AddPlayer(TestPlayer.Random());
|
||||
survivor = finder.AddPlayer(TestPlayer.Random());
|
||||
|
||||
games.CreateGame()?.Start();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Deagle_Kills_OnDamage() {
|
||||
bus.RegisterListener(new DeagleDamageListener(provider));
|
||||
shop.GiveItem(testPlayer, item);
|
||||
|
||||
var playerDmgEvent =
|
||||
new PlayerDamagedEvent(victim, testPlayer, 1, 99) {
|
||||
Weapon = item.WeaponId
|
||||
};
|
||||
bus.Dispatch(playerDmgEvent);
|
||||
|
||||
Assert.Equal(0, victim.Health);
|
||||
Assert.False(victim.IsAlive);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Deagle_DoesNotKill_AfterFirstKill() {
|
||||
bus.RegisterListener(new DeagleDamageListener(provider));
|
||||
shop.GiveItem(testPlayer, item);
|
||||
|
||||
var playerDmgEvent =
|
||||
new PlayerDamagedEvent(victim, testPlayer, 1, 99) {
|
||||
Weapon = item.WeaponId
|
||||
};
|
||||
bus.Dispatch(playerDmgEvent);
|
||||
|
||||
var secondDmgEvent =
|
||||
new PlayerDamagedEvent(survivor, testPlayer, 1, 99) {
|
||||
Weapon = item.WeaponId
|
||||
};
|
||||
bus.Dispatch(secondDmgEvent);
|
||||
|
||||
Assert.NotEqual(0, survivor.Health);
|
||||
}
|
||||
}
|
||||
56
TTT/Test/Shop/ShopTests.cs
Normal file
56
TTT/Test/Shop/ShopTests.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TTT.API.Events;
|
||||
using TTT.API.Game;
|
||||
using TTT.API.Player;
|
||||
using TTT.Shop;
|
||||
using TTT.Shop.Listeners;
|
||||
using Xunit;
|
||||
|
||||
namespace TTT.Test.Shop;
|
||||
|
||||
public class ShopTests(IServiceProvider provider) {
|
||||
private readonly IShop shop = provider.GetRequiredService<IShop>();
|
||||
private readonly IOnlinePlayer player = TestPlayer.Random();
|
||||
private readonly IEventBus bus = provider.GetRequiredService<IEventBus>();
|
||||
|
||||
private readonly IGameManager games =
|
||||
provider.GetRequiredService<IGameManager>();
|
||||
|
||||
private readonly IPlayerFinder finder =
|
||||
provider.GetRequiredService<IPlayerFinder>();
|
||||
|
||||
[Fact]
|
||||
public void GiveItem_ShowsInInventory() {
|
||||
shop.GiveItem(player, new TestShopItem());
|
||||
Assert.Single(shop.GetOwnedItems(player));
|
||||
Assert.Equal(TestShopItem.ID, shop.GetOwnedItems(player)[0].Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ClearBalances_ClearsBalances() {
|
||||
shop.AddBalance(player, 500, "Test");
|
||||
Assert.Equal(500, await shop.Load(player));
|
||||
shop.ClearBalances();
|
||||
Assert.Equal(0, await shop.Load(player));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClearItems_ClearsItems() {
|
||||
shop.GiveItem(player, new TestShopItem());
|
||||
shop.ClearItems();
|
||||
Assert.Empty(shop.GetOwnedItems(player));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Shop_ClearsItems_OnNewRound() {
|
||||
bus.RegisterListener(new RoundShopClearer(provider));
|
||||
|
||||
finder.AddPlayers(player, TestPlayer.Random());
|
||||
games.CreateGame()?.Start();
|
||||
shop.GiveItem(player, new TestShopItem());
|
||||
games.ActiveGame?.EndGame();
|
||||
games.CreateGame()?.Start();
|
||||
|
||||
Assert.Empty(shop.GetOwnedItems(player));
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,15 @@ public class TestPlayer(string id, string name) : IOnlinePlayer {
|
||||
public int Health { get; set; } = 100;
|
||||
public int MaxHealth { get; set; } = 100;
|
||||
public int Armor { get; set; } = 100;
|
||||
public bool IsAlive { get; set; } = true;
|
||||
|
||||
public bool IsAlive {
|
||||
get => Health > 0;
|
||||
set {
|
||||
if (!value)
|
||||
Health = 0;
|
||||
else if (Health <= 0) { Health = 1; }
|
||||
}
|
||||
}
|
||||
|
||||
public static TestPlayer Random() {
|
||||
return new TestPlayer(new Random().NextInt64().ToString(),
|
||||
|
||||
Reference in New Issue
Block a user