2024-10-10 10:48:56 +02:00
using System.Diagnostics.CodeAnalysis ;
Refactor antag rule code (#23445)
* Initial Pass, Rev, Thief
* Zombie initial pass
* Rebase, Traitor
* Nukeops, More overloads
* Revert RevolutionaryRuleComponent
* Use TryRoundStartAttempt, Rewrite nukie spawning
* Comments, Add task scheduler to GameRuleSystem
* Zombie initial testing done
* Sort methods, rework GameRuleTask
* Add CCVar, Initial testing continues
* Might as well get rid of the obsolete logging
* Oops, i dont know how to log apparently
* Suggested formatting fixes
* Suggested changes
* Fix merge issues
* Minor optimisation
* Allowed thief to choose other antags
* Review changes
* Spawn items on floor first, then inserting
* minor tweaks
* Shift as much as possible to ProtoId<>
* Remove unneeded
* Add exclusive antag attribute
* Fix merge issues
* Minor formatting fix
* Convert to struct
* Cleanup
* Review cleanup (need to test a lot)
* Some fixes, (mostly) tested
* oop
* Pass tests (for real)
---------
Co-authored-by: Rainfall <rainfey0+git@gmail.com>
Co-authored-by: AJCM <AJCM@tutanota.com>
2024-02-29 06:25:10 +00:00
using Content.Shared.Administration.Logs ;
2024-06-08 04:43:02 +12:00
using Content.Shared.CCVar ;
2023-08-30 21:46:11 -07:00
using Content.Shared.Database ;
2024-10-10 10:48:56 +02:00
using Content.Shared.GameTicking ;
2023-08-30 21:46:11 -07:00
using Content.Shared.Mind ;
using Content.Shared.Roles.Jobs ;
2023-11-14 12:52:40 +00:00
using Robust.Shared.Audio ;
2023-11-27 22:12:34 +11:00
using Robust.Shared.Audio.Systems ;
2024-06-08 04:43:02 +12:00
using Robust.Shared.Configuration ;
2024-10-10 10:48:56 +02:00
using Robust.Shared.Map ;
2023-08-30 21:46:11 -07:00
using Robust.Shared.Prototypes ;
2024-10-14 16:05:25 +13:00
using Robust.Shared.Utility ;
2023-08-30 21:46:11 -07:00
namespace Content.Shared.Roles ;
public abstract class SharedRoleSystem : EntitySystem
{
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default ! ;
2023-11-14 12:52:40 +00:00
[Dependency] private readonly SharedAudioSystem _audio = default ! ;
2024-06-08 04:43:02 +12:00
[Dependency] private readonly IConfigurationManager _cfg = default ! ;
2024-10-10 10:48:56 +02:00
[Dependency] private readonly IEntityManager _entityManager = default ! ;
[Dependency] private readonly SharedGameTicker _gameTicker = default ! ;
[Dependency] private readonly IPrototypeManager _prototypes = default ! ;
2023-08-30 21:46:11 -07:00
2024-06-08 04:43:02 +12:00
private JobRequirementOverridePrototype ? _requirementOverride ;
2023-08-30 21:46:11 -07:00
public override void Initialize ( )
{
2024-06-08 04:43:02 +12:00
Subs . CVar ( _cfg , CCVars . GameRoleTimerOverride , SetRequirementOverride , true ) ;
}
private void SetRequirementOverride ( string value )
{
if ( string . IsNullOrEmpty ( value ) )
{
_requirementOverride = null ;
return ;
}
if ( ! _prototypes . TryIndex ( value , out _requirementOverride ) )
Log . Error ( $"Unknown JobRequirementOverridePrototype: {value}" ) ;
2023-08-30 21:46:11 -07:00
}
2024-10-10 10:48:56 +02:00
/// <summary>
/// Adds multiple mind roles to a mind
/// </summary>
/// <param name="mindId">The mind entity to add the role to</param>
/// <param name="roles">The list of mind roles to add</param>
/// <param name="mind">If the mind component is provided, it will be checked if it belongs to the mind entity</param>
/// <param name="silent">If true, no briefing will be generated upon receiving the mind role</param>
public void MindAddRoles ( EntityUid mindId ,
List < ProtoId < EntityPrototype > > ? roles ,
MindComponent ? mind = null ,
bool silent = false )
2023-08-30 21:46:11 -07:00
{
2024-10-10 10:48:56 +02:00
if ( roles is null | | roles . Count = = 0 )
return ;
foreach ( var proto in roles )
2023-08-30 21:46:11 -07:00
{
2024-10-10 10:48:56 +02:00
MindAddRole ( mindId , proto , mind , silent ) ;
2023-08-30 21:46:11 -07:00
}
2024-10-10 10:48:56 +02:00
}
2023-08-30 21:46:11 -07:00
2024-10-10 10:48:56 +02:00
/// <summary>
/// Adds a mind role to a mind
/// </summary>
/// <param name="mindId">The mind entity to add the role to</param>
/// <param name="protoId">The mind role to add</param>
/// <param name="mind">If the mind component is provided, it will be checked if it belongs to the mind entity</param>
/// <param name="silent">If true, no briefing will be generated upon receiving the mind role</param>
public void MindAddRole ( EntityUid mindId ,
ProtoId < EntityPrototype > protoId ,
MindComponent ? mind = null ,
bool silent = false )
{
if ( protoId = = "MindRoleJob" )
MindAddJobRole ( mindId , mind , silent , "" ) ;
else
MindAddRoleDo ( mindId , protoId , mind , silent ) ;
2023-08-30 21:46:11 -07:00
}
2024-10-10 10:48:56 +02:00
/// <summary>
/// Adds a Job mind role with the specified job prototype
/// </summary>
/// /// <param name="mindId">The mind entity to add the job role to</param>
/// <param name="mind">If the mind component is provided, it will be checked if it belongs to the mind entity</param>
/// <param name="silent">If true, no briefing will be generated upon receiving the mind role</param>
/// <param name="jobPrototype">The Job prototype for the new role</param>
public void MindAddJobRole ( EntityUid mindId ,
MindComponent ? mind = null ,
bool silent = false ,
string? jobPrototype = null )
2023-08-30 21:46:11 -07:00
{
2024-10-14 16:05:25 +13:00
if ( ! Resolve ( mindId , ref mind ) )
return ;
2024-10-10 10:48:56 +02:00
// Can't have someone get paid for two jobs now, can we
2024-10-14 16:05:25 +13:00
if ( MindHasRole < JobRoleComponent > ( ( mindId , mind ) , out var jobRole )
& & jobRole . Value . Comp1 . JobPrototype ! = jobPrototype )
2023-08-30 21:46:11 -07:00
{
2024-10-14 16:05:25 +13:00
_adminLogger . Add ( LogType . Mind ,
LogImpact . Low ,
$"Job Role of {ToPrettyString(mind.OwnedEntity)} changed from '{jobRole.Value.Comp1.JobPrototype}' to '{jobPrototype}'" ) ;
2023-08-30 21:46:11 -07:00
2024-10-14 16:05:25 +13:00
jobRole . Value . Comp1 . JobPrototype = jobPrototype ;
2024-10-10 10:48:56 +02:00
}
else
MindAddRoleDo ( mindId , "MindRoleJob" , mind , silent , jobPrototype ) ;
2023-08-30 21:46:11 -07:00
}
2024-10-10 10:48:56 +02:00
/// <summary>
/// Creates a Mind Role
/// </summary>
private void MindAddRoleDo ( EntityUid mindId ,
ProtoId < EntityPrototype > protoId ,
MindComponent ? mind = null ,
bool silent = false ,
string? jobPrototype = null )
2024-04-25 20:25:57 -04:00
{
if ( ! Resolve ( mindId , ref mind ) )
2024-10-10 10:48:56 +02:00
{
Log . Error ( $"Failed to add role {protoId} to mind {mindId} : Mind does not match provided mind component" ) ;
2024-04-25 20:25:57 -04:00
return ;
2024-10-10 10:48:56 +02:00
}
2024-04-25 20:25:57 -04:00
var antagonist = false ;
2024-10-10 10:48:56 +02:00
if ( ! _prototypes . TryIndex ( protoId , out var protoEnt ) )
2024-04-25 20:25:57 -04:00
{
2024-10-10 10:48:56 +02:00
Log . Error ( $"Failed to add role {protoId} to mind {mindId} : Role prototype does not exist" ) ;
return ;
}
2024-04-25 20:25:57 -04:00
2024-10-10 10:48:56 +02:00
//TODO don't let a prototype being added a second time
//If that was somehow to occur, a second mindrole for that comp would be created
//Meaning any mind role checks could return wrong results, since they just return the first match they find
var mindRoleId = Spawn ( protoId , MapCoordinates . Nullspace ) ;
EnsureComp < MindRoleComponent > ( mindRoleId ) ;
var mindRoleComp = Comp < MindRoleComponent > ( mindRoleId ) ;
mindRoleComp . Mind = ( mindId , mind ) ;
if ( jobPrototype is not null )
{
mindRoleComp . JobPrototype = jobPrototype ;
EnsureComp < JobRoleComponent > ( mindRoleId ) ;
2024-10-14 16:05:25 +13:00
DebugTools . AssertNull ( mindRoleComp . AntagPrototype ) ;
DebugTools . Assert ( ! mindRoleComp . Antag ) ;
DebugTools . Assert ( ! mindRoleComp . ExclusiveAntag ) ;
2024-04-25 20:25:57 -04:00
}
2024-10-14 16:05:25 +13:00
antagonist | = mindRoleComp . Antag ;
2024-10-10 10:48:56 +02:00
mind . MindRoles . Add ( mindRoleId ) ;
2024-04-25 20:25:57 -04:00
var mindEv = new MindRoleAddedEvent ( silent ) ;
RaiseLocalEvent ( mindId , ref mindEv ) ;
var message = new RoleAddedEvent ( mindId , mind , antagonist , silent ) ;
if ( mind . OwnedEntity ! = null )
{
RaiseLocalEvent ( mind . OwnedEntity . Value , message , true ) ;
}
2024-10-10 10:48:56 +02:00
var name = Loc . GetString ( protoEnt . Name ) ;
if ( mind . OwnedEntity is not null )
{
_adminLogger . Add ( LogType . Mind ,
LogImpact . Low ,
$"{name} added to mind of {ToPrettyString(mind.OwnedEntity)}" ) ;
}
else
{
//TODO: This is not tied to the player on the Admin Log filters.
//Probably only happens when Job Role is added on initial spawn, before the mind entity is put in a mob
_adminLogger . Add ( LogType . Mind ,
LogImpact . Low ,
$"{name} added to {ToPrettyString(mindId)}" ) ;
}
2024-04-25 20:25:57 -04:00
}
2024-10-10 10:48:56 +02:00
/// <summary>
/// Removes all instances of a specific role from this mind.
/// </summary>
2024-10-14 16:05:25 +13:00
/// <param name="mind">The mind to remove the role from.</param>
2024-10-10 10:48:56 +02:00
/// <typeparam name="T">The type of the role to remove.</typeparam>
2024-10-14 16:05:25 +13:00
/// <returns>Returns false if the role did not exist. True if successful</returns>>
public bool MindRemoveRole < T > ( Entity < MindComponent ? > mind ) where T : IComponent
2024-04-24 21:31:45 -04:00
{
2024-10-14 16:05:25 +13:00
if ( typeof ( T ) = = typeof ( MindRoleComponent ) )
throw new InvalidOperationException ( ) ;
if ( ! Resolve ( mind . Owner , ref mind . Comp ) )
return false ;
2024-04-24 21:31:45 -04:00
2024-10-10 10:48:56 +02:00
var found = false ;
var antagonist = false ;
var delete = new List < EntityUid > ( ) ;
2024-10-14 16:05:25 +13:00
foreach ( var role in mind . Comp . MindRoles )
2024-04-24 21:31:45 -04:00
{
2024-10-10 10:48:56 +02:00
if ( ! HasComp < T > ( role ) )
continue ;
2024-10-14 16:05:25 +13:00
if ( ! TryComp ( role , out MindRoleComponent ? roleComp ) )
{
Log . Error ( $"Encountered mind role entity {ToPrettyString(role)} without a {nameof(MindRoleComponent)}" ) ;
continue ;
}
2024-10-10 10:48:56 +02:00
2024-10-14 16:05:25 +13:00
antagonist | = roleComp . Antag | roleComp . ExclusiveAntag ;
_entityManager . DeleteEntity ( role ) ;
2024-10-10 10:48:56 +02:00
delete . Add ( role ) ;
found = true ;
2024-04-24 21:31:45 -04:00
}
2024-10-14 16:05:25 +13:00
if ( ! found )
return false ;
2024-10-10 10:48:56 +02:00
foreach ( var role in delete )
{
2024-10-14 16:05:25 +13:00
mind . Comp . MindRoles . Remove ( role ) ;
2024-10-10 10:48:56 +02:00
}
2024-04-24 21:31:45 -04:00
2024-10-14 16:05:25 +13:00
if ( mind . Comp . OwnedEntity ! = null )
2024-10-10 10:48:56 +02:00
{
2024-10-14 16:05:25 +13:00
var message = new RoleRemovedEvent ( mind . Owner , mind . Comp , antagonist ) ;
RaiseLocalEvent ( mind . Comp . OwnedEntity . Value , message , true ) ;
2024-10-10 10:48:56 +02:00
}
_adminLogger . Add ( LogType . Mind ,
LogImpact . Low ,
2024-10-14 16:05:25 +13:00
$"All roles of type '{typeof(T).Name}' removed from mind of {ToPrettyString(mind.Comp.OwnedEntity)}" ) ;
2024-10-10 10:48:56 +02:00
return true ;
2024-04-24 21:31:45 -04:00
}
2023-08-30 21:46:11 -07:00
/// <summary>
2024-10-10 10:48:56 +02:00
/// Finds and removes all mind roles of a specific type
2023-08-30 21:46:11 -07:00
/// </summary>
2024-10-10 10:48:56 +02:00
/// <param name="mindId">The mind entity</param>
/// <typeparam name="T">The type of the role to remove.</typeparam>
/// <returns>True if the role existed and was removed</returns>
public bool MindTryRemoveRole < T > ( EntityUid mindId ) where T : IComponent
2023-08-30 21:46:11 -07:00
{
2024-10-10 10:48:56 +02:00
if ( typeof ( T ) = = typeof ( MindRoleComponent ) )
return false ;
2023-08-30 21:46:11 -07:00
2024-10-14 16:05:25 +13:00
if ( MindRemoveRole < T > ( mindId ) )
return true ;
Log . Warning ( $"Failed to remove role {typeof(T)} from {ToPrettyString(mindId)} : mind does not have role " ) ;
return false ;
2024-10-10 10:48:56 +02:00
}
2023-08-30 21:46:11 -07:00
2024-10-10 10:48:56 +02:00
/// <summary>
/// Finds the first mind role of a specific T type on a mind entity.
/// Outputs entity components for the mind role's MindRoleComponent and for T
/// </summary>
/// <param name="mindId">The mind entity</param>
/// <typeparam name="T">The type of the role to find.</typeparam>
/// <param name="role">The Mind Role entity component</param>
/// <param name="roleT">The Mind Role's entity component for T</param>
/// <returns>True if the role is found</returns>
2024-10-14 16:05:25 +13:00
public bool MindHasRole < T > ( Entity < MindComponent ? > mind ,
[NotNullWhen(true)] out Entity < MindRoleComponent , T > ? role ) where T : IComponent
2024-10-10 10:48:56 +02:00
{
role = null ;
2024-10-14 16:05:25 +13:00
if ( ! Resolve ( mind . Owner , ref mind . Comp ) )
2024-10-10 10:48:56 +02:00
return false ;
2024-10-14 16:05:25 +13:00
foreach ( var roleEnt in mind . Comp . MindRoles )
2023-08-30 21:46:11 -07:00
{
2024-10-14 16:05:25 +13:00
if ( ! TryComp ( roleEnt , out T ? tcomp ) )
2024-10-10 10:48:56 +02:00
continue ;
2024-10-14 16:05:25 +13:00
if ( ! TryComp ( roleEnt , out MindRoleComponent ? roleComp ) )
{
Log . Error ( $"Encountered mind role entity {ToPrettyString(roleEnt)} without a {nameof(MindRoleComponent)}" ) ;
continue ;
}
role = ( roleEnt , roleComp , tcomp ) ;
return true ;
2023-08-30 21:46:11 -07:00
}
2024-10-14 16:05:25 +13:00
return false ;
2023-08-30 21:46:11 -07:00
}
/// <summary>
2024-10-10 10:48:56 +02:00
/// Finds the first mind role of a specific type on a mind entity.
/// Outputs an entity component for the mind role's MindRoleComponent
2023-08-30 21:46:11 -07:00
/// </summary>
2024-10-10 10:48:56 +02:00
/// <param name="mindId">The mind entity</param>
/// <param name="type">The Type to look for</param>
/// <param name="role">The output role</param>
/// <returns>True if the role is found</returns>
public bool MindHasRole ( EntityUid mindId ,
Type type ,
[NotNullWhen(true)] out Entity < MindRoleComponent > ? role )
2023-08-30 21:46:11 -07:00
{
2024-10-10 10:48:56 +02:00
role = null ;
// All MindRoles have this component, it would just return the first one.
// Order might not be what is expected.
// Better to report null
if ( type = = Type . GetType ( "MindRoleComponent" ) )
2023-08-30 21:46:11 -07:00
{
2024-10-10 10:48:56 +02:00
Log . Error ( $"Something attempted to query mind role 'MindRoleComponent' on mind {mindId}. This component is present on every single mind role." ) ;
return false ;
2023-08-30 21:46:11 -07:00
}
2024-10-10 10:48:56 +02:00
if ( ! TryComp < MindComponent > ( mindId , out var mind ) )
return false ;
2023-08-30 21:46:11 -07:00
2024-10-10 10:48:56 +02:00
var found = false ;
foreach ( var roleEnt in mind . MindRoles )
2023-08-30 21:46:11 -07:00
{
2024-10-10 10:48:56 +02:00
if ( ! HasComp ( roleEnt , type ) )
continue ;
2024-10-14 16:05:25 +13:00
if ( ! TryComp ( roleEnt , out MindRoleComponent ? roleComp ) )
{
Log . Error ( $"Encountered mind role entity {ToPrettyString(roleEnt)} without a {nameof(MindRoleComponent)}" ) ;
continue ;
}
role = ( roleEnt , roleComp ) ;
2024-10-10 10:48:56 +02:00
found = true ;
break ;
2023-08-30 21:46:11 -07:00
}
2024-10-10 10:48:56 +02:00
return found ;
2023-08-30 21:46:11 -07:00
}
2024-10-10 10:48:56 +02:00
/// <summary>
/// Finds the first mind role of a specific type on a mind entity.
/// </summary>
/// <param name="mindId">The mind entity</param>
/// <typeparam name="T">The type of the role to find.</typeparam>
/// <returns>True if the role is found</returns>
2023-10-17 19:42:47 -07:00
public bool MindHasRole < T > ( EntityUid mindId ) where T : IComponent
2023-08-30 21:46:11 -07:00
{
2024-10-14 16:05:25 +13:00
return MindHasRole < T > ( mindId , out _ ) ;
2023-08-30 21:46:11 -07:00
}
2024-10-10 10:48:56 +02:00
//TODO: Delete this later
/// <summary>
/// Returns the first mind role of a specific type
/// </summary>
/// <param name="mindId">The mind entity</param>
/// <returns>Entity Component of the mind role</returns>
[Obsolete("Use MindHasRole's output value")]
public Entity < MindRoleComponent > ? MindGetRole < T > ( EntityUid mindId ) where T : IComponent
2023-08-30 21:46:11 -07:00
{
2024-10-10 10:48:56 +02:00
Entity < MindRoleComponent > ? result = null ;
var mind = Comp < MindComponent > ( mindId ) ;
foreach ( var uid in mind . MindRoles )
{
if ( HasComp < T > ( uid ) & & TryComp < MindRoleComponent > ( uid , out var comp ) )
result = ( uid , comp ) ;
}
return result ;
2023-08-30 21:46:11 -07:00
}
2024-10-10 10:48:56 +02:00
/// <summary>
/// Reads all Roles of a mind Entity and returns their data as RoleInfo
/// </summary>
2024-10-14 16:05:25 +13:00
/// <param name="mind">The mind entity</param>
2024-10-10 10:48:56 +02:00
/// <returns>RoleInfo list</returns>
2024-10-14 16:05:25 +13:00
public List < RoleInfo > MindGetAllRoleInfo ( Entity < MindComponent ? > mind )
2024-10-10 10:48:56 +02:00
{
var roleInfo = new List < RoleInfo > ( ) ;
2024-10-14 16:05:25 +13:00
if ( ! Resolve ( mind . Owner , ref mind . Comp ) )
2024-10-10 10:48:56 +02:00
return roleInfo ;
2024-10-14 16:05:25 +13:00
foreach ( var role in mind . Comp . MindRoles )
2024-10-10 10:48:56 +02:00
{
var valid = false ;
var name = "game-ticker-unknown-role" ;
var prototype = "" ;
2024-10-14 16:05:25 +13:00
string? playTimeTracker = null ;
2024-10-10 10:48:56 +02:00
2024-10-14 16:05:25 +13:00
if ( ! TryComp ( role , out MindRoleComponent ? comp ) )
2024-10-10 10:48:56 +02:00
{
2024-10-14 16:05:25 +13:00
Log . Error ( $"Encountered mind role entity {ToPrettyString(role)} without a {nameof(MindRoleComponent)}" ) ;
continue ;
2024-10-10 10:48:56 +02:00
}
2024-10-14 16:05:25 +13:00
if ( comp . AntagPrototype is not null )
prototype = comp . AntagPrototype ;
2024-10-10 10:48:56 +02:00
if ( comp . JobPrototype is not null & & comp . AntagPrototype is null )
{
prototype = comp . JobPrototype ;
if ( _prototypes . TryIndex ( comp . JobPrototype , out var job ) )
{
playTimeTracker = job . PlayTimeTracker ;
name = job . Name ;
valid = true ;
}
else
{
Log . Error ( $" Mind Role Prototype '{role.Id}' contains invalid Job prototype: '{comp.JobPrototype}'" ) ;
}
}
else if ( comp . AntagPrototype is not null & & comp . JobPrototype is null )
{
prototype = comp . AntagPrototype ;
if ( _prototypes . TryIndex ( comp . AntagPrototype , out var antag ) )
{
name = antag . Name ;
valid = true ;
}
else
{
Log . Error ( $" Mind Role Prototype '{role.Id}' contains invalid Antagonist prototype: '{comp.AntagPrototype}'" ) ;
}
}
else if ( comp . JobPrototype is not null & & comp . AntagPrototype is not null )
{
Log . Error ( $" Mind Role Prototype '{role.Id}' contains both Job and Antagonist prototypes" ) ;
}
if ( valid )
2024-10-14 16:05:25 +13:00
roleInfo . Add ( new RoleInfo ( name , comp . Antag , playTimeTracker , prototype ) ) ;
2024-10-10 10:48:56 +02:00
}
return roleInfo ;
}
/// <summary>
/// Does this mind possess an antagonist role
/// </summary>
/// <param name="mindId">The mind entity</param>
/// <returns>True if the mind possesses any antag roles</returns>
2023-08-30 21:46:11 -07:00
public bool MindIsAntagonist ( EntityUid ? mindId )
{
2024-10-10 10:48:56 +02:00
if ( mindId is null )
2023-08-30 21:46:11 -07:00
return false ;
2024-10-14 16:05:25 +13:00
return CheckAntagonistStatus ( mindId . Value ) . Antag ;
2023-08-30 21:46:11 -07:00
}
Refactor antag rule code (#23445)
* Initial Pass, Rev, Thief
* Zombie initial pass
* Rebase, Traitor
* Nukeops, More overloads
* Revert RevolutionaryRuleComponent
* Use TryRoundStartAttempt, Rewrite nukie spawning
* Comments, Add task scheduler to GameRuleSystem
* Zombie initial testing done
* Sort methods, rework GameRuleTask
* Add CCVar, Initial testing continues
* Might as well get rid of the obsolete logging
* Oops, i dont know how to log apparently
* Suggested formatting fixes
* Suggested changes
* Fix merge issues
* Minor optimisation
* Allowed thief to choose other antags
* Review changes
* Spawn items on floor first, then inserting
* minor tweaks
* Shift as much as possible to ProtoId<>
* Remove unneeded
* Add exclusive antag attribute
* Fix merge issues
* Minor formatting fix
* Convert to struct
* Cleanup
* Review cleanup (need to test a lot)
* Some fixes, (mostly) tested
* oop
* Pass tests (for real)
---------
Co-authored-by: Rainfall <rainfey0+git@gmail.com>
Co-authored-by: AJCM <AJCM@tutanota.com>
2024-02-29 06:25:10 +00:00
/// <summary>
/// Does this mind possess an exclusive antagonist role
/// </summary>
/// <param name="mindId">The mind entity</param>
2024-10-10 10:48:56 +02:00
/// <returns>True if the mind possesses any exclusive antag roles</returns>
Refactor antag rule code (#23445)
* Initial Pass, Rev, Thief
* Zombie initial pass
* Rebase, Traitor
* Nukeops, More overloads
* Revert RevolutionaryRuleComponent
* Use TryRoundStartAttempt, Rewrite nukie spawning
* Comments, Add task scheduler to GameRuleSystem
* Zombie initial testing done
* Sort methods, rework GameRuleTask
* Add CCVar, Initial testing continues
* Might as well get rid of the obsolete logging
* Oops, i dont know how to log apparently
* Suggested formatting fixes
* Suggested changes
* Fix merge issues
* Minor optimisation
* Allowed thief to choose other antags
* Review changes
* Spawn items on floor first, then inserting
* minor tweaks
* Shift as much as possible to ProtoId<>
* Remove unneeded
* Add exclusive antag attribute
* Fix merge issues
* Minor formatting fix
* Convert to struct
* Cleanup
* Review cleanup (need to test a lot)
* Some fixes, (mostly) tested
* oop
* Pass tests (for real)
---------
Co-authored-by: Rainfall <rainfey0+git@gmail.com>
Co-authored-by: AJCM <AJCM@tutanota.com>
2024-02-29 06:25:10 +00:00
public bool MindIsExclusiveAntagonist ( EntityUid ? mindId )
{
2024-10-10 10:48:56 +02:00
if ( mindId is null )
Refactor antag rule code (#23445)
* Initial Pass, Rev, Thief
* Zombie initial pass
* Rebase, Traitor
* Nukeops, More overloads
* Revert RevolutionaryRuleComponent
* Use TryRoundStartAttempt, Rewrite nukie spawning
* Comments, Add task scheduler to GameRuleSystem
* Zombie initial testing done
* Sort methods, rework GameRuleTask
* Add CCVar, Initial testing continues
* Might as well get rid of the obsolete logging
* Oops, i dont know how to log apparently
* Suggested formatting fixes
* Suggested changes
* Fix merge issues
* Minor optimisation
* Allowed thief to choose other antags
* Review changes
* Spawn items on floor first, then inserting
* minor tweaks
* Shift as much as possible to ProtoId<>
* Remove unneeded
* Add exclusive antag attribute
* Fix merge issues
* Minor formatting fix
* Convert to struct
* Cleanup
* Review cleanup (need to test a lot)
* Some fixes, (mostly) tested
* oop
* Pass tests (for real)
---------
Co-authored-by: Rainfall <rainfey0+git@gmail.com>
Co-authored-by: AJCM <AJCM@tutanota.com>
2024-02-29 06:25:10 +00:00
return false ;
2024-10-14 16:05:25 +13:00
return CheckAntagonistStatus ( mindId . Value ) . ExclusiveAntag ;
Refactor antag rule code (#23445)
* Initial Pass, Rev, Thief
* Zombie initial pass
* Rebase, Traitor
* Nukeops, More overloads
* Revert RevolutionaryRuleComponent
* Use TryRoundStartAttempt, Rewrite nukie spawning
* Comments, Add task scheduler to GameRuleSystem
* Zombie initial testing done
* Sort methods, rework GameRuleTask
* Add CCVar, Initial testing continues
* Might as well get rid of the obsolete logging
* Oops, i dont know how to log apparently
* Suggested formatting fixes
* Suggested changes
* Fix merge issues
* Minor optimisation
* Allowed thief to choose other antags
* Review changes
* Spawn items on floor first, then inserting
* minor tweaks
* Shift as much as possible to ProtoId<>
* Remove unneeded
* Add exclusive antag attribute
* Fix merge issues
* Minor formatting fix
* Convert to struct
* Cleanup
* Review cleanup (need to test a lot)
* Some fixes, (mostly) tested
* oop
* Pass tests (for real)
---------
Co-authored-by: Rainfall <rainfey0+git@gmail.com>
Co-authored-by: AJCM <AJCM@tutanota.com>
2024-02-29 06:25:10 +00:00
}
2024-10-14 16:05:25 +13:00
public ( bool Antag , bool ExclusiveAntag ) CheckAntagonistStatus ( Entity < MindComponent ? > mind )
2024-10-10 10:48:56 +02:00
{
2024-10-14 16:05:25 +13:00
if ( ! Resolve ( mind . Owner , ref mind . Comp ) )
2024-10-10 10:48:56 +02:00
return ( false , false ) ;
2023-11-14 12:52:40 +00:00
2024-10-10 10:48:56 +02:00
var antagonist = false ;
var exclusiveAntag = false ;
2024-10-14 16:05:25 +13:00
foreach ( var role in mind . Comp . MindRoles )
2024-10-10 10:48:56 +02:00
{
2024-10-11 21:17:01 +02:00
if ( ! TryComp < MindRoleComponent > ( role , out var roleComp ) )
{
2024-10-14 16:05:25 +13:00
Log . Error ( $"Mind Role Entity {ToPrettyString(role)} does not have a MindRoleComponent, despite being listed as a role belonging to {ToPrettyString(mind)}|" ) ;
2024-10-11 21:17:01 +02:00
continue ;
}
2024-10-14 16:05:25 +13:00
antagonist | = roleComp . Antag ;
exclusiveAntag | = roleComp . ExclusiveAntag ;
2024-10-10 10:48:56 +02:00
}
return ( antagonist , exclusiveAntag ) ;
2024-04-24 21:31:45 -04:00
}
2023-11-14 12:52:40 +00:00
/// <summary>
/// Play a sound for the mind, if it has a session attached.
/// Use this for role greeting sounds.
/// </summary>
public void MindPlaySound ( EntityUid mindId , SoundSpecifier ? sound , MindComponent ? mind = null )
{
if ( Resolve ( mindId , ref mind ) & & mind . Session ! = null )
_audio . PlayGlobal ( sound , mind . Session ) ;
}
2024-06-08 04:43:02 +12:00
2024-10-14 16:05:25 +13:00
// TODO ROLES Change to readonly.
// Passing around a reference to a prototype's hashset makes me uncomfortable because it might be accidentally
// mutated.
2024-06-08 04:43:02 +12:00
public HashSet < JobRequirement > ? GetJobRequirement ( JobPrototype job )
{
if ( _requirementOverride ! = null & & _requirementOverride . Jobs . TryGetValue ( job . ID , out var req ) )
return req ;
return job . Requirements ;
}
2024-10-14 16:05:25 +13:00
// TODO ROLES Change to readonly.
2024-06-08 04:43:02 +12:00
public HashSet < JobRequirement > ? GetJobRequirement ( ProtoId < JobPrototype > job )
{
if ( _requirementOverride ! = null & & _requirementOverride . Jobs . TryGetValue ( job , out var req ) )
return req ;
return _prototypes . Index ( job ) . Requirements ;
}
2024-10-14 16:05:25 +13:00
// TODO ROLES Change to readonly.
2024-06-08 04:43:02 +12:00
public HashSet < JobRequirement > ? GetAntagRequirement ( ProtoId < AntagPrototype > antag )
{
if ( _requirementOverride ! = null & & _requirementOverride . Antags . TryGetValue ( antag , out var req ) )
return req ;
return _prototypes . Index ( antag ) . Requirements ;
}
2024-10-14 16:05:25 +13:00
// TODO ROLES Change to readonly.
2024-06-08 04:43:02 +12:00
public HashSet < JobRequirement > ? GetAntagRequirement ( AntagPrototype antag )
{
if ( _requirementOverride ! = null & & _requirementOverride . Antags . TryGetValue ( antag . ID , out var req ) )
return req ;
return antag . Requirements ;
}
2023-08-30 21:46:11 -07:00
}