JobPrototype.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. using Content.Shared.Access;
  2. using Content.Shared.Guidebook;
  3. using Content.Shared.Players.PlayTimeTracking;
  4. using Content.Shared.StatusIcon;
  5. using Robust.Shared.Prototypes;
  6. using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
  7. using Content.Shared._RMC14.Marines.Roles.Ranks;
  8. namespace Content.Shared.Roles
  9. {
  10. /// <summary>
  11. /// Describes information for a single job on the station.
  12. /// </summary>
  13. [Prototype]
  14. public sealed partial class JobPrototype : IPrototype
  15. {
  16. [ViewVariables]
  17. [IdDataField]
  18. public string ID { get; private set; } = default!;
  19. [DataField("playTimeTracker", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<PlayTimeTrackerPrototype>))]
  20. public string PlayTimeTracker { get; private set; } = string.Empty;
  21. /// <summary>
  22. /// Who is the supervisor for this job.
  23. /// </summary>
  24. [DataField("supervisors")]
  25. public string Supervisors { get; private set; } = "nobody";
  26. /// <summary>
  27. /// The name of this job as displayed to players.
  28. /// </summary>
  29. [DataField("name")]
  30. public string Name { get; private set; } = string.Empty;
  31. [ViewVariables(VVAccess.ReadOnly)]
  32. public string LocalizedName => Loc.GetString(Name);
  33. /// <summary>
  34. /// The "original" name of the role, untranslated.
  35. /// This would be, for example, a medic for the french faction being called Médecin
  36. /// </summary>
  37. [DataField("originalName")]
  38. public string OriginalName { get; private set; } = string.Empty;
  39. /// <summary>
  40. /// The faction this job belongs to. Used to look for spawnpoints.
  41. /// </summary>
  42. [DataField("faction")]
  43. public string Faction { get; private set; } = string.Empty;
  44. /// <summary>
  45. /// The name of this job as displayed to players.
  46. /// </summary>
  47. [DataField("description")]
  48. public string? Description { get; private set; }
  49. [ViewVariables(VVAccess.ReadOnly)]
  50. public string? LocalizedDescription => Description is null ? null : Loc.GetString(Description);
  51. /// <summary>
  52. /// Requirements for the job.
  53. /// </summary>
  54. [DataField, Access(typeof(SharedRoleSystem), Other = AccessPermissions.None)]
  55. public HashSet<JobRequirement>? Requirements;
  56. /// <summary>
  57. /// When true - the station will have anouncement about arrival of this player.
  58. /// </summary>
  59. [DataField("joinNotifyCrew")]
  60. public bool JoinNotifyCrew { get; private set; } = false;
  61. /// <summary>
  62. /// When true - the player will recieve a message about importancy of their job.
  63. /// </summary>
  64. [DataField("requireAdminNotify")]
  65. public bool RequireAdminNotify { get; private set; } = false;
  66. /// <summary>
  67. /// Should this job appear in preferences menu?
  68. /// </summary>
  69. [DataField("setPreference")]
  70. public bool SetPreference { get; private set; } = true;
  71. /// <summary>
  72. /// Should the selected traits be applied for this job?
  73. /// </summary>
  74. [DataField]
  75. public bool ApplyTraits { get; private set; } = true;
  76. /// <summary>
  77. /// Whether this job should show in the ID Card Console.
  78. /// If set to null, it will default to SetPreference's value.
  79. /// </summary>
  80. [DataField]
  81. public bool? OverrideConsoleVisibility { get; private set; } = null;
  82. [DataField("canBeAntag")]
  83. public bool CanBeAntag { get; private set; } = true;
  84. /// <summary>
  85. /// The "weight" or importance of this job. If this number is large, the job system will assign this job
  86. /// before assigning other jobs.
  87. /// </summary>
  88. [DataField("weight")]
  89. public int Weight { get; private set; }
  90. /// <summary>
  91. /// How to sort this job relative to other jobs in the UI.
  92. /// Jobs with a higher value with sort before jobs with a lower value.
  93. /// If not set, <see cref="Weight"/> is used as a fallback.
  94. /// </summary>
  95. [DataField]
  96. public int? DisplayWeight { get; private set; }
  97. public int RealDisplayWeight => DisplayWeight ?? Weight;
  98. /// <summary>
  99. /// A numerical score for how much easier this job is for antagonists.
  100. /// For traitors, reduces starting TC by this amount. Other gamemodes can use it for whatever they find fitting.
  101. /// </summary>
  102. [DataField("antagAdvantage")]
  103. public int AntagAdvantage = 0;
  104. [DataField]
  105. public ProtoId<StartingGearPrototype>? StartingGear { get; private set; }
  106. [DataField]
  107. public List<ProtoId<StartingGearPrototype>>? RandomStartingGears { get; private set; } = new();
  108. /// <summary>
  109. /// Use this to spawn in as a non-humanoid (borg, test subject, etc.)
  110. /// Starting gear will be ignored.
  111. /// If you want to just add special attributes to a humanoid, use AddComponentSpecial instead.
  112. /// </summary>
  113. [DataField("jobEntity", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
  114. public string? JobEntity = null;
  115. /// <summary>
  116. /// Entity to use as a preview in the lobby/character editor.
  117. /// Same restrictions as <see cref="JobEntity"/> apply.
  118. /// </summary>
  119. [DataField]
  120. public EntProtoId? JobPreviewEntity = null;
  121. [DataField]
  122. public ProtoId<JobIconPrototype> Icon { get; private set; } = "JobIconUnknown";
  123. [DataField("special", serverOnly: true)]
  124. public JobSpecial[] Special { get; private set; } = Array.Empty<JobSpecial>();
  125. [DataField("access")]
  126. public IReadOnlyCollection<ProtoId<AccessLevelPrototype>> Access { get; private set; } = Array.Empty<ProtoId<AccessLevelPrototype>>();
  127. [DataField("accessGroups")]
  128. public IReadOnlyCollection<ProtoId<AccessGroupPrototype>> AccessGroups { get; private set; } = Array.Empty<ProtoId<AccessGroupPrototype>>();
  129. [DataField("extendedAccess")]
  130. public IReadOnlyCollection<ProtoId<AccessLevelPrototype>> ExtendedAccess { get; private set; } = Array.Empty<ProtoId<AccessLevelPrototype>>();
  131. [DataField("extendedAccessGroups")]
  132. public IReadOnlyCollection<ProtoId<AccessGroupPrototype>> ExtendedAccessGroups { get; private set; } = Array.Empty<ProtoId<AccessGroupPrototype>>();
  133. [DataField]
  134. public bool Whitelisted;
  135. /// <summary>
  136. /// Optional list of guides associated with this role. If the guides are opened, the first entry in this list
  137. /// will be used to select the currently selected guidebook.
  138. /// </summary>
  139. [DataField]
  140. public List<ProtoId<GuideEntryPrototype>>? Guides;
  141. //RMC Ranks
  142. [DataField]
  143. public readonly Dictionary<ProtoId<RankPrototype>, HashSet<JobRequirement>?>? Ranks;
  144. }
  145. /// <summary>
  146. /// Sorts <see cref="JobPrototype"/>s appropriately for display in the UI,
  147. /// respecting their <see cref="JobPrototype.Weight"/>.
  148. /// </summary>
  149. public sealed class JobUIComparer : IComparer<JobPrototype>
  150. {
  151. public static readonly JobUIComparer Instance = new();
  152. public int Compare(JobPrototype? x, JobPrototype? y)
  153. {
  154. if (ReferenceEquals(x, y))
  155. return 0;
  156. if (ReferenceEquals(null, y))
  157. return 1;
  158. if (ReferenceEquals(null, x))
  159. return -1;
  160. var cmp = -x.RealDisplayWeight.CompareTo(y.RealDisplayWeight);
  161. if (cmp != 0)
  162. return cmp;
  163. return string.Compare(x.ID, y.ID, StringComparison.Ordinal);
  164. }
  165. }
  166. }