2024-08-29 20:23:33 +05:00
/ *
* This file is sublicensed under MIT License
* https : //github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
* /
2024-08-06 21:25:59 +10:00
using Content.Server.DoAfter ;
2024-07-22 12:16:32 +03:00
using Content.Server.Popups ;
2024-08-06 21:25:59 +10:00
using Content.Server.Stack ;
2024-07-22 12:16:32 +03:00
using Content.Shared._CP14.Workbench ;
using Content.Shared._CP14.Workbench.Prototypes ;
2024-09-28 01:29:02 +03:00
using Content.Shared.Chemistry.EntitySystems ;
2024-07-22 12:16:32 +03:00
using Content.Shared.DoAfter ;
using Content.Shared.Stacks ;
2024-08-06 21:25:59 +10:00
using Content.Shared.UserInterface ;
using Robust.Server.Audio ;
using Robust.Server.GameObjects ;
2024-07-22 12:16:32 +03:00
using Robust.Shared.Prototypes ;
namespace Content.Server._CP14.Workbench ;
2024-08-06 21:25:59 +10:00
public sealed partial class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
2024-07-22 12:16:32 +03:00
{
2024-08-06 21:25:59 +10:00
[Dependency] private readonly AudioSystem _audio = default ! ;
[Dependency] private readonly EntityLookupSystem _lookup = default ! ;
[Dependency] private readonly DoAfterSystem _doAfter = default ! ;
[Dependency] private readonly StackSystem _stack = default ! ;
2024-07-22 12:16:32 +03:00
[Dependency] private readonly IPrototypeManager _proto = default ! ;
[Dependency] private readonly PopupSystem _popup = default ! ;
2024-08-06 21:25:59 +10:00
[Dependency] private readonly UserInterfaceSystem _userInterface = default ! ;
2024-09-28 01:29:02 +03:00
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default ! ;
2024-08-19 18:39:47 +03:00
[Dependency] private readonly SharedTransformSystem _transform = default ! ;
2024-07-22 12:16:32 +03:00
private EntityQuery < MetaDataComponent > _metaQuery ;
private EntityQuery < StackComponent > _stackQuery ;
public override void Initialize ( )
{
base . Initialize ( ) ;
_metaQuery = GetEntityQuery < MetaDataComponent > ( ) ;
_stackQuery = GetEntityQuery < StackComponent > ( ) ;
2024-09-28 01:29:02 +03:00
SubscribeLocalEvent < CP14WorkbenchComponent , MapInitEvent > ( OnMapInit ) ;
2024-08-06 21:25:59 +10:00
SubscribeLocalEvent < CP14WorkbenchComponent , BeforeActivatableUIOpenEvent > ( OnBeforeUIOpen ) ;
SubscribeLocalEvent < CP14WorkbenchComponent , CP14WorkbenchUiCraftMessage > ( OnCraft ) ;
2024-07-22 12:16:32 +03:00
SubscribeLocalEvent < CP14WorkbenchComponent , CP14CraftDoAfterEvent > ( OnCraftFinished ) ;
}
2024-09-28 01:29:02 +03:00
private void OnMapInit ( Entity < CP14WorkbenchComponent > ent , ref MapInitEvent args )
{
foreach ( var recipe in _proto . EnumeratePrototypes < CP14WorkbenchRecipePrototype > ( ) )
{
if ( ent . Comp . Recipes . Contains ( recipe ) )
continue ;
if ( ! ent . Comp . RecipeTags . Contains ( recipe . Tag ) )
continue ;
ent . Comp . Recipes . Add ( recipe ) ;
}
}
2024-08-06 21:25:59 +10:00
private void OnBeforeUIOpen ( Entity < CP14WorkbenchComponent > ent , ref BeforeActivatableUIOpenEvent args )
{
UpdateUIRecipes ( ent ) ;
}
// TODO: Replace Del to QueueDel when it's will be works with events
2024-07-22 12:16:32 +03:00
private void OnCraftFinished ( Entity < CP14WorkbenchComponent > ent , ref CP14CraftDoAfterEvent args )
{
if ( args . Cancelled | | args . Handled )
return ;
if ( ! _proto . TryIndex ( args . Recipe , out var recipe ) )
return ;
2024-09-28 01:29:02 +03:00
var placedEntities = _lookup . GetEntitiesInRange ( Transform ( ent ) . Coordinates , ent . Comp . WorkbenchRadius , LookupFlags . Uncontained ) ;
2024-07-22 12:16:32 +03:00
if ( ! CanCraftRecipe ( recipe , placedEntities ) )
{
_popup . PopupEntity ( Loc . GetString ( "cp14-workbench-no-resource" ) , ent , args . User ) ;
return ;
}
2024-08-19 18:39:47 +03:00
var resultEntity = Spawn ( _proto . Index ( args . Recipe ) . Result ) ;
2024-10-17 13:08:36 +03:00
_stack . TryMergeToContacts ( resultEntity ) ;
2024-08-19 18:39:47 +03:00
_solutionContainer . TryGetSolution ( resultEntity , recipe . Solution , out var resultSoln , out var resultSolution ) ;
if ( recipe . TryMergeSolutions & & resultSoln is not null )
{
resultSoln . Value . Comp . Solution . MaxVolume = 0 ;
_solutionContainer . RemoveAllSolution ( resultSoln . Value ) ; //If we combine ingredient solutions, we do not use the default solution prescribed in the entity.
}
2024-07-22 12:16:32 +03:00
foreach ( var requiredIngredient in recipe . Entities )
{
var requiredCount = requiredIngredient . Value ;
foreach ( var placedEntity in placedEntities )
{
2024-08-19 18:39:47 +03:00
if ( ! TryComp < MetaDataComponent > ( placedEntity , out var metaData ) | | metaData . EntityPrototype is null )
continue ;
var placedProto = metaData . EntityPrototype . ID ;
if ( placedProto = = requiredIngredient . Key & & requiredCount > 0 )
2024-07-22 12:16:32 +03:00
{
2024-08-19 18:39:47 +03:00
// Trying merge solutions
if ( recipe . TryMergeSolutions
& & resultSoln is not null
& & _solutionContainer . TryGetSolution ( placedEntity , recipe . Solution , out var ingredientSoln , out var ingredientSolution ) )
{
resultSoln . Value . Comp . Solution . MaxVolume + = ingredientSoln . Value . Comp . Solution . MaxVolume ;
_solutionContainer . TryAddSolution ( resultSoln . Value , ingredientSolution ) ;
}
2024-07-22 12:16:32 +03:00
requiredCount - - ;
2024-08-06 21:25:59 +10:00
Del ( placedEntity ) ;
2024-07-22 12:16:32 +03:00
}
}
}
foreach ( var requiredStack in recipe . Stacks )
{
var requiredCount = requiredStack . Value ;
foreach ( var placedEntity in placedEntities )
{
if ( ! _stackQuery . TryGetComponent ( placedEntity , out var stack ) )
continue ;
if ( stack . StackTypeId ! = requiredStack . Key )
continue ;
var count = ( int ) MathF . Min ( requiredCount , stack . Count ) ;
2024-08-06 21:25:59 +10:00
if ( stack . Count - count < = 0 )
Del ( placedEntity ) ;
else
_stack . SetCount ( placedEntity , stack . Count - count , stack ) ;
2024-07-22 12:16:32 +03:00
requiredCount - = count ;
}
}
2024-08-19 18:39:47 +03:00
_transform . SetCoordinates ( resultEntity , Transform ( ent ) . Coordinates ) ;
2024-08-06 21:25:59 +10:00
UpdateUIRecipes ( ent ) ;
2024-07-22 12:16:32 +03:00
args . Handled = true ;
}
private void StartCraft ( Entity < CP14WorkbenchComponent > workbench , EntityUid user , CP14WorkbenchRecipePrototype recipe )
{
var craftDoAfter = new CP14CraftDoAfterEvent
{
Recipe = recipe . ID ,
} ;
var doAfterArgs = new DoAfterArgs ( EntityManager ,
user ,
recipe . CraftTime * workbench . Comp . CraftSpeed ,
craftDoAfter ,
workbench ,
workbench )
{
BreakOnMove = true ,
BreakOnDamage = true ,
NeedHand = true ,
} ;
_doAfter . TryStartDoAfter ( doAfterArgs ) ;
2024-07-23 10:29:41 +03:00
_audio . PlayPvs ( recipe . OverrideCraftSound ? ? workbench . Comp . CraftSound , workbench ) ;
2024-07-22 12:16:32 +03:00
}
private bool CanCraftRecipe ( CP14WorkbenchRecipePrototype recipe , HashSet < EntityUid > entities )
{
var indexedIngredients = IndexIngredients ( entities ) ;
foreach ( var requiredIngredient in recipe . Entities )
{
if ( ! indexedIngredients . TryGetValue ( requiredIngredient . Key , out var availableQuantity ) | |
availableQuantity < requiredIngredient . Value )
return false ;
}
foreach ( var ( key , value ) in recipe . Stacks )
{
var count = 0 ;
foreach ( var ent in entities )
{
if ( _stackQuery . TryGetComponent ( ent , out var stack ) )
{
if ( stack . StackTypeId ! = key )
continue ;
count + = stack . Count ;
}
}
if ( count < value )
return false ;
}
return true ;
}
private string GetCraftRecipeMessage ( string desc , CP14WorkbenchRecipePrototype recipe )
{
var result = desc + "\n \n" + Loc . GetString ( "cp14-workbench-recipe-list" ) + "\n" ;
foreach ( var pair in recipe . Entities )
{
var proto = _proto . Index ( pair . Key ) ;
result + = $"{proto.Name} x{pair.Value}\n" ;
}
foreach ( var pair in recipe . Stacks )
{
var proto = _proto . Index ( pair . Key ) ;
result + = $"{proto.Name} x{pair.Value}\n" ;
}
return result ;
}
private Dictionary < EntProtoId , int > IndexIngredients ( HashSet < EntityUid > ingredients )
{
var indexedIngredients = new Dictionary < EntProtoId , int > ( ) ;
foreach ( var ingredient in ingredients )
{
var protoId = _metaQuery . GetComponent ( ingredient ) . EntityPrototype ? . ID ;
if ( protoId = = null )
continue ;
if ( indexedIngredients . ContainsKey ( protoId ) )
indexedIngredients [ protoId ] + + ;
else
indexedIngredients [ protoId ] = 1 ;
}
return indexedIngredients ;
}
}