using Content.Shared.Research.Components;
using Content.Shared.Research.Systems;
+using Robust.Shared.Random;
namespace Content.Server.Research.Systems;
public sealed class ResearchStealerSystem : SharedResearchStealerSystem
{
[Dependency] private readonly SharedResearchSystem _research = default!;
+ [Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
if (!TryComp<TechnologyDatabaseComponent>(target, out var database))
return;
- var ev = new ResearchStolenEvent(uid, target, database.UnlockedTechnologies);
+ var ev = new ResearchStolenEvent(uid, target, new());
+ var count = _random.Next(comp.MinToSteal, comp.MaxToSteal + 1);
+ for (var i = 0; i < count; i++)
+ {
+ if (database.UnlockedTechnologies.Count == 0)
+ break;
+
+ var toRemove = _random.Pick(database.UnlockedTechnologies);
+ if (_research.TryRemoveTechnology((target, database), toRemove))
+ ev.Techs.Add(toRemove);
+ }
RaiseLocalEvent(uid, ref ev);
- // oops, no more advanced lasers!
- _research.ClearTechs(target, database);
+
+ args.Handled = true;
}
}
/// <summary>
-/// Event raised on the user when research is stolen from a R&D server.
+/// Event raised on the user when research is stolen from a RND server.
/// Techs contains every technology id researched.
/// </summary>
[ByRefEvent]
-public record struct ResearchStolenEvent(EntityUid Used, EntityUid Target, List<String> Techs);
+public record struct ResearchStolenEvent(EntityUid Used, EntityUid Target, List<string> Techs);
/// </summary>
[DataField("delay"), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan Delay = TimeSpan.FromSeconds(20);
+
+ /// <summary>
+ /// The minimum number of technologies that will be stolen
+ /// </summary>
+ [DataField]
+ public int MinToSteal = 4;
+
+ /// <summary>
+ /// The maximum number of technologies that will be stolen
+ /// </summary>
+ [DataField]
+ public int MaxToSteal = 8;
}
using System.Linq;
using Content.Shared.Research.Components;
using Content.Shared.Research.Prototypes;
+using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;
if (!Resolve(uid, ref component))
return;
- var discipline = PrototypeManager.Index<TechDisciplinePrototype>(prototype.Discipline);
+ var discipline = PrototypeManager.Index(prototype.Discipline);
if (prototype.Tier < discipline.LockoutTier)
return;
component.MainDiscipline = prototype.Discipline;
Dirty(uid, component);
}
+ /// <summary>
+ /// Removes a technology and its recipes from a technology database.
+ /// </summary>
+ public bool TryRemoveTechnology(Entity<TechnologyDatabaseComponent> entity, ProtoId<TechnologyPrototype> tech)
+ {
+ return TryRemoveTechnology(entity, PrototypeManager.Index(tech));
+ }
+
+ /// <summary>
+ /// Removes a technology and its recipes from a technology database.
+ /// </summary>
+ [PublicAPI]
+ public bool TryRemoveTechnology(Entity<TechnologyDatabaseComponent> entity, TechnologyPrototype tech)
+ {
+ if (!entity.Comp.UnlockedTechnologies.Remove(tech.ID))
+ return false;
+
+ // check to make sure we didn't somehow get the recipe from another tech.
+ // unlikely, but whatever
+ var recipes = tech.RecipeUnlocks;
+ foreach (var recipe in recipes)
+ {
+ var hasTechElsewhere = false;
+ foreach (var unlockedTech in entity.Comp.UnlockedTechnologies)
+ {
+ var unlockedTechProto = PrototypeManager.Index<TechnologyPrototype>(unlockedTech);
+
+ if (!unlockedTechProto.RecipeUnlocks.Contains(recipe))
+ continue;
+ hasTechElsewhere = true;
+ break;
+ }
+
+ if (!hasTechElsewhere)
+ entity.Comp.UnlockedRecipes.Remove(recipe);
+ }
+ Dirty(entity, entity.Comp);
+ UpdateTechnologyCards(entity, entity);
+ return true;
+ }
+
/// <summary>
/// Clear all unlocked technologies from the database.
/// </summary>
+ [PublicAPI]
public void ClearTechs(EntityUid uid, TechnologyDatabaseComponent? comp = null)
{
if (!Resolve(uid, ref comp) || comp.UnlockedTechnologies.Count == 0)
sprite: Structures/Machines/server.rsi
state: server
- type: NumberObjective
- min: 5
- max: 10
+ min: 9
+ max: 13
title: objective-condition-steal-research-title
- type: StealResearchCondition