Skip to content

Commit 33067b2

Browse files
Cheackrazearimah
andauthored
Gun Rarity System (#3616)
Co-authored-by: Arimah <arimah42@gmail.com>
1 parent 341e37e commit 33067b2

File tree

8 files changed

+342
-47
lines changed

8 files changed

+342
-47
lines changed

Content.Server/Storage/EntitySystems/StorageSystem.Fill.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Content.Server.Humanoid.Components;
33
using Content.Server.Spawners.Components;
44
using Content.Server.Storage.Components;
5+
using Content.Server.Storage.Events;
56
using Content.Shared.Item;
67
using Content.Shared.Prototypes;
78
using Content.Shared.Storage;
@@ -85,6 +86,11 @@ private void FillStorage(Entity<StorageFillComponent?, StorageComponent?> entity
8586
ClearCantFillReasons();
8687
Del(ent);
8788
}
89+
90+
// Frontier - we raise an event to let other systems know their storages have completed filling
91+
var StoreFillEv = new StorageFilledEvent();
92+
RaiseLocalEvent(uid, ref StoreFillEv, broadcast: true);
93+
// End Frontier
8894
}
8995

9096
private void FillEntityStorage(Entity<StorageFillComponent?, EntityStorageComponent?> entity)
@@ -118,5 +124,9 @@ private void FillEntityStorage(Entity<StorageFillComponent?, EntityStorageCompon
118124
Log.Error($"Tried to StorageFill {item} inside {ToPrettyString(uid)} but can't.");
119125
Del(ent);
120126
}
127+
// Frontier - we raise an event to let other systems know their storages have completed filling
128+
var StoreFillEv = new StorageFilledEvent();
129+
RaiseLocalEvent(uid, ref StoreFillEv, broadcast: true);
130+
// End Frontier
121131
}
122132
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Content.Server.Storage.Events;
2+
3+
/// <summary>
4+
/// Raised when a <see cref="StorageFillComponent"/> is finished filling the storage
5+
/// </summary>
6+
[ByRefEvent]
7+
public record struct StorageFilledEvent;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
namespace Content.Server._NF.Weapons.Rarity;
2+
3+
/// <summary>
4+
/// Added to a weapon to indicate that it's been modified in some way.
5+
/// </summary>
6+
[RegisterComponent]
7+
[Access(typeof(WeaponRaritySystem))]
8+
public sealed partial class RareWeaponComponent : Component
9+
{
10+
[DataField]
11+
public List<string> NameModifiers = new();
12+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using Robust.Shared.Random;
2+
3+
namespace Content.Server._NF.Weapons.Rarity;
4+
5+
/// <summary>
6+
/// This component is added to weapon cases that transform the containing spawned weapon into a weapon with rare markers.
7+
/// </summary>
8+
[RegisterComponent]
9+
public sealed partial class RareWeaponSpawnerCaseComponent : Component
10+
{
11+
[DataField]
12+
public int Rarity = 1;
13+
14+
[DataField]
15+
public bool RandomRarity = false;
16+
17+
/// <summary>
18+
/// Modifier that can be applied to the gun's accuracy.
19+
/// </summary>
20+
[DataField]
21+
public StatModifier AccuracyModifier = new StatModifier(0.65f, 0.85f);
22+
23+
/// <summary>
24+
/// Modifier that can be applied to the gun's projectile speed.
25+
/// </summary>
26+
[DataField]
27+
public StatModifier ProjectileSpeedModifier = new StatModifier(1.15f, 1.35f);
28+
29+
/// <summary>
30+
/// Modifier that can be applied to the gun's fire rate.
31+
/// </summary>
32+
[DataField]
33+
public StatModifier FireRateModifier = new StatModifier(1.15f, 1.35f);
34+
}
35+
36+
// Note: can't use MinMax here, because that only takes integers.
37+
[DataDefinition, Serializable]
38+
public partial struct StatModifier
39+
{
40+
[DataField(required: true)]
41+
public float Min;
42+
43+
[DataField(required: true)]
44+
public float Max;
45+
46+
public StatModifier(float min, float max)
47+
{
48+
Min = min;
49+
Max = max;
50+
}
51+
52+
public readonly float Next(IRobustRandom random)
53+
{
54+
return random.NextFloat(Min, Max);
55+
}
56+
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
using Content.Server.Storage.Events;
2+
using Content.Shared.Dataset;
3+
using Content.Shared.NameModifier.EntitySystems;
4+
using Content.Shared.Storage;
5+
using Content.Shared.Weapons.Ranged.Components;
6+
using Robust.Shared.Prototypes;
7+
using Robust.Shared.Random;
8+
9+
namespace Content.Server._NF.Weapons.Rarity;
10+
11+
/// <summary>
12+
/// A stand-alone system intended to modularly sit atop the existing gun and weapon systems to create dynamic weapon rarities.
13+
/// </summary>
14+
public sealed partial class WeaponRaritySystem : EntitySystem
15+
{
16+
[Dependency] private readonly IRobustRandom _random = default!;
17+
[Dependency] private readonly MetaDataSystem _metaSystem = default!;
18+
[Dependency] private readonly NameModifierSystem _namingSystem = default!;
19+
[Dependency] private readonly IPrototypeManager _protoMan = default!;
20+
21+
public override void Initialize()
22+
{
23+
base.Initialize();
24+
SubscribeLocalEvent<RareWeaponSpawnerCaseComponent, StorageFilledEvent>(OnCaseSpawn);
25+
SubscribeLocalEvent<RareWeaponComponent, RefreshNameModifiersEvent>(OnRefreshNameModifiers);
26+
}
27+
28+
private void OnCaseSpawn(Entity<RareWeaponSpawnerCaseComponent> ent, ref StorageFilledEvent args)
29+
{
30+
if (!TryComp(ent, out StorageComponent? storage))
31+
return;
32+
33+
foreach (var item in storage.StoredItems)
34+
{
35+
if (TryComp(item.Key, out GunComponent? gunComp))
36+
{
37+
ModifyGun(ent.Comp, item.Key, gunComp);
38+
}
39+
}
40+
}
41+
42+
private void ModifyGun(RareWeaponSpawnerCaseComponent comp, EntityUid gun, GunComponent gunComp)
43+
{
44+
//Basic functionality of 3 rarity levels
45+
var rarity = comp.Rarity;
46+
if (comp.RandomRarity)
47+
{
48+
rarity = _random.Next(0, 4);
49+
}
50+
51+
RenameGun(gun, rarity);
52+
53+
while (rarity > 0)
54+
{
55+
var chance = _random.Next(1, 4);
56+
switch (chance)
57+
{
58+
case 1:
59+
ImproveAccuracy(comp.AccuracyModifier, gun, gunComp);
60+
break;
61+
case 2:
62+
ImproveFireRate(comp.FireRateModifier, gun, gunComp);
63+
break;
64+
case 3:
65+
ImproveProjectileSpeed(comp.ProjectileSpeedModifier, gun, gunComp);
66+
break;
67+
}
68+
rarity--;
69+
}
70+
}
71+
72+
private void ImproveAccuracy(StatModifier modifier, EntityUid gun, GunComponent? gunComp)
73+
{
74+
if (!Resolve(gun, ref gunComp))
75+
return;
76+
77+
var buff = modifier.Next(_random);
78+
79+
gunComp.MinAngle *= buff;
80+
gunComp.MinAngleModified *= buff;
81+
gunComp.MaxAngle *= buff;
82+
gunComp.MaxAngleModified *= buff;
83+
gunComp.AngleIncrease *= buff;
84+
gunComp.AngleIncreaseModified *= buff;
85+
gunComp.AngleDecay *= 1 / buff;
86+
gunComp.AngleDecayModified *= 1 / buff;
87+
}
88+
89+
private void ImproveFireRate(StatModifier modifier, EntityUid gun, GunComponent? gunComp)
90+
{
91+
if (!Resolve(gun, ref gunComp))
92+
return;
93+
94+
var buff = modifier.Next(_random);
95+
96+
gunComp.FireRate *= buff;
97+
gunComp.FireRateModified *= buff;
98+
}
99+
100+
private void ImproveProjectileSpeed(StatModifier modifier, EntityUid gun, GunComponent? gunComp)
101+
{
102+
if (!Resolve(gun, ref gunComp))
103+
return;
104+
105+
var buff = modifier.Next(_random);
106+
107+
gunComp.ProjectileSpeed *= buff;
108+
gunComp.ProjectileSpeedModified *= buff;
109+
}
110+
111+
private void RenameGun(EntityUid gun, int rarity)
112+
{
113+
var datasetUncommon = _protoMan.Index<LocalizedDatasetPrototype>("NFNamesGunsUncommon");
114+
var datasetRare = _protoMan.Index<LocalizedDatasetPrototype>("NFNamesGunsRare");
115+
var datasetEpic = _protoMan.Index<LocalizedDatasetPrototype>("NFNamesGunsEpic");
116+
117+
var meta = MetaData(gun);
118+
var rareComp = EnsureComp<RareWeaponComponent>(gun);
119+
120+
if (rarity == 1)
121+
{
122+
rareComp.NameModifiers.Add(_random.Pick(datasetUncommon.Values));
123+
}
124+
else if (rarity == 2)
125+
{
126+
rareComp.NameModifiers.Add(_random.Pick(datasetUncommon.Values));
127+
rareComp.NameModifiers.Add(_random.Pick(datasetRare.Values));
128+
}
129+
else if (rarity >= 3)
130+
{
131+
// At this rarity, we rename the entire gun instead of adding a modifier
132+
var pick = _random.Pick(datasetEpic.Values);
133+
_metaSystem.SetEntityName(gun, Loc.GetString(pick), meta, false);
134+
}
135+
136+
_namingSystem.RefreshNameModifiers(gun);
137+
}
138+
139+
private void OnRefreshNameModifiers(Entity<RareWeaponComponent> ent, ref RefreshNameModifiersEvent args)
140+
{
141+
foreach (var modifier in ent.Comp.NameModifiers)
142+
{
143+
args.AddModifier(modifier);
144+
}
145+
}
146+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
adjectives-nf-gun-uncommon-1 = sturdy {$baseName}
2+
adjectives-nf-gun-uncommon-2 = keen {$baseName}
3+
adjectives-nf-gun-uncommon-3 = swift {$baseName}
4+
adjectives-nf-gun-uncommon-4 = resilient {$baseName}
5+
adjectives-nf-gun-uncommon-5 = hardened {$baseName}
6+
adjectives-nf-gun-uncommon-6 = steady {$baseName}
7+
adjectives-nf-gun-uncommon-7 = tactical {$baseName}
8+
adjectives-nf-gun-uncommon-8 = precision {$baseName}
9+
adjectives-nf-gun-uncommon-9 = enhanced {$baseName}
10+
adjectives-nf-gun-uncommon-10 = refined {$baseName}
11+
adjectives-nf-gun-uncommon-11 = reinforced {$baseName}
12+
adjectives-nf-gun-uncommon-12 = stabilized {$baseName}
13+
14+
adjectives-nf-gun-rare-1 = deadly {$baseName}
15+
adjectives-nf-gun-rare-2 = lethal {$baseName}
16+
adjectives-nf-gun-rare-3 = killer {$baseName}
17+
adjectives-nf-gun-rare-4 = legendary {$baseName}
18+
adjectives-nf-gun-rare-5 = pristine {$baseName}
19+
20+
names-nf-gun-epic-1 = Blaster Master 9000
21+
names-nf-gun-epic-2 = Chrono-Trigger
22+
names-nf-gun-epic-3 = The Big Bang
23+
names-nf-gun-epic-4 = Rekt-ifier
24+
names-nf-gun-epic-5 = Boomstick
25+
names-nf-gun-epic-6 = Shooty McShooterton
26+
names-nf-gun-epic-7 = Insurance Policy
27+
names-nf-gun-epic-8 = Big Friendly Gun
28+
names-nf-gun-epic-9 = Little Friend
29+
names-nf-gun-epic-10 = Second Opinion
30+
names-nf-gun-epic-11 = The Negotiator
31+
names-nf-gun-epic-12 = Chamber of Justice
32+
names-nf-gun-epic-13 = Ms. Fire
33+
names-nf-gun-epic-14 = The Long Shot
34+
names-nf-gun-epic-15 = The Last Resort
35+
names-nf-gun-epic-16 = Big Bertha
36+
names-nf-gun-epic-17 = Voight-Kampf
37+
names-nf-gun-epic-18 = Rooty Tooty Big And Shooty
38+
names-nf-gun-epic-19 = Plan B
39+
names-nf-gun-epic-20 = Plan C

0 commit comments

Comments
 (0)