mirror of
https://github.com/MSWS/TTT.git
synced 2025-12-07 23:06:33 -08:00
Compare commits
26 Commits
0.17.0-dev
...
0.18.0-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31f1403b9b | ||
|
|
d12cfa5eab | ||
|
|
9022416053 | ||
|
|
6524772d4f | ||
|
|
bd8125b7a0 | ||
|
|
695d34c10c | ||
|
|
9d3ecbe7fb | ||
|
|
85dac3622a | ||
|
|
9e4c29e3f7 | ||
|
|
453ba14126 | ||
|
|
91750a1067 | ||
|
|
dd6b8c00fe | ||
|
|
d9ad08aa27 | ||
|
|
35191f23e1 | ||
|
|
ad29de1bc5 | ||
|
|
0a0416bff0 | ||
|
|
62c96123d1 | ||
|
|
274716267f | ||
|
|
c20842575b | ||
|
|
cf8169a10e | ||
|
|
3dcc3a7de5 | ||
|
|
65bcafca79 | ||
|
|
6cac535e94 | ||
|
|
ab3dfbda45 | ||
|
|
324a19c457 | ||
|
|
fda4c72da5 |
@@ -84,7 +84,6 @@ public static class CS2ServiceCollection {
|
||||
// Commands
|
||||
#if DEBUG
|
||||
collection.AddModBehavior<TestCommand>();
|
||||
collection.AddModBehavior<DebugMessage>();
|
||||
#endif
|
||||
|
||||
collection.AddScoped<IGameManager, CS2GameManager>();
|
||||
|
||||
41
TTT/CS2/Command/Test/SpecCommand.cs
Normal file
41
TTT/CS2/Command/Test/SpecCommand.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TTT.API.Command;
|
||||
using TTT.API.Player;
|
||||
|
||||
namespace TTT.CS2.Command.Test;
|
||||
|
||||
public class SpecCommand(IServiceProvider provider) : ICommand {
|
||||
public void Dispose() { }
|
||||
public void Start() { }
|
||||
|
||||
public Task<CommandResult>
|
||||
Execute(IOnlinePlayer? executor, ICommandInfo info) {
|
||||
var target = executor;
|
||||
|
||||
if (info.ArgCount == 2) {
|
||||
var finder = provider.GetRequiredService<IPlayerFinder>();
|
||||
var result = finder.GetPlayerByName(info.Args[1]);
|
||||
if (result == null) {
|
||||
info.ReplySync($"Player '{info.Args[1]}' not found.");
|
||||
return Task.FromResult(CommandResult.ERROR);
|
||||
}
|
||||
|
||||
target = result;
|
||||
} else if (target == null) {
|
||||
return Task.FromResult(CommandResult.PLAYER_ONLY);
|
||||
}
|
||||
|
||||
var converter =
|
||||
provider.GetRequiredService<IPlayerConverter<CCSPlayerController>>();
|
||||
|
||||
Server.NextWorldUpdate(() => {
|
||||
var player = converter.GetPlayer(target);
|
||||
player?.ChangeTeam(CsTeam.Spectator);
|
||||
info.ReplySync($"{target.Name} has been moved to Spectators.");
|
||||
});
|
||||
return Task.FromResult(CommandResult.SUCCESS);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ public class TestCommand(IServiceProvider provider) : ICommand, IPluginModule {
|
||||
subCommands.Add("sethealth", new SetHealthCommand());
|
||||
subCommands.Add("emitsound", new EmitSoundCommand(provider));
|
||||
subCommands.Add("credits", new CreditsCommand(provider));
|
||||
subCommands.Add("spec", new SpecCommand(provider));
|
||||
}
|
||||
|
||||
public Task<CommandResult>
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace TTT.CS2.Configs;
|
||||
|
||||
public class CS2TaserConfig : IStorage<TaserConfig>, IPluginModule {
|
||||
public static readonly FakeConVar<int> CV_PRICE = new(
|
||||
"css_ttt_shop_taser_price", "Price of the Taser item", 100,
|
||||
"css_ttt_shop_taser_price", "Price of the Taser item", 120,
|
||||
ConVarFlags.FCVAR_NONE, new RangeValidator<int>(0, 10000));
|
||||
|
||||
public static readonly FakeConVar<string> CV_WEAPON = new(
|
||||
|
||||
@@ -6,18 +6,17 @@ using CounterStrikeSharp.API.Modules.Entities.Constants;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TTT.API;
|
||||
using TTT.API.Events;
|
||||
using TTT.API.Game;
|
||||
using TTT.API.Player;
|
||||
using TTT.CS2.Extensions;
|
||||
using TTT.Game.Events.Body;
|
||||
using TTT.Game.Events.Player;
|
||||
using TTT.Game.Listeners;
|
||||
using TTT.Game.Roles;
|
||||
|
||||
namespace TTT.CS2.GameHandlers;
|
||||
|
||||
public class BodySpawner(IServiceProvider provider) : BaseListener(provider) {
|
||||
public class BodySpawner(IServiceProvider provider) : IPluginModule {
|
||||
private readonly IEventBus bus = provider.GetRequiredService<IEventBus>();
|
||||
|
||||
private readonly IPlayerConverter<CCSPlayerController> converter =
|
||||
@@ -26,40 +25,31 @@ public class BodySpawner(IServiceProvider provider) : BaseListener(provider) {
|
||||
private readonly IGameManager games =
|
||||
provider.GetRequiredService<IGameManager>();
|
||||
|
||||
[UsedImplicitly]
|
||||
[EventHandler]
|
||||
public void OnLeave(PlayerLeaveEvent ev) {
|
||||
if (games.ActiveGame is not { State: State.IN_PROGRESS }) return;
|
||||
spawnRagdoll(ev.Player);
|
||||
}
|
||||
public void Dispose() { }
|
||||
public void Start() { }
|
||||
|
||||
[UsedImplicitly]
|
||||
[EventHandler]
|
||||
public void OnDeath(PlayerDeathEvent ev) {
|
||||
if (games.ActiveGame is not { State: State.IN_PROGRESS }) return;
|
||||
spawnRagdoll(ev.Player, ev.Killer, ev.Weapon);
|
||||
}
|
||||
|
||||
private void spawnRagdoll(IPlayer apiPlayer, IOnlinePlayer? killer = null,
|
||||
string? weapon = null) {
|
||||
var player = converter.GetPlayer(apiPlayer);
|
||||
if (player == null || !player.IsValid) return;
|
||||
[GameEventHandler]
|
||||
public HookResult OnDeath(EventPlayerDeath ev, GameEventInfo _) {
|
||||
if (games.ActiveGame is not { State: State.IN_PROGRESS })
|
||||
return HookResult.Continue;
|
||||
var player = ev.Userid;
|
||||
if (player == null || !player.IsValid) return HookResult.Continue;
|
||||
player.SetColor(Color.FromArgb(0, 255, 255, 255));
|
||||
|
||||
var ragdollBody = makeGameRagdoll(player);
|
||||
var body = new CS2Body(ragdollBody, converter.GetPlayer(player));
|
||||
|
||||
if (killer != null) body.WithKiller(killer);
|
||||
if (ev.Attacker != null && ev.Attacker.IsValid)
|
||||
body.WithKiller(converter.GetPlayer(ev.Attacker));
|
||||
|
||||
body.WithWeapon(new BaseWeapon(weapon ?? "unknown"));
|
||||
body.WithWeapon(new BaseWeapon(ev.Weapon));
|
||||
|
||||
var bodyCreatedEvent = new BodyCreateEvent(body);
|
||||
bus.Dispatch(bodyCreatedEvent);
|
||||
|
||||
if (bodyCreatedEvent.IsCanceled) {
|
||||
ragdollBody.AcceptInput("Kill");
|
||||
// ragdollBody.Remove();
|
||||
}
|
||||
if (bodyCreatedEvent.IsCanceled) ragdollBody.AcceptInput("Kill");
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.UserMessages;
|
||||
using TTT.API;
|
||||
|
||||
namespace TTT.CS2.GameHandlers;
|
||||
|
||||
public class DebugMessage : IPluginModule {
|
||||
public void Dispose() { }
|
||||
public void Start() { }
|
||||
|
||||
public void Start(BasePlugin? plugin) {
|
||||
for (var i = 0; i < 10000; i++) {
|
||||
if (i is 325 or 124) continue;
|
||||
var j = i;
|
||||
plugin.HookUserMessage(i, msg => debug(msg, j));
|
||||
}
|
||||
}
|
||||
|
||||
private HookResult debug(UserMessage native, int id) {
|
||||
Server.PrintToConsole(id + "");
|
||||
Server.PrintToConsole(native.DebugString);
|
||||
return HookResult.Continue;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,24 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TTT.API.Events;
|
||||
using TTT.API.Game;
|
||||
using TTT.API.Player;
|
||||
using TTT.CS2.Extensions;
|
||||
using TTT.Game.Events.Game;
|
||||
using TTT.Game.Events.Player;
|
||||
using TTT.Game.Listeners;
|
||||
|
||||
namespace TTT.CS2.Listeners;
|
||||
namespace TTT.CS2.GameHandlers;
|
||||
|
||||
public class LateSpawnListener(IServiceProvider provider)
|
||||
: BaseListener(provider) {
|
||||
private readonly IPlayerConverter<CCSPlayerController> converter =
|
||||
provider.GetRequiredService<IPlayerConverter<CCSPlayerController>>();
|
||||
|
||||
[UsedImplicitly]
|
||||
[EventHandler]
|
||||
public void OnJoin(PlayerJoinEvent ev) {
|
||||
if (Games.ActiveGame is { State: State.IN_PROGRESS }) return;
|
||||
@@ -24,4 +29,17 @@ public class LateSpawnListener(IServiceProvider provider)
|
||||
player.Respawn();
|
||||
});
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
[EventHandler]
|
||||
public void GameState(GameStateUpdateEvent ev) {
|
||||
if (ev.NewState == State.FINISHED) return;
|
||||
|
||||
Server.NextWorldUpdate(() => {
|
||||
foreach (var player in Utilities.GetPlayers()
|
||||
.Where(p => p.GetHealth() <= 0 && p.Team != CsTeam.Spectator
|
||||
&& p.Team != CsTeam.None))
|
||||
player.Respawn();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ using TTT.API;
|
||||
using TTT.API.Events;
|
||||
using TTT.API.Game;
|
||||
using TTT.API.Player;
|
||||
using TTT.CS2.Extensions;
|
||||
using TTT.Game.Events.Player;
|
||||
|
||||
namespace TTT.CS2.GameHandlers;
|
||||
@@ -44,7 +45,7 @@ public class TeamChangeHandler(IServiceProvider provider) : IPluginModule {
|
||||
};
|
||||
|
||||
if (games.ActiveGame is not { State: State.IN_PROGRESS }) {
|
||||
if (player != null && player.LifeState != (int)LifeState_t.LIFE_ALIVE)
|
||||
if (player != null && player.GetHealth() <= 0)
|
||||
Server.NextWorldUpdate(player.Respawn);
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Commands;
|
||||
using CounterStrikeSharp.API.Modules.Utils;
|
||||
using MAULActainShared.plugin;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using TTT.API;
|
||||
@@ -36,7 +37,7 @@ public class TraitorChatHandler(IServiceProvider provider) : IPluginModule {
|
||||
try {
|
||||
maulService ??= EgoApi.MAUL.Get();
|
||||
if (maulService != null) {
|
||||
maulService.getChatShareService().OnChatShare += OnOnChatShare;
|
||||
maulService.getChatShareService().OnChatShare += OnChatShare;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -48,17 +49,21 @@ public class TraitorChatHandler(IServiceProvider provider) : IPluginModule {
|
||||
|
||||
public void Dispose() {
|
||||
if (maulService != null)
|
||||
maulService.getChatShareService().OnChatShare -= OnOnChatShare;
|
||||
maulService.getChatShareService().OnChatShare -= OnChatShare;
|
||||
}
|
||||
|
||||
public void Start() { }
|
||||
|
||||
private void OnOnChatShare(CCSPlayerController? player, CommandInfo info,
|
||||
private void OnChatShare(CCSPlayerController? player, CommandInfo info,
|
||||
ref bool canceled) {
|
||||
if (player == null) return;
|
||||
if (!info.GetArg(0).Equals("say_team", StringComparison.OrdinalIgnoreCase))
|
||||
return;
|
||||
var result = onSay(player, info);
|
||||
if (result == HookResult.Handled) canceled = true;
|
||||
if (player.Team == CsTeam.CounterTerrorist) return;
|
||||
var result = onSay(player, info);
|
||||
canceled = true;
|
||||
if (result == HookResult.Handled) return;
|
||||
player?.ExecuteClientCommandFromServer("say " + info.ArgString);
|
||||
}
|
||||
|
||||
private HookResult onSay(CCSPlayerController? player,
|
||||
|
||||
@@ -16,11 +16,11 @@ public static class ArmorItemServicesCollection {
|
||||
}
|
||||
|
||||
public class ArmorItem(IServiceProvider provider) : BaseItem(provider) {
|
||||
private readonly ArmorConfig config = provider
|
||||
.GetService<IStorage<ArmorConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new ArmorConfig();
|
||||
private ArmorConfig config
|
||||
=> Provider.GetService<IStorage<ArmorConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new ArmorConfig();
|
||||
|
||||
private readonly IPlayerConverter<CCSPlayerController> converter =
|
||||
provider.GetRequiredService<IPlayerConverter<CCSPlayerController>>();
|
||||
|
||||
@@ -17,11 +17,11 @@ public static class BodyPaintServicesCollection {
|
||||
|
||||
public class BodyPaintItem(IServiceProvider provider)
|
||||
: RoleRestrictedItem<TraitorRole>(provider) {
|
||||
private readonly BodyPaintConfig config = provider
|
||||
.GetService<IStorage<BodyPaintConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new BodyPaintConfig();
|
||||
private BodyPaintConfig config
|
||||
=> Provider.GetService<IStorage<BodyPaintConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new BodyPaintConfig();
|
||||
|
||||
public override string Name => Locale[BodyPaintMsgs.SHOP_ITEM_BODY_PAINT];
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@ public static class ClusterGrenadeServiceCollection {
|
||||
|
||||
public class ClusterGrenadeItem(IServiceProvider provider)
|
||||
: RoleRestrictedItem<TraitorRole>(provider) {
|
||||
private readonly ClusterGrenadeConfig config = provider
|
||||
.GetService<IStorage<ClusterGrenadeConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new ClusterGrenadeConfig();
|
||||
private ClusterGrenadeConfig config
|
||||
=> Provider.GetService<IStorage<ClusterGrenadeConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new ClusterGrenadeConfig();
|
||||
|
||||
public override string Name
|
||||
=> Locale[ClusterGrenadeMsgs.SHOP_ITEM_CLUSTER_GRENADE];
|
||||
|
||||
@@ -17,8 +17,8 @@ using TTT.API.Storage;
|
||||
namespace TTT.CS2.Items.ClusterGrenade;
|
||||
|
||||
public class ClusterGrenadeListener(IServiceProvider provider) : IPluginModule {
|
||||
private readonly ClusterGrenadeConfig config =
|
||||
provider.GetService<IStorage<ClusterGrenadeConfig>>()
|
||||
private ClusterGrenadeConfig config
|
||||
=> provider.GetService<IStorage<ClusterGrenadeConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new ClusterGrenadeConfig();
|
||||
|
||||
@@ -28,11 +28,11 @@ public class DnaListener(IServiceProvider provider) : BaseListener(provider) {
|
||||
private readonly IBodyTracker bodies =
|
||||
provider.GetRequiredService<IBodyTracker>();
|
||||
|
||||
private readonly DnaScannerConfig config = provider
|
||||
.GetService<IStorage<DnaScannerConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new DnaScannerConfig();
|
||||
private DnaScannerConfig config
|
||||
=> Provider.GetService<IStorage<DnaScannerConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new DnaScannerConfig();
|
||||
|
||||
private readonly Dictionary<string, DateTime> lastMessages = new();
|
||||
private readonly IShop shop = provider.GetRequiredService<IShop>();
|
||||
|
||||
@@ -18,11 +18,11 @@ public static class DnaScannerServiceCollection {
|
||||
|
||||
public class DnaScanner(IServiceProvider provider)
|
||||
: RoleRestrictedItem<DetectiveRole>(provider) {
|
||||
private readonly DnaScannerConfig config = provider
|
||||
.GetService<IStorage<DnaScannerConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new DnaScannerConfig();
|
||||
private DnaScannerConfig config
|
||||
=> Provider.GetService<IStorage<DnaScannerConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new DnaScannerConfig();
|
||||
|
||||
public override string Name => Locale[DnaMsgs.SHOP_ITEM_DNA];
|
||||
public override string Description => Locale[DnaMsgs.SHOP_ITEM_DNA_DESC];
|
||||
|
||||
@@ -18,11 +18,11 @@ public static class OneHitKnifeServiceCollection {
|
||||
|
||||
public class OneHitKnife(IServiceProvider provider)
|
||||
: RoleRestrictedItem<TraitorRole>(provider) {
|
||||
private readonly OneHitKnifeConfig config = provider
|
||||
.GetService<IStorage<OneHitKnifeConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new OneHitKnifeConfig();
|
||||
private OneHitKnifeConfig config
|
||||
=> Provider.GetService<IStorage<OneHitKnifeConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new OneHitKnifeConfig();
|
||||
|
||||
public override string Name
|
||||
=> Locale[OneHitKnifeMsgs.SHOP_ITEM_ONE_HIT_KNIFE];
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace TTT.CS2.Items.OneHitKnife;
|
||||
|
||||
public class OneHitKnifeListener(IServiceProvider provider)
|
||||
: BaseListener(provider) {
|
||||
private readonly OneHitKnifeConfig config =
|
||||
provider.GetService<IStorage<OneHitKnifeConfig>>()
|
||||
private OneHitKnifeConfig config
|
||||
=> Provider.GetService<IStorage<OneHitKnifeConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new OneHitKnifeConfig();
|
||||
|
||||
@@ -18,11 +18,11 @@ public static class PoisonShotServiceCollection {
|
||||
|
||||
public class PoisonShotsItem(IServiceProvider provider)
|
||||
: RoleRestrictedItem<TraitorRole>(provider) {
|
||||
private readonly PoisonShotsConfig config = provider
|
||||
.GetService<IStorage<PoisonShotsConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new PoisonShotsConfig();
|
||||
private PoisonShotsConfig config
|
||||
=> Provider.GetService<IStorage<PoisonShotsConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new PoisonShotsConfig();
|
||||
|
||||
public override string Name => Locale[PoisonShotMsgs.SHOP_ITEM_POISON_SHOTS];
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ public class PoisonShotsListener(IServiceProvider provider)
|
||||
|
||||
private readonly IShop shop = provider.GetRequiredService<IShop>();
|
||||
|
||||
private readonly ISet<string> killedWithPoison = new HashSet<string>();
|
||||
private readonly Dictionary<string, IPlayer> killedWithPoison = new();
|
||||
|
||||
public override void Dispose() {
|
||||
base.Dispose();
|
||||
@@ -118,20 +118,18 @@ public class PoisonShotsListener(IServiceProvider provider)
|
||||
if (dmgEvent.IsCanceled) return true;
|
||||
|
||||
if (online.Health - config.PoisonConfig.DamagePerTick <= 0) {
|
||||
killedWithPoison.Add(online.Id);
|
||||
killedWithPoison[online.Id] = effect.Shooter;
|
||||
var deathEvent = new PlayerDeathEvent(online)
|
||||
.WithKiller(effect.Shooter as IOnlinePlayer)
|
||||
.WithWeapon($"[{Locale[PoisonShotMsgs.SHOP_ITEM_POISON_SHOTS]}]");
|
||||
bus.Dispatch(deathEvent);
|
||||
}
|
||||
|
||||
// online.Health -= config.PoisonConfig.DamagePerTick;
|
||||
effect.Ticks++;
|
||||
effect.DamageGiven += config.PoisonConfig.DamagePerTick;
|
||||
|
||||
var gamePlayer = converter.GetPlayer(online);
|
||||
gamePlayer?.ColorScreen(config.PoisonColor, 0.2f, 0.3f);
|
||||
// gamePlayer?.ExecuteClientCommand("play " + config.PoisonConfig.PoisonSound);
|
||||
if (gamePlayer != null)
|
||||
gamePlayer.DealPoisonDamage(config.PoisonConfig.DamagePerTick);
|
||||
|
||||
@@ -169,8 +167,10 @@ public class PoisonShotsListener(IServiceProvider provider)
|
||||
[UsedImplicitly]
|
||||
[EventHandler]
|
||||
public void OnRagdollSpawn(BodyCreateEvent ev) {
|
||||
if (!killedWithPoison.Contains(ev.Body.OfPlayer.Id)) return;
|
||||
if (ev.Body.Killer == null || ev.Body.Killer.Id == ev.Body.OfPlayer.Id)
|
||||
ev.IsCanceled = true;
|
||||
if (!killedWithPoison.TryGetValue(ev.Body.OfPlayer.Id, out var shooter))
|
||||
return;
|
||||
if (ev.Body.Killer != null && ev.Body.Killer.Id != ev.Body.OfPlayer.Id)
|
||||
return;
|
||||
ev.Body.Killer = shooter as IOnlinePlayer;
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,8 @@ public static class PoisonSmokeServiceCollection {
|
||||
|
||||
public class PoisonSmokeItem(IServiceProvider provider)
|
||||
: RoleRestrictedItem<TraitorRole>(provider) {
|
||||
private readonly PoisonSmokeConfig config =
|
||||
provider.GetService<IStorage<PoisonSmokeConfig>>()
|
||||
private PoisonSmokeConfig config
|
||||
=> Provider.GetService<IStorage<PoisonSmokeConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new PoisonSmokeConfig();
|
||||
|
||||
@@ -25,8 +25,8 @@ namespace TTT.CS2.Items.PoisonSmoke;
|
||||
|
||||
public class PoisonSmokeListener(IServiceProvider provider)
|
||||
: BaseListener(provider), IPluginModule {
|
||||
private readonly PoisonSmokeConfig config =
|
||||
provider.GetService<IStorage<PoisonSmokeConfig>>()
|
||||
private PoisonSmokeConfig config
|
||||
=> Provider.GetService<IStorage<PoisonSmokeConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new PoisonSmokeConfig();
|
||||
|
||||
@@ -24,8 +24,8 @@ public static class SilentAWPServiceCollection {
|
||||
|
||||
public class SilentAWPItem(IServiceProvider provider)
|
||||
: RoleRestrictedItem<TraitorRole>(provider), IPluginModule {
|
||||
private readonly SilentAWPConfig config =
|
||||
provider.GetService<IStorage<SilentAWPConfig>>()
|
||||
private SilentAWPConfig config
|
||||
=> Provider.GetService<IStorage<SilentAWPConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new SilentAWPConfig();
|
||||
|
||||
@@ -10,6 +10,7 @@ using TTT.API.Player;
|
||||
using TTT.API.Role;
|
||||
using TTT.API.Storage;
|
||||
using TTT.CS2.Extensions;
|
||||
using TTT.CS2.Utils;
|
||||
using TTT.Game.Events.Body;
|
||||
using TTT.Game.Events.Game;
|
||||
using TTT.Game.Events.Player;
|
||||
@@ -45,7 +46,8 @@ public class DamageStation(IServiceProvider provider)
|
||||
public override string Description
|
||||
=> Locale[StationMsgs.SHOP_ITEM_STATION_HURT_DESC];
|
||||
|
||||
private readonly ISet<string> killedWithStation = new HashSet<string>();
|
||||
private Dictionary<string, StationInfo> killedWithStation =
|
||||
new Dictionary<string, StationInfo>();
|
||||
|
||||
override protected void onInterval() {
|
||||
var players = finder.GetOnline();
|
||||
@@ -87,7 +89,7 @@ public class DamageStation(IServiceProvider provider)
|
||||
damageAmount = -dmgEvent.DmgDealt;
|
||||
|
||||
if (player.Health + damageAmount <= 0) {
|
||||
killedWithStation.Add(player.Id);
|
||||
killedWithStation[player.Id] = info;
|
||||
var playerDeath = new PlayerDeathEvent(player)
|
||||
.WithKiller(info.Owner as IOnlinePlayer)
|
||||
.WithWeapon($"[{Name}]");
|
||||
@@ -115,8 +117,11 @@ public class DamageStation(IServiceProvider provider)
|
||||
[UsedImplicitly]
|
||||
[EventHandler]
|
||||
public void OnRagdollSpawn(BodyCreateEvent ev) {
|
||||
if (!killedWithStation.Contains(ev.Body.OfPlayer.Id)) return;
|
||||
if (ev.Body.Killer == null || ev.Body.Killer.Id == ev.Body.OfPlayer.Id)
|
||||
ev.IsCanceled = true;
|
||||
if (!killedWithStation.TryGetValue(ev.Body.OfPlayer.Id,
|
||||
out var stationInfo))
|
||||
return;
|
||||
if (ev.Body.Killer != null && ev.Body.Killer.Id != ev.Body.OfPlayer.Id)
|
||||
return;
|
||||
ev.Body.Killer = stationInfo.Owner as IOnlinePlayer;
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,8 @@ using TTT.Karma.lang;
|
||||
namespace TTT.CS2.Listeners;
|
||||
|
||||
public class KarmaBanner(IServiceProvider provider) : BaseListener(provider) {
|
||||
private readonly KarmaConfig config =
|
||||
provider.GetService<IStorage<KarmaConfig>>()
|
||||
private KarmaConfig config
|
||||
=> Provider.GetService<IStorage<KarmaConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new KarmaConfig();
|
||||
|
||||
@@ -45,7 +45,7 @@ public class RoundTimerListener(IServiceProvider provider)
|
||||
.TotalSeconds);
|
||||
Server.ExecuteCommand("mp_ignore_round_win_conditions 1");
|
||||
foreach (var player in Utilities.GetPlayers()
|
||||
.Where(p => p.LifeState != (int)LifeState_t.LIFE_ALIVE && p is {
|
||||
.Where(p => p.GetHealth() <= 0 && p is {
|
||||
Team: CsTeam.CounterTerrorist or CsTeam.Terrorist
|
||||
}))
|
||||
player.Respawn();
|
||||
@@ -60,7 +60,7 @@ public class RoundTimerListener(IServiceProvider provider)
|
||||
if (ev.NewState == State.IN_PROGRESS)
|
||||
Server.NextWorldUpdate(() => {
|
||||
foreach (var player in Utilities.GetPlayers()
|
||||
.Where(p => p.LifeState != (int)LifeState_t.LIFE_ALIVE && p is {
|
||||
.Where(p => p.GetHealth() <= 0 && p is {
|
||||
Team: CsTeam.CounterTerrorist or CsTeam.Terrorist
|
||||
}))
|
||||
player.Respawn();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Attributes.Registration;
|
||||
using JetBrains.Annotations;
|
||||
using TTT.API;
|
||||
using TTT.CS2.API;
|
||||
|
||||
@@ -52,6 +54,14 @@ public class CS2AliveSpoofer : IAliveSpoofer, IPluginModule {
|
||||
onTick);
|
||||
}
|
||||
|
||||
[UsedImplicitly]
|
||||
[GameEventHandler]
|
||||
public HookResult OnDisconnect(EventPlayerDisconnect ev) {
|
||||
if (ev.Userid == null) return HookResult.Continue;
|
||||
_fakeAlivePlayers.Remove(ev.Userid);
|
||||
return HookResult.Continue;
|
||||
}
|
||||
|
||||
private void onTick() {
|
||||
_fakeAlivePlayers.RemoveWhere(p => !p.IsValid || p.Handle == IntPtr.Zero);
|
||||
foreach (var player in _fakeAlivePlayers) {
|
||||
|
||||
87
TTT/CS2/Utils/DamageDealingHelper.cs
Normal file
87
TTT/CS2/Utils/DamageDealingHelper.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System.Net;
|
||||
using System.Numerics;
|
||||
using System.Runtime.InteropServices;
|
||||
using CounterStrikeSharp.API;
|
||||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Modules.Memory;
|
||||
using Vector = CounterStrikeSharp.API.Modules.Utils.Vector;
|
||||
|
||||
namespace TTT.CS2.Utils;
|
||||
|
||||
public class DamageDealingHelper {
|
||||
public static void DealDamage(CCSPlayerController target,
|
||||
CCSPlayerController? attacker, int damage, string source,
|
||||
DamageTypes_t type = DamageTypes_t.DMG_BLAST_SURFACE) {
|
||||
if (target.Pawn.Value == null) return;
|
||||
|
||||
var infoSize = Schema.GetClassSize("CTakeDamageInfo");
|
||||
var infoPtr = Marshal.AllocHGlobal(infoSize);
|
||||
|
||||
for (var i = 0; i < infoSize; i++) Marshal.WriteByte(infoPtr, i, 0);
|
||||
|
||||
var damageInfo = new CTakeDamageInfo(infoPtr);
|
||||
|
||||
Schema.SetSchemaValue(damageInfo.Handle, "CTakeDamageInfo", "m_hInflictor",
|
||||
attacker != null ? attacker.Pawn.Raw : 0);
|
||||
Schema.SetSchemaValue(damageInfo.Handle, "CTakeDamageInfo", "m_hAttacker",
|
||||
attacker != null ? attacker.EntityHandle.Raw : 0);
|
||||
damageInfo.Damage = damage;
|
||||
damageInfo.BitsDamageType = type;
|
||||
|
||||
if (target.Pawn.Value?.AbsOrigin != null)
|
||||
Schema.SetSchemaValue(damageInfo.Handle, "CTakeDamageInfo",
|
||||
"m_vecDamagePosition",
|
||||
target.Pawn.Value != null ?
|
||||
target.Pawn.Value.AbsOrigin.Handle :
|
||||
Vector.Zero.Handle);
|
||||
|
||||
Schema.SetSchemaValue(damageInfo.Handle, "CTakeDamageInfo",
|
||||
"m_vecDamageForce", Vector.Zero.Handle);
|
||||
|
||||
var damageResultSize = Schema.GetClassSize("CTakeDamageResult");
|
||||
var damageResultPtr = Marshal.AllocHGlobal(damageResultSize);
|
||||
for (var i = 0; i < damageResultSize; i++)
|
||||
Marshal.WriteByte(damageResultPtr, i, 0);
|
||||
|
||||
var damageResult = new CTakeDamageResult(damageResultPtr);
|
||||
Schema.SetSchemaValue(damageResult.Handle, "CTakeDamageResult",
|
||||
"m_pOriginatingInfo", damageInfo.Handle);
|
||||
|
||||
damageResult.HealthLost = damage;
|
||||
damageResult.DamageDealt = damage;
|
||||
damageResult.TotalledHealthLost = damage;
|
||||
damageResult.TotalledDamageDealt = damage;
|
||||
damageResult.WasDamageSuppressed = false;
|
||||
|
||||
if (target.EntityHandle.Value != null)
|
||||
VirtualFunctions.CBaseEntity_TakeDamageOldFunc.Invoke(
|
||||
target.EntityHandle.Value, damageInfo, damageResult);
|
||||
|
||||
Marshal.FreeHGlobal(infoPtr);
|
||||
Marshal.FreeHGlobal(damageResultPtr);
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct CAttackerInfo {
|
||||
[FieldOffset(0x0)]
|
||||
public bool NeedInit;
|
||||
|
||||
[FieldOffset(0x1)]
|
||||
public bool IsPawn;
|
||||
|
||||
[FieldOffset(0x2)]
|
||||
public bool IsWorld;
|
||||
|
||||
[FieldOffset(0x4)]
|
||||
public UInt32 AttackerPawn;
|
||||
|
||||
[FieldOffset(0x8)]
|
||||
public ushort AttackerUserId;
|
||||
|
||||
[FieldOffset(0x0C)]
|
||||
public int TeamChecked;
|
||||
|
||||
[FieldOffset(0x10)]
|
||||
public int TeamNum;
|
||||
}
|
||||
@@ -48,9 +48,9 @@ public record KarmaConfig {
|
||||
/// <summary>
|
||||
/// Amount of karma a player will gain at the end of each round.
|
||||
/// </summary>
|
||||
public int KarmaPerRound { get; init; } = 3;
|
||||
public int KarmaPerRound { get; init; } = 1;
|
||||
|
||||
public int KarmaPerRoundWin { get; init; } = 5;
|
||||
public int KarmaPerRoundWin { get; init; } = 2;
|
||||
|
||||
public int INNO_ON_TRAITOR { get; init; } = 5;
|
||||
public int TRAITOR_ON_DETECTIVE { get; init; } = 1;
|
||||
|
||||
@@ -19,8 +19,11 @@ public sealed class KarmaStorage(IServiceProvider provider) : IKarmaService {
|
||||
private const bool EnableCache = true;
|
||||
private readonly IEventBus _bus = provider.GetRequiredService<IEventBus>();
|
||||
|
||||
private readonly IStorage<KarmaConfig>? _configStorage =
|
||||
provider.GetService<IStorage<KarmaConfig>>();
|
||||
private KarmaConfig _configStorage
|
||||
=> provider.GetService<IStorage<KarmaConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new KarmaConfig();
|
||||
|
||||
private readonly SemaphoreSlim _flushGate = new(1, 1);
|
||||
|
||||
@@ -38,12 +41,6 @@ public sealed class KarmaStorage(IServiceProvider provider) : IKarmaService {
|
||||
public string Version => GitVersionInformation.FullSemVer;
|
||||
|
||||
public void Start() {
|
||||
// Load configuration first
|
||||
if (_configStorage is not null)
|
||||
// Synchronously wait here since IKarmaService.Start is sync
|
||||
_config = _configStorage.Load().GetAwaiter().GetResult()
|
||||
?? new KarmaConfig();
|
||||
|
||||
// Open a dedicated connection used only by this service
|
||||
_connection = new SqliteConnection(_config.DbString);
|
||||
_connection.Open();
|
||||
|
||||
@@ -18,11 +18,11 @@ public static class StickerExtensions {
|
||||
|
||||
public class Stickers(IServiceProvider provider)
|
||||
: RoleRestrictedItem<DetectiveRole>(provider) {
|
||||
private readonly StickersConfig config = provider
|
||||
.GetService<IStorage<StickersConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new StickersConfig();
|
||||
private StickersConfig config
|
||||
=> Provider.GetService<IStorage<StickersConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new StickersConfig();
|
||||
|
||||
public override string Name => Locale[StickerMsgs.SHOP_ITEM_STICKERS];
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ public static class HealthshotServiceCollection {
|
||||
}
|
||||
|
||||
public class HealthshotItem(IServiceProvider provider) : BaseItem(provider) {
|
||||
private readonly HealthshotConfig config =
|
||||
provider.GetService<IStorage<HealthshotConfig>>()
|
||||
private HealthshotConfig config
|
||||
=> Provider.GetService<IStorage<HealthshotConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new HealthshotConfig();
|
||||
|
||||
@@ -17,11 +17,11 @@ public static class DeagleServiceCollection {
|
||||
|
||||
public class OneShotDeagleItem(IServiceProvider provider)
|
||||
: BaseItem(provider), IWeapon {
|
||||
private readonly OneShotDeagleConfig deagleConfigStorage = provider
|
||||
.GetService<IStorage<OneShotDeagleConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new OneShotDeagleConfig();
|
||||
private OneShotDeagleConfig deagleConfigStorage
|
||||
=> Provider.GetService<IStorage<OneShotDeagleConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new OneShotDeagleConfig();
|
||||
|
||||
public override string Name => Locale[DeagleMsgs.SHOP_ITEM_DEAGLE];
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ public class GlovesListener(IServiceProvider provider)
|
||||
private readonly Dictionary<IPlayer, int> uses = new();
|
||||
|
||||
[UsedImplicitly]
|
||||
[EventHandler]
|
||||
[EventHandler(Priority = Priority.LOW)]
|
||||
public void BodyCreate(BodyCreateEvent ev) {
|
||||
if (ev.Body.Killer == null || !useGloves(ev.Body.Killer)) return;
|
||||
if (ev.Body.Killer is not IOnlinePlayer online) return;
|
||||
|
||||
@@ -17,8 +17,8 @@ public class RoleAssignCreditor(IServiceProvider provider)
|
||||
provider.GetService<IStorage<ShopConfig>>()?.Load().GetAwaiter().GetResult()
|
||||
?? new ShopConfig(provider);
|
||||
|
||||
private readonly KarmaConfig karmaConfig =
|
||||
provider.GetService<IStorage<KarmaConfig>>()
|
||||
private KarmaConfig karmaConfig
|
||||
=> Provider.GetService<IStorage<KarmaConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new KarmaConfig();
|
||||
@@ -50,8 +50,8 @@ public class RoleAssignCreditor(IServiceProvider provider)
|
||||
}
|
||||
|
||||
private float getKarmaScale(float percent) {
|
||||
if (percent >= 0.9) return 1.1f;
|
||||
if (percent >= 0.8f) return 1;
|
||||
if (percent >= 0.9) return 1;
|
||||
if (percent >= 0.8f) return 0.9f;
|
||||
if (percent >= 0.5) return 0.8f;
|
||||
if (percent >= 0.3) return 0.5f;
|
||||
return 0.25f;
|
||||
|
||||
@@ -11,11 +11,11 @@ using TTT.API.Storage;
|
||||
namespace TTT.Shop;
|
||||
|
||||
public class PeriodicRewarder(IServiceProvider provider) : ITerrorModule {
|
||||
private readonly ShopConfig config = provider
|
||||
.GetService<IStorage<ShopConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new ShopConfig(provider);
|
||||
private ShopConfig config
|
||||
=> provider.GetService<IStorage<ShopConfig>>()
|
||||
?.Load()
|
||||
.GetAwaiter()
|
||||
.GetResult() ?? new ShopConfig(provider);
|
||||
|
||||
private readonly IPlayerFinder finder =
|
||||
provider.GetRequiredService<IPlayerFinder>();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
namespace ShopAPI.Configs;
|
||||
|
||||
public record OneShotDeagleConfig : ShopItemConfig {
|
||||
public override int Price { get; init; } = 100;
|
||||
public override int Price { get; init; } = 125;
|
||||
public bool DoesFriendlyFire { get; init; } = true;
|
||||
public bool KillShooterOnFF { get; init; } = false;
|
||||
public string Weapon { get; init; } = "revolver";
|
||||
|
||||
@@ -57,7 +57,7 @@ public class BalanceClearTest(IServiceProvider provider) {
|
||||
var game = games.CreateGame();
|
||||
game?.Start();
|
||||
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(10),
|
||||
await Task.Delay(TimeSpan.FromMilliseconds(50),
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
var newBalance = await shop.Load(player);
|
||||
|
||||
Reference in New Issue
Block a user