2022-09-26 16:18:31 -04:00
using System.Linq ;
2022-02-03 10:04:46 +11:00
using Content.Server.Construction.Components ;
2022-11-04 04:27:47 +01:00
using Content.Server.Examine ;
2022-09-26 16:18:31 -04:00
using Content.Shared.Construction.Prototypes ;
2022-11-04 04:27:47 +01:00
using Content.Shared.Verbs ;
2022-02-03 10:04:46 +11:00
using Robust.Shared.Containers ;
2022-11-04 04:27:47 +01:00
using Robust.Shared.Utility ;
2022-02-03 10:04:46 +11:00
namespace Content.Server.Construction ;
public sealed partial class ConstructionSystem
{
2022-11-04 04:27:47 +01:00
[Dependency] private readonly ExamineSystem _examineSystem = default ! ;
2022-02-03 10:04:46 +11:00
private void InitializeMachines ( )
{
SubscribeLocalEvent < MachineComponent , ComponentInit > ( OnMachineInit ) ;
SubscribeLocalEvent < MachineComponent , MapInitEvent > ( OnMachineMapInit ) ;
2022-11-04 04:27:47 +01:00
SubscribeLocalEvent < MachineComponent , GetVerbsEvent < ExamineVerb > > ( OnMachineExaminableVerb ) ;
2022-02-03 10:04:46 +11:00
}
private void OnMachineInit ( EntityUid uid , MachineComponent component , ComponentInit args )
{
2022-07-14 04:35:37 -07:00
component . BoardContainer = _container . EnsureContainer < Container > ( uid , MachineFrameComponent . BoardContainerName ) ;
component . PartContainer = _container . EnsureContainer < Container > ( uid , MachineFrameComponent . PartContainerName ) ;
2022-02-03 10:04:46 +11:00
}
private void OnMachineMapInit ( EntityUid uid , MachineComponent component , MapInitEvent args )
{
CreateBoardAndStockParts ( component ) ;
RefreshParts ( component ) ;
}
2022-11-04 04:27:47 +01:00
private void OnMachineExaminableVerb ( EntityUid uid , MachineComponent component , GetVerbsEvent < ExamineVerb > args )
{
if ( ! args . CanInteract | | ! args . CanAccess )
return ;
var markup = new FormattedMessage ( ) ;
RaiseLocalEvent ( uid , new UpgradeExamineEvent ( ref markup ) ) ;
if ( markup . IsEmpty )
return ; // Not upgradable.
markup = FormattedMessage . FromMarkup ( markup . ToMarkup ( ) . TrimEnd ( '\n' ) ) ; // Cursed workaround to https://github.com/space-wizards/RobustToolbox/issues/3371
var verb = new ExamineVerb ( )
{
Act = ( ) = >
{
_examineSystem . SendExamineTooltip ( args . User , uid , markup , getVerbs : false , centerAtCursor : false ) ;
} ,
2022-11-06 08:50:19 +01:00
Text = Loc . GetString ( "machine-upgrade-examinable-verb-text" ) ,
Message = Loc . GetString ( "machine-upgrade-examinable-verb-message" ) ,
2022-11-04 04:27:47 +01:00
Category = VerbCategory . Examine ,
IconTexture = "/Textures/Interface/VerbIcons/pickup.svg.192dpi.png"
} ;
args . Verbs . Add ( verb ) ;
}
2022-02-07 13:10:43 +11:00
public List < MachinePartComponent > GetAllParts ( MachineComponent component )
2022-02-03 10:04:46 +11:00
{
2022-02-07 13:10:43 +11:00
var parts = new List < MachinePartComponent > ( ) ;
2022-02-03 10:04:46 +11:00
foreach ( var entity in component . PartContainer . ContainedEntities )
{
if ( TryComp < MachinePartComponent ? > ( entity , out var machinePart ) )
2022-02-07 13:10:43 +11:00
parts . Add ( machinePart ) ;
2022-02-03 10:04:46 +11:00
}
2022-02-07 13:10:43 +11:00
return parts ;
2022-02-03 10:04:46 +11:00
}
2022-09-26 16:18:31 -04:00
public Dictionary < string , float > GetPartsRatings ( List < MachinePartComponent > parts )
{
var output = new Dictionary < string , float > ( ) ;
foreach ( var type in _prototypeManager . EnumeratePrototypes < MachinePartPrototype > ( ) )
{
var amount = 0 ;
var sumRating = 0 ;
foreach ( var part in parts . Where ( part = > part . PartType = = type . ID ) )
{
amount + + ;
sumRating + = part . Rating ;
}
var rating = amount ! = 0 ? sumRating / amount : 0 ;
output . Add ( type . ID , rating ) ;
}
return output ;
}
2022-02-03 10:04:46 +11:00
public void RefreshParts ( MachineComponent component )
{
2022-09-26 16:18:31 -04:00
var parts = GetAllParts ( component ) ;
EntityManager . EventBus . RaiseLocalEvent ( component . Owner , new RefreshPartsEvent
2022-02-03 10:04:46 +11:00
{
2022-09-26 16:18:31 -04:00
Parts = parts ,
PartRatings = GetPartsRatings ( parts ) ,
2022-06-22 09:53:41 +10:00
} , true ) ;
2022-02-03 10:04:46 +11:00
}
public void CreateBoardAndStockParts ( MachineComponent component )
{
// Entity might not be initialized yet.
2022-07-14 04:35:37 -07:00
var boardContainer = _container . EnsureContainer < Container > ( component . Owner , MachineFrameComponent . BoardContainerName ) ;
var partContainer = _container . EnsureContainer < Container > ( component . Owner , MachineFrameComponent . PartContainerName ) ;
2022-02-03 10:04:46 +11:00
if ( string . IsNullOrEmpty ( component . BoardPrototype ) )
return ;
// We're done here, let's suppose all containers are correct just so we don't screw SaveLoadSave.
if ( boardContainer . ContainedEntities . Count > 0 )
return ;
var board = EntityManager . SpawnEntity ( component . BoardPrototype , Transform ( component . Owner ) . Coordinates ) ;
if ( ! component . BoardContainer . Insert ( board ) )
{
throw new Exception ( $"Couldn't insert board with prototype {component.BoardPrototype} to machine with prototype {MetaData(component.Owner).EntityPrototype?.ID ?? " N / A "}!" ) ;
}
if ( ! TryComp < MachineBoardComponent ? > ( board , out var machineBoard ) )
{
throw new Exception ( $"Entity with prototype {component.BoardPrototype} doesn't have a {nameof(MachineBoardComponent)}!" ) ;
}
2022-09-26 16:18:31 -04:00
var xform = Transform ( component . Owner ) ;
2022-02-03 10:04:46 +11:00
foreach ( var ( part , amount ) in machineBoard . Requirements )
{
2022-09-26 16:18:31 -04:00
var partProto = _prototypeManager . Index < MachinePartPrototype > ( part ) ;
2022-02-03 10:04:46 +11:00
for ( var i = 0 ; i < amount ; i + + )
{
2022-09-26 16:18:31 -04:00
var p = EntityManager . SpawnEntity ( partProto . StockPartPrototype , xform . Coordinates ) ;
2022-02-03 10:04:46 +11:00
if ( ! partContainer . Insert ( p ) )
2022-09-26 16:18:31 -04:00
throw new Exception ( $"Couldn't insert machine part of type {part} to machine with prototype {partProto.StockPartPrototype ?? " N / A "}!" ) ;
2022-02-03 10:04:46 +11:00
}
}
foreach ( var ( stackType , amount ) in machineBoard . MaterialRequirements )
{
var stack = _stackSystem . Spawn ( amount , stackType , Transform ( component . Owner ) . Coordinates ) ;
if ( ! partContainer . Insert ( stack ) )
throw new Exception ( $"Couldn't insert machine material of type {stackType} to machine with prototype {MetaData(component.Owner).EntityPrototype?.ID ?? " N / A "}" ) ;
}
foreach ( var ( compName , info ) in machineBoard . ComponentRequirements )
{
for ( var i = 0 ; i < info . Amount ; i + + )
{
var c = EntityManager . SpawnEntity ( info . DefaultPrototype , Transform ( component . Owner ) . Coordinates ) ;
if ( ! partContainer . Insert ( c ) )
throw new Exception ( $"Couldn't insert machine component part with default prototype '{compName}' to machine with prototype {MetaData(component.Owner).EntityPrototype?.ID ?? " N / A "}" ) ;
}
}
foreach ( var ( tagName , info ) in machineBoard . TagRequirements )
{
for ( var i = 0 ; i < info . Amount ; i + + )
{
var c = EntityManager . SpawnEntity ( info . DefaultPrototype , Transform ( component . Owner ) . Coordinates ) ;
if ( ! partContainer . Insert ( c ) )
throw new Exception ( $"Couldn't insert machine component part with default prototype '{tagName}' to machine with prototype {MetaData(component.Owner).EntityPrototype?.ID ?? " N / A "}" ) ;
}
}
}
}
2022-02-07 13:10:43 +11:00
public sealed class RefreshPartsEvent : EntityEventArgs
{
public IReadOnlyList < MachinePartComponent > Parts = new List < MachinePartComponent > ( ) ;
2022-09-26 16:18:31 -04:00
public Dictionary < string , float > PartRatings = new Dictionary < string , float > ( ) ;
2022-02-07 13:10:43 +11:00
}
2022-11-04 04:27:47 +01:00
public sealed class UpgradeExamineEvent : EntityEventArgs
{
private FormattedMessage Message ;
public UpgradeExamineEvent ( ref FormattedMessage message )
{
Message = message ;
}
/// <summary>
/// Add a line to the upgrade examine tooltip with a percentage-based increase or decrease.
/// </summary>
public void AddPercentageUpgrade ( string upgradedLocId , float multiplier )
{
var percent = Math . Round ( 100 * MathF . Abs ( multiplier - 1 ) , 2 ) ;
var locId = multiplier switch {
< 1 = > "machine-upgrade-decreased-by-percentage" ,
1 or float . NaN = > "machine-upgrade-not-upgraded" ,
> 1 = > "machine-upgrade-increased-by-percentage" ,
} ;
var upgraded = Loc . GetString ( upgradedLocId ) ;
this . Message . AddMarkup ( Loc . GetString ( locId , ( "upgraded" , upgraded ) , ( "percent" , percent ) ) + '\n' ) ;
}
/// <summary>
/// Add a line to the upgrade examine tooltip with a numeric increase or decrease.
/// </summary>
public void AddNumberUpgrade ( string upgradedLocId , int number )
{
var difference = Math . Abs ( number ) ;
var locId = number switch {
< 0 = > "machine-upgrade-decreased-by-amount" ,
0 = > "machine-upgrade-not-upgraded" ,
> 0 = > "machine-upgrade-increased-by-amount" ,
} ;
var upgraded = Loc . GetString ( upgradedLocId ) ;
this . Message . AddMarkup ( Loc . GetString ( locId , ( "upgraded" , upgraded ) , ( "difference" , difference ) ) + '\n' ) ;
}
}