diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs index 1ecde269a4..73c10becd0 100644 --- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs +++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.cs @@ -53,7 +53,7 @@ public sealed class ChatUIController : UIController [Dependency] private readonly IReplayRecordingManager _replayRecording = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly CultistWordGeneratorManager _wordGenerator = default!; - + [Dependency] private readonly IEntityManager _entities = default!; [UISystemDependency] private readonly ExamineSystem? _examine = default; [UISystemDependency] private readonly GhostSystem? _ghost = default; diff --git a/Content.Client/_White/Cult/UI/SpellSelector/SpellSelectorBUI.cs b/Content.Client/_White/Cult/UI/SpellSelector/SpellSelectorBUI.cs index dc17e9805f..80dd458392 100644 --- a/Content.Client/_White/Cult/UI/SpellSelector/SpellSelectorBUI.cs +++ b/Content.Client/_White/Cult/UI/SpellSelector/SpellSelectorBUI.cs @@ -1,8 +1,11 @@ using Content.Client._White.UserInterface.Radial; +using Content.Shared.Actions; using Content.Shared.White.Cult; using Content.Shared.White.Cult.Components; using Robust.Client.GameObjects; using Robust.Client.Utility; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; namespace Content.Client._White.Cult.UI.SpellSelector; @@ -22,9 +25,27 @@ public sealed class SpellSelectorBUI : BoundUserInterface _radialContainer = new RadialContainer(); _radialContainer.Closed += Close; + var protoMan = IoCManager.Resolve(); + foreach (var action in CultistComponent.CultistActions) { - var button = _radialContainer.AddButton(action.DisplayName, action.Icon?.Frame0()); + if (!protoMan.TryIndex(action, out var proto)) + continue; + + SpriteSpecifier? icon; + if (action.StartsWith("InstantAction") && proto.TryGetComponent(out InstantActionComponent? instantComp)) + icon = instantComp.Icon; + else + { + if (!proto.TryGetComponent(out EntityTargetActionComponent? targetComp)) + continue; + icon = targetComp.Icon; + } + + if (icon == null) + continue; + + var button = _radialContainer.AddButton(proto.Name, icon.ToString()); button.Controller.OnPressed += _ => { diff --git a/Content.Server/Objectives/Components/KillCultistTargetConditionComponent.cs b/Content.Server/Objectives/Components/KillCultistTargetConditionComponent.cs new file mode 100644 index 0000000000..3bf8e62b0e --- /dev/null +++ b/Content.Server/Objectives/Components/KillCultistTargetConditionComponent.cs @@ -0,0 +1,8 @@ +using Content.Server.Objectives.Systems; + +namespace Content.Server.Objectives.Components; + +[RegisterComponent, Access(typeof(KillCultistTargetConditionSystem))] +public sealed partial class KillCultistTargetConditionComponent : Component +{ +} diff --git a/Content.Server/Objectives/Conditions/KillCultistTarget.cs b/Content.Server/Objectives/Conditions/KillCultistTarget.cs index e7d2bb4123..0ec93fb7ae 100644 --- a/Content.Server/Objectives/Conditions/KillCultistTarget.cs +++ b/Content.Server/Objectives/Conditions/KillCultistTarget.cs @@ -1,9 +1,8 @@ -using System.Diagnostics; +/*using System.Diagnostics; using System.Linq; using Content.Server.Mind; using Content.Server.White.Cult.GameRule; using Content.Shared.Mind; -using Content.Shared.Objectives.Interfaces; using Content.Shared.Roles.Jobs; using Robust.Shared.Utility; @@ -85,4 +84,4 @@ public sealed partial class KillCultistTarget : IObjectiveCondition { return TargetMindId?.GetHashCode() ?? 0; } -} +}*/ diff --git a/Content.Server/Objectives/Systems/KillCultistTargetConditionSystem.cs b/Content.Server/Objectives/Systems/KillCultistTargetConditionSystem.cs new file mode 100644 index 0000000000..74706f33fb --- /dev/null +++ b/Content.Server/Objectives/Systems/KillCultistTargetConditionSystem.cs @@ -0,0 +1,61 @@ +using System.Diagnostics; +using System.Linq; +using Content.Server.Objectives.Components; +using Content.Server.White.Cult.GameRule; +using Content.Shared.Mind; +using Content.Shared.Objectives.Components; + +namespace Content.Server.Objectives.Systems; + +public sealed class KillCultistTargetConditionSystem : EntitySystem +{ + [Dependency] private readonly SharedMindSystem _mind = default!; + [Dependency] private readonly TargetObjectiveSystem _target = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGetProgress); + + SubscribeLocalEvent(OnPersonAssigned); + } + + private void OnGetProgress(EntityUid uid, KillCultistTargetConditionComponent comp, ref ObjectiveGetProgressEvent args) + { + if (!_target.GetTarget(uid, out var target)) + return; + + args.Progress = GetProgress(target.Value); + } + + private void OnPersonAssigned(EntityUid uid, KillCultistTargetConditionComponent component, ref ObjectiveAssignedEvent args) + { + if (!TryComp(uid, out var target)) + { + args.Cancelled = true; + return; + } + + // target already assigned + if (target.Target != null) + return; + + var cultistRule = EntityManager.EntityQuery().FirstOrDefault(); + Debug.Assert(cultistRule != null, nameof(cultistRule) + " != null"); + var cultTarget = cultistRule.CultTarget; + + if (cultTarget != null) + _target.SetTarget(uid, cultTarget.Value, target); + } + + private float GetProgress(EntityUid target) + { + // deleted or gibbed or something, counts as dead + if (!TryComp(target, out var mind) || mind.OwnedEntity == null) + return 1f; + + // dead is success + return _mind.IsCharacterDeadIc(mind) ? 1f : 0f; + } +} diff --git a/Content.Server/_White/Cult/ConstructComponent.cs b/Content.Server/_White/Cult/ConstructComponent.cs index ea7c8d6e04..b84e94915c 100644 --- a/Content.Server/_White/Cult/ConstructComponent.cs +++ b/Content.Server/_White/Cult/ConstructComponent.cs @@ -1,11 +1,8 @@ -using Content.Shared.Actions.ActionTypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Server.White.Cult; +namespace Content.Server.White.Cult; [RegisterComponent] public sealed partial class ConstructComponent : Component { - [DataField("actions", customTypeSerializer: typeof(PrototypeIdListSerializer))] + [DataField("actions")] public List Actions = new(); } diff --git a/Content.Server/_White/Cult/HolyWater/HolyWaterSystem.cs b/Content.Server/_White/Cult/HolyWater/HolyWaterSystem.cs index 1580d727bd..73ab24258f 100644 --- a/Content.Server/_White/Cult/HolyWater/HolyWaterSystem.cs +++ b/Content.Server/_White/Cult/HolyWater/HolyWaterSystem.cs @@ -1,6 +1,6 @@ using System.Linq; -using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.Stunnable; +using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Interaction; using Content.Shared.Mobs.Components; using Content.Shared.Popups; diff --git a/Content.Server/_White/Cult/Runes/Systems/CultSystem.Actions.cs b/Content.Server/_White/Cult/Runes/Systems/CultSystem.Actions.cs index e863e80ecb..7bd56c8c5f 100644 --- a/Content.Server/_White/Cult/Runes/Systems/CultSystem.Actions.cs +++ b/Content.Server/_White/Cult/Runes/Systems/CultSystem.Actions.cs @@ -1,9 +1,9 @@ using System.Linq; using Content.Server.Body.Components; -using Content.Server.Chemistry.EntitySystems; using Content.Server.Emp; using Content.Server.EUI; using Content.Server.White.Cult.UI; +using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; diff --git a/Content.Server/_White/Cult/Runes/Systems/CultSystem.ConstructsAbilities.cs b/Content.Server/_White/Cult/Runes/Systems/CultSystem.ConstructsAbilities.cs index 91585b8379..596415b28c 100644 --- a/Content.Server/_White/Cult/Runes/Systems/CultSystem.ConstructsAbilities.cs +++ b/Content.Server/_White/Cult/Runes/Systems/CultSystem.ConstructsAbilities.cs @@ -6,7 +6,6 @@ using Content.Server.Popups; using Content.Server.White.Cult.GameRule; using Content.Server.White.IncorporealSystem; using Content.Shared.Actions; -using Content.Shared.Actions.ActionTypes; using Content.Shared.Coordinates.Helpers; using Content.Shared.Interaction.Events; using Content.Shared.Maps; @@ -48,8 +47,7 @@ public partial class CultSystem { foreach (var action in component.Actions) { - var actionPrototype = _prototypeManager.Index(action); - _actionsSystem.AddAction(uid, new InstantAction(actionPrototype), uid); + _actionsSystem.AddAction(uid, action, uid); } var query = EntityQueryEnumerator(); diff --git a/Content.Server/_White/Cult/Runes/Systems/CultSystem.Rune.cs b/Content.Server/_White/Cult/Runes/Systems/CultSystem.Rune.cs index ed789eff71..1c5971fc06 100644 --- a/Content.Server/_White/Cult/Runes/Systems/CultSystem.Rune.cs +++ b/Content.Server/_White/Cult/Runes/Systems/CultSystem.Rune.cs @@ -5,14 +5,13 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Components; using Content.Server.Chat.Systems; using Content.Server.Body.Systems; -using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.DoAfter; using Content.Server.Hands.Systems; using Content.Server.Weapons.Ranged.Systems; using Content.Server.White.Cult.GameRule; using Content.Server.White.Cult.Runes.Comps; using Content.Shared.Actions; -using Content.Shared.Actions.ActionTypes; +using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Cuffs.Components; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; @@ -147,7 +146,7 @@ public sealed partial class CultSystem : EntitySystem if (_ui.TryGetUi(uid, ListViewSelectorUiKey.Key, out var bui)) { - UserInterfaceSystem.SetUiState(bui, new ListViewBUIState(component.RunePrototypes, false)); + _ui.SetUiState(bui, new ListViewBUIState(component.RunePrototypes, false)); _ui.OpenUi(bui, actorComponent.PlayerSession); } } @@ -166,8 +165,8 @@ public sealed partial class CultSystem : EntitySystem if (!TryDraw(whoCalled, runePrototype)) return; - if (component.UserInterface != null) - _ui.CloseUi(component.UserInterface, actorComponent.PlayerSession); + /*if (component.UserInterface != null) + _ui.CloseUi(component.UserInterface, actorComponent.PlayerSession);*/ } private bool TryDraw(EntityUid whoCalled, string runePrototype) @@ -192,7 +191,7 @@ public sealed partial class CultSystem : EntitySystem Rune = runePrototype }; - var argsDoAfterEvent = new DoAfterArgs(whoCalled, _timeToDraw, ev, whoCalled) + var argsDoAfterEvent = new DoAfterArgs(_entityManager, whoCalled, _timeToDraw, ev, whoCalled) { BreakOnUserMove = true, NeedHand = true @@ -280,7 +279,7 @@ public sealed partial class CultSystem : EntitySystem TargetEntityId = target }; - var argsDoAfterEvent = new DoAfterArgs(user, time, ev, target) + var argsDoAfterEvent = new DoAfterArgs(_entityManager, user, time, ev, target) { BreakOnUserMove = true, NeedHand = true @@ -632,7 +631,7 @@ public sealed partial class CultSystem : EntitySystem providerComponent.Targets = victims; providerComponent.BaseRune = rune; - UserInterfaceSystem.SetUiState(ui, new TeleportRunesListWindowBUIState(list, labels)); + _ui.SetUiState(ui, new TeleportRunesListWindowBUIState(list, labels)); if (_ui.IsUiOpen(user, ui.UiKey)) return false; @@ -724,7 +723,7 @@ public sealed partial class CultSystem : EntitySystem var ev = new SummonNarsieDoAfterEvent(); - var argsDoAfterEvent = new DoAfterArgs(user, TimeSpan.FromSeconds(40), ev, user) + var argsDoAfterEvent = new DoAfterArgs(_entityManager, user, TimeSpan.FromSeconds(40), ev, user) { BreakOnUserMove = true }; @@ -920,7 +919,7 @@ public sealed partial class CultSystem : EntitySystem _entityManager.EnsureComponent(user, out var providerComponent); providerComponent.BaseRune = rune; - UserInterfaceSystem.SetUiState(ui, new SummonCultistListWindowBUIState(list, labels)); + _ui.SetUiState(ui, new SummonCultistListWindowBUIState(list, labels)); if (_ui.IsUiOpen(user, ui.UiKey)) return false; @@ -1115,17 +1114,25 @@ public sealed partial class CultSystem : EntitySystem { var playerEntity = args.Session.AttachedEntity; - if (!playerEntity.HasValue || !TryComp(playerEntity, out _) || + if (!playerEntity.HasValue || !TryComp(playerEntity, out var comp) || !TryComp(playerEntity, out var actionsComponent)) return; - var cultistsActions = actionsComponent.Actions.Intersect(CultistComponent.CultistActions).Count(); + var cultistsActions = 0; + + foreach (var userAction in actionsComponent.Actions) + { + var entityPrototypeId = MetaData(userAction).EntityPrototype?.ID; + if (entityPrototypeId != null && CultistComponent.CultistActions.Contains(entityPrototypeId)) + cultistsActions++; + } var action = CultistComponent.CultistActions.FirstOrDefault(x => x.Equals(args.ActionType)); if (action == null) return; + EntityUid? actionId = null; if (component.IsRune) { if (cultistsActions > component.MaxAllowedCultistActions) @@ -1134,11 +1141,11 @@ public sealed partial class CultSystem : EntitySystem return; } - _actionsSystem.AddAction(playerEntity.Value, (ActionType) action.Clone(), null!); + _actionsSystem.AddAction(playerEntity.Value, ref actionId, action); } else if (cultistsActions < component.MinRequiredCultistActions) { - _actionsSystem.AddAction(playerEntity.Value, (ActionType) action.Clone(), null!); + _actionsSystem.AddAction(playerEntity.Value, ref actionId, action); } } diff --git a/Content.Server/_White/IncorporealSystem/IncorporealSystem.cs b/Content.Server/_White/IncorporealSystem/IncorporealSystem.cs index 02c8ccebd2..938a66829b 100644 --- a/Content.Server/_White/IncorporealSystem/IncorporealSystem.cs +++ b/Content.Server/_White/IncorporealSystem/IncorporealSystem.cs @@ -1,5 +1,5 @@ using System.Linq; -using Content.Server.Visible; +using Content.Shared.Eye; using Content.Shared.Movement.Systems; using Content.Shared.Physics; using Robust.Server.GameObjects; diff --git a/Content.Shared/_White/Cult/Components/CultEmpowerComponent.cs b/Content.Shared/_White/Cult/Components/CultEmpowerComponent.cs index ed2b7dc319..94e95a4ba3 100644 --- a/Content.Shared/_White/Cult/Components/CultEmpowerComponent.cs +++ b/Content.Shared/_White/Cult/Components/CultEmpowerComponent.cs @@ -1,8 +1,5 @@ -using System.Diagnostics.CodeAnalysis; -using Content.Shared.Actions.ActionTypes; -using Robust.Shared.GameStates; +using Robust.Shared.GameStates; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Shared.White.Cult.Components; @@ -19,9 +16,9 @@ public sealed partial class CultEmpowerComponent : Component [Serializable, NetSerializable] public sealed class CultEmpowerSelectedBuiMessage : BoundUserInterfaceMessage { - public ActionType ActionType; + public string ActionType; - public CultEmpowerSelectedBuiMessage(ActionType actionType) + public CultEmpowerSelectedBuiMessage(string actionType) { ActionType = actionType; } diff --git a/Content.Shared/_White/Cult/Components/CultistComponent.cs b/Content.Shared/_White/Cult/Components/CultistComponent.cs index 5cb65252da..45c9a946fd 100644 --- a/Content.Shared/_White/Cult/Components/CultistComponent.cs +++ b/Content.Shared/_White/Cult/Components/CultistComponent.cs @@ -1,5 +1,4 @@ using System.Threading; -using Content.Shared.Actions.ActionTypes; using Content.Shared.White.Cult.Actions; using Content.Shared.Whitelist; using Robust.Shared.Audio; @@ -23,74 +22,19 @@ public sealed partial class CultistComponent : Component public CancellationTokenSource? HolyConvertToken; [NonSerialized] - public List SelectedEmpowers = new(); + public List SelectedEmpowers = new(); - public static InstantAction SummonCultDaggerAction = new() - { - UseDelay = TimeSpan.FromSeconds(200), - DisplayName = "Summon cult dagger.", - Description = "Summons a ritual dagger.", - Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/White/Cult/interface.rsi"), "icon"), - Event = new CultSummonDaggerActionEvent() - }; + public static string SummonCultDaggerAction = "InstantActionSummonCultDagger"; - public static InstantAction BloodRitesAction = new() - { - UseDelay = TimeSpan.FromSeconds(35), - DisplayName = "Blood Rites", - Description = "Sucks blood and heals you", - Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/White/Cult/actions_cult.rsi"), "blood_rites"), - Event = new CultBloodRitesInstantActionEvent() - }; + public static string BloodRitesAction = "InstantActionBloodRites"; - public static EntityTargetAction CultTwistedConstructionAction = new() - { - UseDelay = TimeSpan.FromSeconds(50), - DisplayName = "Twisted Construction", - Description = "A sinister spell that is used to turn metal into runic metal.", - Icon = new SpriteSpecifier.Texture(new ResPath("Objects/Materials/Sheets/metal.rsi/steel.png")), - Event = new CultTwistedConstructionActionEvent() - }; + public static string CultTwistedConstructionAction = "ActionCultTwistedConstruction"; - public static EntityTargetAction CultTeleportAction = new() - { - UseDelay = TimeSpan.FromSeconds(30), - DisplayName = "Teleport", - CanTargetSelf = true, - DeselectOnMiss = true, - Repeat = false, - Description = "A useful spell that teleports cultists to a chosen destination", - Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/White/Cult/actions_cult.rsi"), "teleport"), - Event = new CultTeleportTargetActionEvent(), - Whitelist = new EntityWhitelist - { - Components = new[] - { - "HumanoidAppearance", "Cultist" - } - } - }; + public static string CultTeleportAction = "ActionCultTeleport"; - public static EntityTargetAction CultSummonCombatEquipmentAction = new() - { - UseDelay = TimeSpan.FromSeconds(300), - DisplayName = "Summon combat equipment", - CanTargetSelf = true, - DeselectOnMiss = true, - Repeat = false, - Description = "A crucial spell that enables you to summon a full set of combat gear", - Icon = new SpriteSpecifier.Rsi(new ResPath("/Textures/White/Cult/actions_cult.rsi"), "armor"), - Event = new CultSummonCombatEquipmentTargetActionEvent(), - Whitelist = new EntityWhitelist - { - Components = new[] - { - "HumanoidAppearance", "Cultist" - } - } - }; + public static string CultSummonCombatEquipmentAction = "ActionCultSummonCombatEquipment"; - public static List CultistActions = new() + public static List CultistActions = new() { SummonCultDaggerAction, BloodRitesAction, CultTwistedConstructionAction, CultTeleportAction, CultSummonCombatEquipmentAction diff --git a/Resources/Prototypes/_White/Actions/cult_actions.yml b/Resources/Prototypes/_White/Actions/cult_actions.yml index e69de29bb2..94d7c6d124 100644 --- a/Resources/Prototypes/_White/Actions/cult_actions.yml +++ b/Resources/Prototypes/_White/Actions/cult_actions.yml @@ -0,0 +1,79 @@ +- type: entity + id: ActionCultTwistedConstruction + name: Twisted Construction + description: A sinister spell that is used to turn metal into runic metal. + noSpawn: true + components: + - type: EntityTargetAction + useDelay: 50 + canTargetSelf: false + icon: + sprite: /Objects/Materials/Sheets/metal.rsi + state: steel + event: !type:CultTwistedConstructionActionEvent + +- type: entity + id: ActionCultTeleport + name: Teleport + description: A useful spell that teleports cultists to a chosen destination. + noSpawn: true + components: + - type: EntityTargetAction + useDelay: 30 + whitelist: + components: + - HumanoidAppearance + - Cultist + canTargetSelf: true + deselectOnMiss: true + repeat: false + icon: + sprite: /Textures/White/Cult/actions_cult.rsi + state: teleport + event: !type:CultTeleportTargetActionEvent + +- type: entity + id: ActionCultSummonCombatEquipment + name: Summon combat equipment + description: A crucial spell that enables you to summon a full set of combat gear. + noSpawn: true + components: + - type: EntityTargetAction + useDelay: 300 + whitelist: + components: + - HumanoidAppearance + - Cultist + canTargetSelf: true + deselectOnMiss: true + repeat: false + icon: + sprite: /Textures/White/Cult/actions_cult.rsi + state: armor + event: !type:CultSummonCombatEquipmentTargetActionEvent + +- type: entity + id: InstantActionSummonCultDagger + name: Summon cult dagger + description: Summons a ritual dagger. + noSpawn: true + components: + - type: InstantAction + icon: + sprite: /Textures/White/Cult/interface.rsi + state: icon + event: !type:CultSummonDaggerActionEvent + useDelay: 200 + +- type: entity + id: InstantActionBloodRites + name: Blood Rites + description: Sucks blood and heals you. + noSpawn: true + components: + - type: InstantAction + icon: + sprite: /Textures/White/Cult/actions_cult.rsi + state: blood_rites + event: !type:CultBloodRitesInstantActionEvent + useDelay: 35