]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Blueprints (#31138)
authorNemanja <98561806+EmoGarbage404@users.noreply.github.com>
Sun, 25 Aug 2024 12:06:50 +0000 (08:06 -0400)
committerGitHub <noreply@github.com>
Sun, 25 Aug 2024 12:06:50 +0000 (22:06 +1000)
* Blueprints

* Update tables_loot.yml

* doink

* mark as required

15 files changed:
Content.Server/Lathe/LatheSystem.cs
Content.Shared/Lathe/LatheComponent.cs
Content.Shared/Research/Components/BlueprintComponent.cs [new file with mode: 0644]
Content.Shared/Research/Components/BlueprintReceiverComponent.cs [new file with mode: 0644]
Content.Shared/Research/Systems/BlueprintSystem.cs [new file with mode: 0644]
Resources/Locale/en-US/research/components/blueprint.ftl [new file with mode: 0644]
Resources/Prototypes/Entities/Markers/Spawners/Random/Salvage/tables_loot.yml
Resources/Prototypes/Entities/Objects/Tools/blueprint.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Structures/Machines/lathe.yml
Resources/Prototypes/Recipes/Lathes/salvage.yml
Resources/Prototypes/tags.yml
Resources/Textures/Objects/Tools/blueprint.rsi/icon.png [new file with mode: 0644]
Resources/Textures/Objects/Tools/blueprint.rsi/inhand-left.png [new file with mode: 0644]
Resources/Textures/Objects/Tools/blueprint.rsi/inhand-right.png [new file with mode: 0644]
Resources/Textures/Objects/Tools/blueprint.rsi/meta.json [new file with mode: 0644]

index 5ece533a628fc3edfc61fbc57eb4518b6fa4955f..6d7d4e453315d99367a9c59e7be1708d083a12f2 100644 (file)
@@ -155,10 +155,10 @@ namespace Content.Server.Lathe
         {
             var ev = new LatheGetRecipesEvent(uid, getUnavailable)
             {
-                Recipes = new List<ProtoId<LatheRecipePrototype>>(component.StaticRecipes)
+                Recipes = new HashSet<ProtoId<LatheRecipePrototype>>(component.StaticRecipes)
             };
             RaiseLocalEvent(uid, ev);
-            return ev.Recipes;
+            return ev.Recipes.ToList();
         }
 
         public static List<ProtoId<LatheRecipePrototype>> GetAllBaseRecipes(LatheComponent component)
index 7924a0ec94425cde72ecc73d7ac0778ef3f865c7..de4311e5595c15772595debc9c25b4468050fbb3 100644 (file)
@@ -83,7 +83,7 @@ namespace Content.Shared.Lathe
 
         public bool getUnavailable;
 
-        public List<ProtoId<LatheRecipePrototype>> Recipes = new();
+        public HashSet<ProtoId<LatheRecipePrototype>> Recipes = new();
 
         public LatheGetRecipesEvent(EntityUid lathe, bool forced)
         {
diff --git a/Content.Shared/Research/Components/BlueprintComponent.cs b/Content.Shared/Research/Components/BlueprintComponent.cs
new file mode 100644 (file)
index 0000000..71ed3da
--- /dev/null
@@ -0,0 +1,19 @@
+using Content.Shared.Research.Prototypes;
+using Content.Shared.Research.Systems;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Research.Components;
+
+/// <summary>
+/// This is used for an item that is inserted directly into a given lathe to provide it with a recipe.
+/// </summary>
+[RegisterComponent, NetworkedComponent, Access(typeof(BlueprintSystem))]
+public sealed partial class BlueprintComponent : Component
+{
+    /// <summary>
+    /// The recipes that this blueprint provides.
+    /// </summary>
+    [DataField(required: true)]
+    public HashSet<ProtoId<LatheRecipePrototype>> ProvidedRecipes = new();
+}
diff --git a/Content.Shared/Research/Components/BlueprintReceiverComponent.cs b/Content.Shared/Research/Components/BlueprintReceiverComponent.cs
new file mode 100644 (file)
index 0000000..94c323e
--- /dev/null
@@ -0,0 +1,18 @@
+using Content.Shared.Research.Systems;
+using Content.Shared.Whitelist;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Research.Components;
+
+/// <summary>
+/// This is used for a lathe that can utilize <see cref="BlueprintComponent"/>s to gain more recipes.
+/// </summary>
+[RegisterComponent, NetworkedComponent, Access(typeof(BlueprintSystem))]
+public sealed partial class BlueprintReceiverComponent : Component
+{
+    [DataField]
+    public string ContainerId = "blueprint";
+
+    [DataField(required: true)]
+    public EntityWhitelist Whitelist = new();
+}
diff --git a/Content.Shared/Research/Systems/BlueprintSystem.cs b/Content.Shared/Research/Systems/BlueprintSystem.cs
new file mode 100644 (file)
index 0000000..237ff70
--- /dev/null
@@ -0,0 +1,114 @@
+using Content.Shared.IdentityManagement;
+using Content.Shared.Interaction;
+using Content.Shared.Lathe;
+using Content.Shared.Popups;
+using Content.Shared.Research.Components;
+using Content.Shared.Research.Prototypes;
+using Content.Shared.Whitelist;
+using Robust.Shared.Containers;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Research.Systems;
+
+public sealed class BlueprintSystem : EntitySystem
+{
+    [Dependency] private readonly SharedContainerSystem _container = default!;
+    [Dependency] private readonly EntityWhitelistSystem _entityWhitelist = default!;
+    [Dependency] private readonly SharedPopupSystem _popup = default!;
+
+    /// <inheritdoc/>
+    public override void Initialize()
+    {
+        SubscribeLocalEvent<BlueprintReceiverComponent, ComponentStartup>(OnStartup);
+        SubscribeLocalEvent<BlueprintReceiverComponent, AfterInteractUsingEvent>(OnAfterInteract);
+        SubscribeLocalEvent<BlueprintReceiverComponent, LatheGetRecipesEvent>(OnGetRecipes);
+    }
+
+    private void OnStartup(Entity<BlueprintReceiverComponent> ent, ref ComponentStartup args)
+    {
+        _container.EnsureContainer<Container>(ent, ent.Comp.ContainerId);
+    }
+
+    private void OnAfterInteract(Entity<BlueprintReceiverComponent> ent, ref AfterInteractUsingEvent args)
+    {
+        if (args.Handled || !args.CanReach || !TryComp<BlueprintComponent>(args.Used, out var blueprintComponent))
+            return;
+        args.Handled = TryInsertBlueprint(ent, (args.Used, blueprintComponent), args.User);
+    }
+
+    private void OnGetRecipes(Entity<BlueprintReceiverComponent> ent, ref LatheGetRecipesEvent args)
+    {
+        var recipes = GetBlueprintRecipes(ent);
+        foreach (var recipe in recipes)
+        {
+            args.Recipes.Add(recipe);
+        }
+    }
+
+    public bool TryInsertBlueprint(Entity<BlueprintReceiverComponent> ent, Entity<BlueprintComponent> blueprint, EntityUid? user)
+    {
+        if (!CanInsertBlueprint(ent, blueprint, user))
+            return false;
+
+        if (user is not null)
+        {
+            var userId = Identity.Entity(user.Value, EntityManager);
+            var bpId = Identity.Entity(blueprint, EntityManager);
+            var machineId = Identity.Entity(ent, EntityManager);
+            var msg = Loc.GetString("blueprint-receiver-popup-insert",
+                ("user", userId),
+                ("blueprint", bpId),
+                ("receiver", machineId));
+            _popup.PopupPredicted(msg, ent, user);
+        }
+
+        _container.Insert(blueprint.Owner, _container.GetContainer(ent, ent.Comp.ContainerId));
+
+        var ev = new TechnologyDatabaseModifiedEvent();
+        RaiseLocalEvent(ent, ref ev);
+        return true;
+    }
+
+    public bool CanInsertBlueprint(Entity<BlueprintReceiverComponent> ent, Entity<BlueprintComponent> blueprint, EntityUid? user)
+    {
+        if (_entityWhitelist.IsWhitelistFail(ent.Comp.Whitelist, blueprint))
+        {
+            return false;
+        }
+
+        if (blueprint.Comp.ProvidedRecipes.Count == 0)
+        {
+            Log.Error($"Attempted to insert blueprint {ToPrettyString(blueprint)} with no recipes.");
+            return false;
+        }
+
+        // Don't add new blueprints if there are no new recipes.
+        var currentRecipes = GetBlueprintRecipes(ent);
+        if (currentRecipes.Count != 0 && currentRecipes.IsSupersetOf(blueprint.Comp.ProvidedRecipes))
+        {
+            _popup.PopupPredicted(Loc.GetString("blueprint-receiver-popup-recipe-exists"), ent, user);
+            return false;
+        }
+
+        return _container.CanInsert(blueprint, _container.GetContainer(ent, ent.Comp.ContainerId));
+    }
+
+    public HashSet<ProtoId<LatheRecipePrototype>> GetBlueprintRecipes(Entity<BlueprintReceiverComponent> ent)
+    {
+        var contained = _container.GetContainer(ent, ent.Comp.ContainerId);
+
+        var recipes = new HashSet<ProtoId<LatheRecipePrototype>>();
+        foreach (var blueprint in contained.ContainedEntities)
+        {
+            if (!TryComp<BlueprintComponent>(blueprint, out var blueprintComponent))
+                continue;
+
+            foreach (var provided in blueprintComponent.ProvidedRecipes)
+            {
+                recipes.Add(provided);
+            }
+        }
+
+        return recipes;
+    }
+}
diff --git a/Resources/Locale/en-US/research/components/blueprint.ftl b/Resources/Locale/en-US/research/components/blueprint.ftl
new file mode 100644 (file)
index 0000000..34c3a3c
--- /dev/null
@@ -0,0 +1,2 @@
+blueprint-receiver-popup-insert = { CAPITALIZE(THE($user)) } inserted { THE($blueprint) } into { THE($receiver) }.
+blueprint-receiver-popup-recipe-exists = The same blueprint was already inserted!
index 5e128e8f962f31a2ecc6f3e2424b30eb5bb05801..61b3d1081712c647735205852bd1e39ac20e6d19 100644 (file)
   id: SalvageEquipmentRare
   table: !type:GroupSelector
     children:
+    - id: BlueprintFlare
     - id: FultonBeacon
     - id: Fulton
       amount: !type:RangeNumberSelector
   id: SalvageEquipmentLegendary
   table: !type:GroupSelector
     children:
+    - id: BlueprintFulton
+    - id: BlueprintSeismicCharge
     - id: WeaponCrusherGlaive
     - id: ClothingOuterHardsuitSalvage
     - id: OmnizineChemistryBottle
diff --git a/Resources/Prototypes/Entities/Objects/Tools/blueprint.yml b/Resources/Prototypes/Entities/Objects/Tools/blueprint.yml
new file mode 100644 (file)
index 0000000..ba26baf
--- /dev/null
@@ -0,0 +1,49 @@
+- type: entity
+  parent: BaseItem
+  id: BaseBlueprint
+  name: blueprint
+  description: A blueprint for some machine. It can be inserted into an autolathe.
+  abstract: true
+  components:
+  - type: Sprite
+    sprite: Objects/Tools/blueprint.rsi
+    state: icon
+  - type: Item
+    sprite: Objects/Tools/blueprint.rsi
+    size: Normal
+  - type: Blueprint
+  - type: StaticPrice
+    price: 1000
+  - type: Tag
+    tags:
+    - BlueprintAutolathe
+
+- type: entity
+  parent: BaseBlueprint
+  id: BlueprintFulton
+  name: fulton blueprint
+  description: A blueprint with a schematic of a fulton. It can be inserted into an autolathe.
+  components:
+  - type: Blueprint
+    providedRecipes:
+    - Fulton
+
+- type: entity
+  parent: BaseBlueprint
+  id: BlueprintSeismicCharge
+  name: seismic charge blueprint
+  description: A blueprint with a schematic of a seismic charge. It can be inserted into an autolathe.
+  components:
+  - type: Blueprint
+    providedRecipes:
+    - SeismicCharge
+
+- type: entity
+  parent: BaseBlueprint
+  id: BlueprintFlare
+  name: flare blueprint
+  description: A blueprint with a schematic of a flare. It can be inserted into an autolathe.
+  components:
+  - type: Blueprint
+    providedRecipes:
+    - Flare
index bf4d4de7833f04a8de3f830cdae70a6d34b1aec7..91ac7b049a4ad5ed561896072e4c91b15a41b4e7 100644 (file)
@@ -89,7 +89,7 @@
   id: Autolathe
   parent: BaseLatheLube
   name: autolathe
-  description: It produces basic items using metal and glass.
+  description: It produces basic items using metal and glass. Has the ability to process blueprints to print new recipes.
   components:
   - type: Sprite
     sprite: Structures/Machines/autolathe.rsi
       - RiotShield
       - SpeedLoaderMagnum
       - SpeedLoaderMagnumEmpty
+  - type: BlueprintReceiver
+    whitelist:
+      tags:
+      - BlueprintAutolathe
+  - type: ContainerContainer
+    containers:
+      machine_board: !type:Container
+      machine_parts: !type:Container
+      blueprint: !type:Container
+  - type: EmptyOnMachineDeconstruct
+    containers:
+    - blueprint
 
 - type: entity
   id: AutolatheHyperConvection
index 84047ae75d847c210c925f0e4aa212a8371c3ec2..2def767e9172519080f2ce5f1f933b216d83b52f 100644 (file)
@@ -1,20 +1,32 @@
 - type: latheRecipe
   id: Fulton
   result: Fulton1
+  category: Tools
   completetime: 1
   materials:
     Steel: 200
-    Cloth: 100
+    Cloth: 500
 
 - type: latheRecipe
   id: FultonBeacon
   result: FultonBeacon
+  category: Tools
   completetime: 5
   materials:
     Steel: 1000
     Glass: 500
     # If they get spammed make it cost silver.
 
+- type: latheRecipe
+  id: SeismicCharge
+  result: SeismicCharge
+  category: Tools
+  completetime: 1
+  materials:
+    Plastic: 1500
+    Steel: 100
+    Silver: 100
+
 - type: latheRecipe
   id: MiningDrill
   result: MiningDrill
index 9b11570a252023a8d62017db149ebf7ed28b53f9..b52e2c4e8c5cf6ddfb9d6b73e68693b70715f80c 100644 (file)
@@ -60,6 +60,9 @@
 - type: Tag
   id: Bloodpack
 
+- type: Tag
+  id: BlueprintAutolathe
+
 - type: Tag
   id: BodyBag
 
diff --git a/Resources/Textures/Objects/Tools/blueprint.rsi/icon.png b/Resources/Textures/Objects/Tools/blueprint.rsi/icon.png
new file mode 100644 (file)
index 0000000..fe8b37f
Binary files /dev/null and b/Resources/Textures/Objects/Tools/blueprint.rsi/icon.png differ
diff --git a/Resources/Textures/Objects/Tools/blueprint.rsi/inhand-left.png b/Resources/Textures/Objects/Tools/blueprint.rsi/inhand-left.png
new file mode 100644 (file)
index 0000000..8aecdd7
Binary files /dev/null and b/Resources/Textures/Objects/Tools/blueprint.rsi/inhand-left.png differ
diff --git a/Resources/Textures/Objects/Tools/blueprint.rsi/inhand-right.png b/Resources/Textures/Objects/Tools/blueprint.rsi/inhand-right.png
new file mode 100644 (file)
index 0000000..37dd59e
Binary files /dev/null and b/Resources/Textures/Objects/Tools/blueprint.rsi/inhand-right.png differ
diff --git a/Resources/Textures/Objects/Tools/blueprint.rsi/meta.json b/Resources/Textures/Objects/Tools/blueprint.rsi/meta.json
new file mode 100644 (file)
index 0000000..ab9e7fb
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "version": 1,
+    "license": "CC-BY-SA-3.0",
+    "copyright": "Taken from https://github.com/vgstation-coders/vgstation13/commit/dd749c36c416a6960782732cecf25e5ebac326e8",
+    "size": {
+        "x": 32,
+        "y": 32
+    },
+    "states": [
+        {
+            "name": "inhand-left",
+            "directions": 4
+        },
+        {
+            "name": "inhand-right",
+            "directions": 4
+        },
+        {
+            "name": "icon"
+        }
+    ]
+}