Skip to content

Commit fce346b

Browse files
authored
Merge pull request #40 from Wngui/item-overrides
Item overrides
2 parents 47e6428 + 7153279 commit fce346b

23 files changed

+358
-177
lines changed

WarcraftPlugin/Core/Shop.cs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Reflection;
5+
using System.Text.Json;
6+
using WarcraftPlugin.Items;
7+
8+
namespace WarcraftPlugin.Core
9+
{
10+
internal static class Shop
11+
{
12+
internal static readonly List<ShopItem> Items;
13+
14+
static Shop()
15+
{
16+
Items =
17+
[
18+
new BootsOfSpeed(),
19+
new SockOfFeathers(),
20+
new RingOfRegeneration(),
21+
new MaskOfDeath(),
22+
new AmuletOfTheCat(),
23+
new DaggerOfVenom(),
24+
new MoneySiphonScepter(),
25+
new OrbOfFrost(),
26+
new TalismanOfEvasion(),
27+
new AmuletOfVitality(),
28+
new GlovesOfWrath(),
29+
new GlovesOfCloud(),
30+
new GlovesOfDazzle(),
31+
new TomeOfExperience(),
32+
new TomeOfGambling()
33+
];
34+
}
35+
}
36+
37+
internal static class ShopItemExtensions
38+
{
39+
internal static void ApplyOverrides(this List<ShopItem> items, Config config)
40+
{
41+
if (config?.ItemOverrides != null)
42+
{
43+
foreach (var item in items.ToList()) // Use ToList to avoid modifying the collection during iteration
44+
{
45+
if (config.ItemOverrides.TryGetValue(item.InternalName, out var overrides))
46+
{
47+
foreach (var overrideEntry in overrides)
48+
{
49+
var property = item.GetType().GetProperty(overrideEntry.Key, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
50+
if (property != null && property.CanRead && property.CanWrite && Attribute.IsDefined(property, typeof(Configurable)))
51+
{
52+
try
53+
{
54+
var oldValue = property.GetValue(item);
55+
object newValue;
56+
57+
if (overrideEntry.Value is JsonElement jsonElement)
58+
{
59+
newValue = JsonSerializer.Deserialize(jsonElement, property.PropertyType);
60+
}
61+
else
62+
{
63+
newValue = Convert.ChangeType(overrideEntry.Value, property.PropertyType);
64+
}
65+
66+
if (!Equals(oldValue, newValue))
67+
{
68+
property.SetValue(item, newValue);
69+
//Console.WriteLine($"[Shop] Updated property '{property.Name}' of item '{item.InternalName}' from '{oldValue}' to '{newValue}'.");
70+
}
71+
}
72+
catch (Exception ex)
73+
{
74+
Console.WriteLine($"[Warcraft] Failed to override property '{overrideEntry.Key}' of item '{item.InternalName}': {ex.Message}");
75+
}
76+
}
77+
else
78+
{
79+
Console.WriteLine($"[Warcraft] Failed to override property '{overrideEntry.Key}' of item '{item.InternalName}'");
80+
}
81+
}
82+
}
83+
}
84+
}
85+
86+
//Remove disabled items from the shop
87+
Shop.Items.Where(i => i.IsDisabled).ToList().ForEach(i =>
88+
{
89+
Console.WriteLine($"[Warcraft] Disabling item: {i.InternalName}");
90+
Shop.Items.Remove(i);
91+
});
92+
}
93+
94+
internal static Dictionary<string, Dictionary<string, object>> GetConfigurableProperties(this List<ShopItem> items)
95+
{
96+
return items.Where(i => !string.IsNullOrEmpty(i.InternalName))
97+
.ToDictionary(
98+
i => i.InternalName,
99+
i => i.GetType()
100+
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
101+
.Where(p => p.CanRead && p.CanWrite && Attribute.IsDefined(p, typeof(Configurable)))
102+
.ToDictionary(
103+
p => p.Name,
104+
p =>
105+
{
106+
var value = p.GetValue(i);
107+
if (value == null)
108+
return p.PropertyType.IsValueType ? Activator.CreateInstance(p.PropertyType) : null;
109+
110+
return value;
111+
}
112+
)
113+
);
114+
}
115+
}
116+
}

WarcraftPlugin/Items/AmuletOfTheCat.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ namespace WarcraftPlugin.Items;
1212
internal class AmuletOfTheCat : ShopItem
1313
{
1414
protected override string Name => "Amulet of the Cat";
15-
protected override string Description => "Silent Footsteps";
16-
internal override int Price => 4000;
17-
internal override Color Color => Color.FromArgb(255, 192, 192, 192); // Silver for stealth/unique
15+
protected override FormattableString Description => $"Silent Footsteps";
16+
internal override int Price { get; set; } = 4000;
17+
internal override Color Color { get; set; } = Color.FromArgb(255, 192, 192, 192); // Silver for stealth/unique
1818

1919
internal override void Apply(CCSPlayerController player)
2020
{

WarcraftPlugin/Items/AmuletOfVitality.cs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using CounterStrikeSharp.API.Core;
2+
using System;
23
using System.Drawing;
34
using WarcraftPlugin.Core.Effects;
45
using WarcraftPlugin.Helpers;
@@ -8,16 +9,19 @@ namespace WarcraftPlugin.Items;
89
internal class AmuletOfVitality : ShopItem
910
{
1011
protected override string Name => "Amulet of Vitality";
11-
protected override string Description => "Increase max HP by 50";
12-
internal override int Price => 3500;
13-
internal override Color Color => Color.FromArgb(255, 255, 69, 0); // OrangeRed for vitality/health
12+
protected override FormattableString Description => $"Increase max HP by {HealthBonus}";
13+
internal override int Price { get; set; } = 3500;
14+
internal override Color Color { get; set; } = Color.FromArgb(255, 255, 69, 0); // OrangeRed for vitality/health
15+
16+
[Configurable]
17+
internal int HealthBonus { get; set; } = 50;
1418

1519
internal override void Apply(CCSPlayerController player)
1620
{
17-
new AmuletOfVitalityEffect(player).Start();
21+
new AmuletOfVitalityEffect(player, HealthBonus).Start();
1822
}
1923

20-
private class AmuletOfVitalityEffect(CCSPlayerController owner) : WarcraftEffect(owner)
24+
private class AmuletOfVitalityEffect(CCSPlayerController owner, int healthBonus) : WarcraftEffect(owner)
2125
{
2226
private int _originalMaxHealth;
2327

@@ -26,8 +30,8 @@ public override void OnStart()
2630
if (!Owner.IsAlive()) return;
2731
var pawn = Owner.PlayerPawn.Value;
2832
_originalMaxHealth = pawn.MaxHealth;
29-
pawn.MaxHealth = _originalMaxHealth + 50;
30-
var newHealth = pawn.Health + 50;
33+
pawn.MaxHealth = _originalMaxHealth + healthBonus;
34+
var newHealth = pawn.Health + healthBonus;
3135
Owner.SetHp((int)newHealth);
3236
}
3337

WarcraftPlugin/Items/BootsOfSpeed.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using CounterStrikeSharp.API.Core;
2+
using System;
23
using System.Drawing;
34
using WarcraftPlugin.Core.Effects;
45
using WarcraftPlugin.Helpers;
@@ -8,24 +9,27 @@ namespace WarcraftPlugin.Items;
89
internal class BootsOfSpeed : ShopItem
910
{
1011
protected override string Name => "Boots of Speed";
11-
protected override string Description => "Increase Speed by 20%";
12-
internal override int Price => 2500;
13-
internal override Color Color => Color.FromArgb(255, 30, 144, 255); // DodgerBlue for speed/movement
12+
protected override FormattableString Description => $"Increase Speed by {(SpeedModifier-1)*100}%";
13+
internal override int Price { get; set; } = 2500;
14+
internal override Color Color { get; set; } = Color.FromArgb(255, 30, 144, 255); // DodgerBlue for speed/movement
15+
16+
[Configurable]
17+
public float SpeedModifier { get; set; } = 1.2f; // 20% speed increase
1418

1519
internal override void Apply(CCSPlayerController player)
1620
{
17-
new BootsOfSpeedEffect(player).Start();
21+
new BootsOfSpeedEffect(player, SpeedModifier).Start();
1822
}
1923

20-
private class BootsOfSpeedEffect(CCSPlayerController owner) : WarcraftEffect(owner)
24+
private class BootsOfSpeedEffect(CCSPlayerController owner, float speedModifier) : WarcraftEffect(owner)
2125
{
2226
private float _originalModifier;
2327

2428
public override void OnStart()
2529
{
2630
if (!Owner.IsAlive()) return;
2731
_originalModifier = Owner.PlayerPawn.Value.VelocityModifier;
28-
Owner.PlayerPawn.Value.VelocityModifier = _originalModifier * 1.2f;
32+
Owner.PlayerPawn.Value.VelocityModifier = _originalModifier * speedModifier;
2933
}
3034

3135
public override void OnTick() { }

WarcraftPlugin/Items/DaggerOfVenom.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,21 @@
44
using WarcraftPlugin.Helpers;
55
using System.Linq;
66
using System.Drawing;
7+
using System;
78

89
namespace WarcraftPlugin.Items;
910

1011
internal class DaggerOfVenom : ShopItem
1112
{
1213
protected override string Name => "Dagger of Venom";
13-
protected override string Description => "Poison enemies on hit";
14-
internal override int Price => 2500;
15-
internal override Color Color => Color.FromArgb(255, 34, 139, 34); // ForestGreen for poison/venom
14+
protected override FormattableString Description => $"Poison enemies on hit";
15+
internal override int Price { get; set; } = 2500;
16+
internal override Color Color { get; set; } = Color.FromArgb(255, 34, 139, 34); // ForestGreen for poison/venom
17+
18+
[Configurable]
19+
internal float PoisonDuration { get; set; } = 5f; // Default poison duration in seconds
20+
[Configurable]
21+
internal int PoisonDamage { get; set; } = 1; // Default poison damage per tick
1622

1723
internal override void Apply(CCSPlayerController player) { }
1824

@@ -27,7 +33,7 @@ internal override void OnPlayerHurtOther(EventPlayerHurtOther @event)
2733

2834
if (!isVictimPoisoned)
2935
{
30-
new VenomStrikeEffect(@event.Attacker, @event.Userid, 5f, 1).Start();
36+
new VenomStrikeEffect(@event.Attacker, @event.Userid, PoisonDuration, PoisonDamage).Start();
3137
}
3238
}
3339
}

WarcraftPlugin/Items/GlovesOfCloud.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using CounterStrikeSharp.API.Core;
22
using CounterStrikeSharp.API.Modules.Utils;
3+
using System;
34
using System.Drawing;
45
using System.Linq;
56
using WarcraftPlugin.Core.Effects;
@@ -10,17 +11,22 @@ namespace WarcraftPlugin.Items;
1011
internal class GlovesOfCloud : ShopItem
1112
{
1213
protected override string Name => "Gloves of Cloud";
13-
protected override string Description => "Receive a Smoke grenade every 12s";
14-
internal override int Price => 3000;
15-
internal override Color Color => Color.FromArgb(255, 169, 169, 169); // DarkGray for utility/smoke
14+
protected override FormattableString Description => $"Receive a Smoke grenade every {GrenadeInterval}s";
15+
internal override int Price { get; set; } = 3000;
16+
internal override Color Color { get; set; } = Color.FromArgb(255, 169, 169, 169); // DarkGray for utility/smoke
17+
18+
[Configurable]
19+
internal float GrenadeInterval { get; set; } = 12f;
20+
[Configurable]
21+
internal string GrenadeType { get; set; } = "weapon_smokegrenade";
1622

1723
internal override void Apply(CCSPlayerController player)
1824
{
19-
new GrenadeSupplyEffect(player, "weapon_smokegrenade", ShopItem.Localizer["item.gloves_of_cloud.grenade_name"]).Start();
25+
new GrenadeSupplyEffect(player, GrenadeType, GrenadeInterval, Localizer["item.gloves_of_cloud.grenade_name"]).Start();
2026
}
2127

22-
private class GrenadeSupplyEffect(CCSPlayerController owner, string grenadeName, string displayName)
23-
: WarcraftEffect(owner, onTickInterval: 12f)
28+
private class GrenadeSupplyEffect(CCSPlayerController owner, string grenadeName, float grenadeInterval, string displayName)
29+
: WarcraftEffect(owner, onTickInterval: grenadeInterval)
2430
{
2531
private readonly string _grenadeName = grenadeName;
2632
private readonly string _displayName = displayName;

WarcraftPlugin/Items/GlovesOfDazzle.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using CounterStrikeSharp.API.Core;
22
using CounterStrikeSharp.API.Modules.Utils;
3+
using System;
34
using System.Drawing;
45
using System.Linq;
56
using WarcraftPlugin.Core.Effects;
@@ -10,17 +11,22 @@ namespace WarcraftPlugin.Items;
1011
internal class GlovesOfDazzle : ShopItem
1112
{
1213
protected override string Name => "Gloves of Dazzle";
13-
protected override string Description => "Receive a Flashbang every 12s";
14-
internal override int Price => 3000;
15-
internal override Color Color => Color.FromArgb(255, 255, 255, 0); // Yellow for utility/flashbang
14+
protected override FormattableString Description => $"Receive a Flashbang every {GrenadeInterval}s";
15+
internal override int Price { get; set; } = 3000;
16+
internal override Color Color { get; set; } = Color.FromArgb(255, 255, 255, 0); // Yellow for utility/flashbang
17+
18+
[Configurable]
19+
internal float GrenadeInterval { get; set; } = 12f;
20+
[Configurable]
21+
internal string GrenadeType { get; set; } = "weapon_flashbang";
1622

1723
internal override void Apply(CCSPlayerController player)
1824
{
19-
new GrenadeSupplyEffect(player, "weapon_flashbang", ShopItem.Localizer["item.gloves_of_dazzle.grenade_name"]).Start();
25+
new GrenadeSupplyEffect(player, "weapon_flashbang", GrenadeInterval, Localizer["item.gloves_of_dazzle.grenade_name"]).Start();
2026
}
2127

22-
private class GrenadeSupplyEffect(CCSPlayerController owner, string grenadeName, string displayName)
23-
: WarcraftEffect(owner, onTickInterval: 12f)
28+
private class GrenadeSupplyEffect(CCSPlayerController owner, string grenadeName, float grenadeInterval, string displayName)
29+
: WarcraftEffect(owner, onTickInterval: grenadeInterval)
2430
{
2531
private readonly string _grenadeName = grenadeName;
2632
private readonly string _displayName = displayName;

WarcraftPlugin/Items/GlovesOfWrath.cs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using CounterStrikeSharp.API.Core;
22
using CounterStrikeSharp.API.Modules.Utils;
3+
using System;
34
using System.Drawing;
45
using System.Linq;
56
using WarcraftPlugin.Core.Effects;
@@ -10,17 +11,22 @@ namespace WarcraftPlugin.Items;
1011
internal class GlovesOfWrath : ShopItem
1112
{
1213
protected override string Name => "Gloves of Wrath";
13-
protected override string Description => "Receive an HE grenade every 12s";
14-
internal override int Price => 3000;
15-
internal override Color Color => Color.FromArgb(255, 255, 140, 0); // DarkOrange for offensive/grenade
14+
protected override FormattableString Description => $"Receive a HE grenade every {GrenadeInterval}s";
15+
internal override int Price { get; set; } = 3000;
16+
internal override Color Color { get; set; } = Color.FromArgb(255, 255, 140, 0); // DarkOrange for offensive/grenade
17+
18+
[Configurable]
19+
internal float GrenadeInterval { get; set; } = 12f;
20+
[Configurable]
21+
internal string GrenadeType { get; set; } = "weapon_hegrenade";
1622

1723
internal override void Apply(CCSPlayerController player)
1824
{
19-
new GrenadeSupplyEffect(player, "weapon_hegrenade", ShopItem.Localizer["item.gloves_of_wrath.grenade_name"]).Start();
25+
new GrenadeSupplyEffect(player, "weapon_hegrenade", GrenadeInterval, Localizer["item.gloves_of_wrath.grenade_name"]).Start();
2026
}
2127

22-
private class GrenadeSupplyEffect(CCSPlayerController owner, string grenadeName, string displayName)
23-
: WarcraftEffect(owner, onTickInterval: 12f)
28+
private class GrenadeSupplyEffect(CCSPlayerController owner, string grenadeName, float grenadeInterval, string displayName)
29+
: WarcraftEffect(owner, onTickInterval: grenadeInterval)
2430
{
2531
private readonly string _grenadeName = grenadeName;
2632
private readonly string _displayName = displayName;

WarcraftPlugin/Items/MaskOfDeath.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,26 @@ namespace WarcraftPlugin.Items;
99
internal class MaskOfDeath : ShopItem
1010
{
1111
protected override string Name => "Mask of Death";
12-
protected override string Description => "50% Chance to Heal 15% of Weapon Damage dealt";
13-
internal override int Price => 4000;
14-
internal override Color Color => Color.FromArgb(255, 220, 20, 60); // Crimson for lifesteal/offensive
12+
protected override FormattableString Description => $"{LifeStealChance*100}% Chance to Heal {LifeStealPercent*100}% of Weapon Damage dealt";
13+
internal override int Price { get; set; } = 4000;
14+
internal override Color Color { get; set; } = Color.FromArgb(255, 220, 20, 60); // Crimson for lifesteal/offensive
15+
16+
[Configurable]
17+
internal double LifeStealChance { get; set; } = 0.5;
18+
[Configurable]
19+
internal double LifeStealPercent { get; set; } = 0.15;
1520

1621
internal override void Apply(CCSPlayerController player) { }
1722

1823
internal override void OnPlayerHurtOther(EventPlayerHurtOther @event)
1924
{
2025
if (@event.Attacker == null || !@event.Attacker.IsAlive()) return;
2126

22-
if (Random.Shared.NextDouble() < 0.5)
27+
if (Random.Shared.NextDouble() < LifeStealChance)
2328
{
2429
var pawn = @event.Attacker.PlayerPawn.Value;
25-
var heal = (int)System.Math.Ceiling(@event.DmgHealth * 0.15f);
26-
var newHp = System.Math.Min(pawn.Health + heal, pawn.MaxHealth);
30+
var heal = (int)Math.Ceiling(@event.DmgHealth * LifeStealPercent);
31+
var newHp = Math.Min(pawn.Health + heal, pawn.MaxHealth);
2732
@event.Attacker.SetHp((int)newHp);
2833
}
2934
}

0 commit comments

Comments
 (0)