2023-07-29 00:14:39 -04:00
using Content.Shared.Database ;
2022-06-28 22:54:08 +10:00
using Content.Shared.Research.Components ;
using Content.Shared.Research.Prototypes ;
2023-05-15 16:17:30 -04:00
using JetBrains.Annotations ;
2022-06-28 22:54:08 +10:00
2022-12-19 16:14:02 -05:00
namespace Content.Server.Research.Systems ;
2022-06-28 22:54:08 +10:00
public sealed partial class ResearchSystem
{
/// <summary>
2022-12-25 16:22:23 -05:00
/// Syncs the primary entity's database to that of the secondary entity's database.
2022-06-28 22:54:08 +10:00
/// </summary>
2022-12-25 16:22:23 -05:00
public void Sync ( EntityUid primaryUid , EntityUid otherUid , TechnologyDatabaseComponent ? primaryDb = null , TechnologyDatabaseComponent ? otherDb = null )
2022-06-28 22:54:08 +10:00
{
2022-12-25 16:22:23 -05:00
if ( ! Resolve ( primaryUid , ref primaryDb ) | | ! Resolve ( otherUid , ref otherDb ) )
return ;
2022-06-28 22:54:08 +10:00
2023-05-15 16:17:30 -04:00
primaryDb . MainDiscipline = otherDb . MainDiscipline ;
primaryDb . CurrentTechnologyCards = otherDb . CurrentTechnologyCards ;
primaryDb . SupportedDisciplines = otherDb . SupportedDisciplines ;
primaryDb . UnlockedTechnologies = otherDb . UnlockedTechnologies ;
primaryDb . UnlockedRecipes = otherDb . UnlockedRecipes ;
2022-06-28 22:54:08 +10:00
2024-03-19 23:27:02 -04:00
Dirty ( primaryUid , primaryDb ) ;
2022-12-25 16:22:23 -05:00
var ev = new TechnologyDatabaseModifiedEvent ( ) ;
2023-05-15 16:17:30 -04:00
RaiseLocalEvent ( primaryUid , ref ev ) ;
2022-06-28 22:54:08 +10:00
}
/// <summary>
/// If there's a research client component attached to the owner entity,
/// and the research client is connected to a research server, this method
/// syncs against the research server, and the server against the local database.
/// </summary>
/// <returns>Whether it could sync or not</returns>
2023-05-15 16:17:30 -04:00
public void SyncClientWithServer ( EntityUid uid , TechnologyDatabaseComponent ? databaseComponent = null , ResearchClientComponent ? clientComponent = null )
2022-06-28 22:54:08 +10:00
{
2022-12-25 16:22:23 -05:00
if ( ! Resolve ( uid , ref databaseComponent , ref clientComponent , false ) )
2023-05-15 16:17:30 -04:00
return ;
2022-06-28 22:54:08 +10:00
2022-12-25 16:22:23 -05:00
if ( ! TryComp < TechnologyDatabaseComponent > ( clientComponent . Server , out var serverDatabase ) )
2023-05-15 16:17:30 -04:00
return ;
2022-06-28 22:54:08 +10:00
2022-12-25 16:22:23 -05:00
Sync ( uid , clientComponent . Server . Value , databaseComponent , serverDatabase ) ;
2022-06-28 22:54:08 +10:00
}
/// <summary>
2022-12-25 16:22:23 -05:00
/// Tries to add a technology to a database, checking if it is able to
/// </summary>
/// <returns>If the technology was successfully added</returns>
2023-07-29 00:14:39 -04:00
public bool UnlockTechnology ( EntityUid client ,
string prototypeid ,
EntityUid user ,
ResearchClientComponent ? component = null ,
2023-05-15 16:17:30 -04:00
TechnologyDatabaseComponent ? clientDatabase = null )
2022-12-25 16:22:23 -05:00
{
2023-05-15 16:17:30 -04:00
if ( ! PrototypeManager . TryIndex < TechnologyPrototype > ( prototypeid , out var prototype ) )
2022-12-25 16:22:23 -05:00
return false ;
2023-05-15 16:17:30 -04:00
2023-07-29 00:14:39 -04:00
return UnlockTechnology ( client , prototype , user , component , clientDatabase ) ;
2022-12-25 16:22:23 -05:00
}
/// <summary>
/// Tries to add a technology to a database, checking if it is able to
2022-06-28 22:54:08 +10:00
/// </summary>
2022-12-25 16:22:23 -05:00
/// <returns>If the technology was successfully added</returns>
2023-05-15 16:17:30 -04:00
public bool UnlockTechnology ( EntityUid client ,
TechnologyPrototype prototype ,
2023-07-29 00:14:39 -04:00
EntityUid user ,
2023-05-15 16:17:30 -04:00
ResearchClientComponent ? component = null ,
TechnologyDatabaseComponent ? clientDatabase = null )
2022-06-28 22:54:08 +10:00
{
2023-05-15 16:17:30 -04:00
if ( ! Resolve ( client , ref component , ref clientDatabase , false ) )
2022-12-25 16:22:23 -05:00
return false ;
2022-06-28 22:54:08 +10:00
2023-05-15 16:17:30 -04:00
if ( ! TryGetClientServer ( client , out var serverEnt , out _ , component ) )
2022-12-25 16:22:23 -05:00
return false ;
2023-05-15 16:17:30 -04:00
if ( ! CanServerUnlockTechnology ( client , prototype , clientDatabase , component ) )
2022-12-25 16:22:23 -05:00
return false ;
2023-05-15 16:17:30 -04:00
AddTechnology ( serverEnt . Value , prototype ) ;
TrySetMainDiscipline ( prototype , serverEnt . Value ) ;
ModifyServerPoints ( serverEnt . Value , - prototype . Cost ) ;
UpdateTechnologyCards ( serverEnt . Value ) ;
2023-07-29 00:14:39 -04:00
_adminLog . Add ( LogType . Action , LogImpact . Medium ,
$"{ToPrettyString(user):player} unlocked {prototype.ID} (discipline: {prototype.Discipline}, tier: {prototype.Tier}) at {ToPrettyString(client)}, for server {ToPrettyString(serverEnt.Value)}." ) ;
2022-06-28 22:54:08 +10:00
return true ;
}
/// <summary>
/// Adds a technology to the database without checking if it could be unlocked.
/// </summary>
2023-05-15 16:17:30 -04:00
[PublicAPI]
2022-12-25 16:22:23 -05:00
public void AddTechnology ( EntityUid uid , string technology , TechnologyDatabaseComponent ? component = null )
2022-06-28 22:54:08 +10:00
{
2022-12-25 16:22:23 -05:00
if ( ! Resolve ( uid , ref component ) )
return ;
2023-05-15 16:17:30 -04:00
if ( ! PrototypeManager . TryIndex < TechnologyPrototype > ( technology , out var prototype ) )
2022-12-20 17:39:57 -05:00
return ;
2022-12-25 16:22:23 -05:00
AddTechnology ( uid , prototype , component ) ;
2022-12-20 17:39:57 -05:00
}
2022-12-25 16:22:23 -05:00
/// <summary>
/// Adds a technology to the database without checking if it could be unlocked.
/// </summary>
public void AddTechnology ( EntityUid uid , TechnologyPrototype technology , TechnologyDatabaseComponent ? component = null )
2022-12-20 17:39:57 -05:00
{
2022-12-25 16:22:23 -05:00
if ( ! Resolve ( uid , ref component ) )
return ;
2023-05-15 16:17:30 -04:00
//todo this needs to support some other stuff, too
foreach ( var generic in technology . GenericUnlocks )
2022-12-20 17:39:57 -05:00
{
2023-05-15 16:17:30 -04:00
if ( generic . PurchaseEvent ! = null )
RaiseLocalEvent ( generic . PurchaseEvent ) ;
}
component . UnlockedTechnologies . Add ( technology . ID ) ;
foreach ( var unlock in technology . RecipeUnlocks )
{
if ( component . UnlockedRecipes . Contains ( unlock ) )
2022-12-20 17:39:57 -05:00
continue ;
2023-05-15 16:17:30 -04:00
component . UnlockedRecipes . Add ( unlock ) ;
2022-12-20 17:39:57 -05:00
}
2024-03-19 23:27:02 -04:00
Dirty ( uid , component ) ;
2022-12-20 17:39:57 -05:00
2022-12-25 16:22:23 -05:00
var ev = new TechnologyDatabaseModifiedEvent ( ) ;
RaiseLocalEvent ( uid , ref ev ) ;
2022-12-20 17:39:57 -05:00
}
2022-12-25 16:22:23 -05:00
/// <summary>
/// Adds a lathe recipe to the specified technology database
/// without checking if it can be unlocked.
/// </summary>
2023-05-15 16:17:30 -04:00
public void AddLatheRecipe ( EntityUid uid , string recipe , TechnologyDatabaseComponent ? component = null )
2022-12-20 17:39:57 -05:00
{
2022-12-25 16:22:23 -05:00
if ( ! Resolve ( uid , ref component ) )
return ;
2023-05-15 16:17:30 -04:00
if ( component . UnlockedRecipes . Contains ( recipe ) )
2022-12-20 17:39:57 -05:00
return ;
2023-05-15 16:17:30 -04:00
component . UnlockedRecipes . Add ( recipe ) ;
2024-03-19 23:27:02 -04:00
Dirty ( uid , component ) ;
2022-12-25 16:22:23 -05:00
var ev = new TechnologyDatabaseModifiedEvent ( ) ;
RaiseLocalEvent ( uid , ref ev ) ;
}
/// <summary>
/// Returns whether a technology can be unlocked on this database,
/// taking parent technologies into account.
/// </summary>
/// <returns>Whether it could be unlocked or not</returns>
2023-05-15 16:17:30 -04:00
public bool CanServerUnlockTechnology ( EntityUid uid ,
TechnologyPrototype technology ,
TechnologyDatabaseComponent ? database = null ,
ResearchClientComponent ? client = null )
2022-12-25 16:22:23 -05:00
{
2023-05-15 16:17:30 -04:00
if ( ! Resolve ( uid , ref client , ref database , false ) )
2022-12-25 16:22:23 -05:00
return false ;
2023-05-15 16:17:30 -04:00
if ( ! TryGetClientServer ( uid , out _ , out var serverComp , client ) )
2022-12-25 16:22:23 -05:00
return false ;
2023-05-15 16:17:30 -04:00
if ( ! IsTechnologyAvailable ( database , technology ) )
2022-12-25 16:22:23 -05:00
return false ;
2023-05-15 16:17:30 -04:00
if ( technology . Cost > serverComp . Points )
2022-12-25 16:22:23 -05:00
return false ;
return true ;
2022-06-28 22:54:08 +10:00
}
2023-05-15 16:17:30 -04:00
private void OnDatabaseRegistrationChanged ( EntityUid uid , TechnologyDatabaseComponent component , ref ResearchRegistrationChangedEvent args )
{
if ( args . Server ! = null )
return ;
component . MainDiscipline = null ;
component . CurrentTechnologyCards = new List < string > ( ) ;
component . SupportedDisciplines = new List < string > ( ) ;
component . UnlockedTechnologies = new List < string > ( ) ;
component . UnlockedRecipes = new List < string > ( ) ;
2024-03-19 23:27:02 -04:00
Dirty ( uid , component ) ;
2023-05-15 16:17:30 -04:00
}
2022-06-28 22:54:08 +10:00
}