Blueprints (#31138)

* Blueprints

* Update tables_loot.yml

* doink

* mark as required
This commit is contained in:
Nemanja
2024-08-25 08:06:50 -04:00
committed by GitHub
parent f03fc585ba
commit 85b7d183bd
15 changed files with 259 additions and 5 deletions

View 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)

View 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)
{

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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!

View File

@@ -207,6 +207,7 @@
id: SalvageEquipmentRare
table: !type:GroupSelector
children:
- id: BlueprintFlare
- id: FultonBeacon
- id: Fulton
amount: !type:RangeNumberSelector
@@ -228,6 +229,8 @@
id: SalvageEquipmentLegendary
table: !type:GroupSelector
children:
- id: BlueprintFulton
- id: BlueprintSeismicCharge
- id: WeaponCrusherGlaive
- id: ClothingOuterHardsuitSalvage
- id: OmnizineChemistryBottle

View File

@@ -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

View 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
@@ -226,6 +226,18 @@
- 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

View 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

View File

@@ -60,6 +60,9 @@
- type: Tag
id: Bloodpack
- type: Tag
id: BlueprintAutolathe
- type: Tag
id: BodyBag

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

View File

@@ -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"
}
]
}