make paradox clone receive the original's objectives (#35829)
* make paradox clone receive the original's objectives * remove redundant indexing * Minor comment change * fix ninja objectives --------- Co-authored-by: beck-thompson <beck314159@hotmail.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.Cloning;
|
using Content.Shared.Cloning;
|
||||||
|
using Content.Shared.Whitelist;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Rules.Components;
|
namespace Content.Server.GameTicking.Rules.Components;
|
||||||
@@ -20,4 +21,23 @@ public sealed partial class ParadoxCloneRuleComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public EntProtoId GibProto = "MobParadoxTimed";
|
public EntProtoId GibProto = "MobParadoxTimed";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mind entity of the original player.
|
||||||
|
/// Gets assigned when cloning.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public EntityUid? Original;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whitelist for Objectives to be copied to the clone.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public EntityWhitelist? ObjectiveWhitelist;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Blacklist for Objectives to be copied to the clone.
|
||||||
|
/// </summary>
|
||||||
|
[DataField]
|
||||||
|
public EntityWhitelist? ObjectiveBlacklist;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ namespace Content.Server.GameTicking.Rules;
|
|||||||
public sealed class ParadoxCloneRuleSystem : GameRuleSystem<ParadoxCloneRuleComponent>
|
public sealed class ParadoxCloneRuleSystem : GameRuleSystem<ParadoxCloneRuleComponent>
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
|
||||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly CloningSystem _cloning = default!;
|
[Dependency] private readonly CloningSystem _cloning = default!;
|
||||||
@@ -23,6 +22,7 @@ public sealed class ParadoxCloneRuleSystem : GameRuleSystem<ParadoxCloneRuleComp
|
|||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
SubscribeLocalEvent<ParadoxCloneRuleComponent, AntagSelectEntityEvent>(OnAntagSelectEntity);
|
SubscribeLocalEvent<ParadoxCloneRuleComponent, AntagSelectEntityEvent>(OnAntagSelectEntity);
|
||||||
|
SubscribeLocalEvent<ParadoxCloneRuleComponent, AfterAntagEntitySelectedEvent>(AfterAntagEntitySelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Started(EntityUid uid, ParadoxCloneRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
|
protected override void Started(EntityUid uid, ParadoxCloneRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
|
||||||
@@ -45,12 +45,6 @@ public sealed class ParadoxCloneRuleSystem : GameRuleSystem<ParadoxCloneRuleComp
|
|||||||
if (args.Session?.AttachedEntity is not { } spawner)
|
if (args.Session?.AttachedEntity is not { } spawner)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_prototypeManager.TryIndex(ent.Comp.Settings, out var settings))
|
|
||||||
{
|
|
||||||
Log.Error($"Used invalid cloning settings {ent.Comp.Settings} for ParadoxCloneRule");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get possible targets
|
// get possible targets
|
||||||
var allHumans = _mind.GetAliveHumans();
|
var allHumans = _mind.GetAliveHumans();
|
||||||
|
|
||||||
@@ -65,7 +59,7 @@ public sealed class ParadoxCloneRuleSystem : GameRuleSystem<ParadoxCloneRuleComp
|
|||||||
var playerToClone = _random.Pick(allHumans);
|
var playerToClone = _random.Pick(allHumans);
|
||||||
var bodyToClone = playerToClone.Comp.OwnedEntity;
|
var bodyToClone = playerToClone.Comp.OwnedEntity;
|
||||||
|
|
||||||
if (bodyToClone == null || !_cloning.TryCloning(bodyToClone.Value, _transform.GetMapCoordinates(spawner), settings, out var clone))
|
if (bodyToClone == null || !_cloning.TryCloning(bodyToClone.Value, _transform.GetMapCoordinates(spawner), ent.Comp.Settings, out var clone))
|
||||||
{
|
{
|
||||||
Log.Error($"Unable to make a paradox clone of entity {ToPrettyString(bodyToClone)}");
|
Log.Error($"Unable to make a paradox clone of entity {ToPrettyString(bodyToClone)}");
|
||||||
return;
|
return;
|
||||||
@@ -79,5 +73,17 @@ public sealed class ParadoxCloneRuleSystem : GameRuleSystem<ParadoxCloneRuleComp
|
|||||||
gibComp.PreventGibbingObjectives = new() { "ParadoxCloneKillObjective" }; // don't gib them if they killed the original.
|
gibComp.PreventGibbingObjectives = new() { "ParadoxCloneKillObjective" }; // don't gib them if they killed the original.
|
||||||
|
|
||||||
args.Entity = clone;
|
args.Entity = clone;
|
||||||
|
ent.Comp.Original = playerToClone.Owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AfterAntagEntitySelected(Entity<ParadoxCloneRuleComponent> ent, ref AfterAntagEntitySelectedEvent args)
|
||||||
|
{
|
||||||
|
if (ent.Comp.Original == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_mind.TryGetMind(args.EntityUid, out var cloneMindId, out var cloneMindComp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_mind.CopyObjectives(ent.Comp.Original.Value, (cloneMindId, cloneMindComp), ent.Comp.ObjectiveWhitelist, ent.Comp.ObjectiveBlacklist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using Content.Shared.Mobs.Components;
|
|||||||
using Content.Shared.Mobs.Systems;
|
using Content.Shared.Mobs.Systems;
|
||||||
using Content.Shared.Objectives.Systems;
|
using Content.Shared.Objectives.Systems;
|
||||||
using Content.Shared.Players;
|
using Content.Shared.Players;
|
||||||
|
using Content.Shared.Whitelist;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Network;
|
using Robust.Shared.Network;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
@@ -26,6 +27,7 @@ public abstract class SharedMindSystem : EntitySystem
|
|||||||
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
|
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
|
||||||
[Dependency] private readonly SharedPlayerSystem _player = default!;
|
[Dependency] private readonly SharedPlayerSystem _player = default!;
|
||||||
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
[Dependency] private readonly MetaDataSystem _metadata = default!;
|
||||||
|
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
protected readonly Dictionary<NetUserId, EntityUid> UserMinds = new();
|
protected readonly Dictionary<NetUserId, EntityUid> UserMinds = new();
|
||||||
@@ -364,6 +366,16 @@ public abstract class SharedMindSystem : EntitySystem
|
|||||||
var title = Name(objective);
|
var title = Name(objective);
|
||||||
_adminLogger.Add(LogType.Mind, LogImpact.Low, $"Objective {objective} ({title}) removed from the mind of {MindOwnerLoggingString(mind)}");
|
_adminLogger.Add(LogType.Mind, LogImpact.Low, $"Objective {objective} ({title}) removed from the mind of {MindOwnerLoggingString(mind)}");
|
||||||
mind.Objectives.Remove(objective);
|
mind.Objectives.Remove(objective);
|
||||||
|
|
||||||
|
// garbage collection - only delete the objective entity if no mind uses it anymore
|
||||||
|
// This comes up for stuff like paradox clones where the objectives share the same entity
|
||||||
|
var mindQuery = new AllEntityQueryEnumerator<MindComponent>();
|
||||||
|
while (mindQuery.MoveNext(out _, out var queryComp))
|
||||||
|
{
|
||||||
|
if (queryComp.Objectives.Contains(objective))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Del(objective);
|
Del(objective);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -395,6 +407,33 @@ public abstract class SharedMindSystem : EntitySystem
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies objectives from one mind to another, so that they are shared between two players.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Only copies the reference to the objective entity, not the entity itself.
|
||||||
|
/// This relies on the fact that objectives are never changed after spawning them.
|
||||||
|
/// If someone ever changes that, they will have to address this.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="source"> mind entity of the player to copy from </param>
|
||||||
|
/// <param name="target"> mind entity of the player to copy to </param>
|
||||||
|
/// <param name="except"> whitelist for objectives that should be copied </param>
|
||||||
|
/// <param name="except"> blacklist for objectives that should not be copied </param>
|
||||||
|
public void CopyObjectives(Entity<MindComponent?> source, Entity<MindComponent?> target, EntityWhitelist? whitelist = null, EntityWhitelist? blacklist = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(source, ref source.Comp) || !Resolve(target, ref target.Comp))
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var objective in source.Comp.Objectives)
|
||||||
|
{
|
||||||
|
if (target.Comp.Objectives.Contains(objective))
|
||||||
|
continue; // target already has this objective
|
||||||
|
|
||||||
|
if (_whitelist.CheckBoth(objective, blacklist, whitelist))
|
||||||
|
AddObjective(target, target.Comp, objective);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to find an objective that has the same prototype as the argument.
|
/// Tries to find an objective that has the same prototype as the argument.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
- Clumsy
|
- Clumsy
|
||||||
- MindShield
|
- MindShield
|
||||||
- MimePowers
|
- MimePowers
|
||||||
|
- SpaceNinja
|
||||||
# accents
|
# accents
|
||||||
- Accentless
|
- Accentless
|
||||||
- BackwardsAccent
|
- BackwardsAccent
|
||||||
|
|||||||
@@ -244,6 +244,9 @@
|
|||||||
reoccurrenceDelay: 20
|
reoccurrenceDelay: 20
|
||||||
minimumPlayers: 15
|
minimumPlayers: 15
|
||||||
- type: ParadoxCloneRule
|
- type: ParadoxCloneRule
|
||||||
|
objectiveBlacklist:
|
||||||
|
tags:
|
||||||
|
- ParadoxCloneObjectiveBlacklist
|
||||||
- type: AntagObjectives
|
- type: AntagObjectives
|
||||||
objectives:
|
objectives:
|
||||||
- ParadoxCloneKillObjective
|
- ParadoxCloneKillObjective
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
roles:
|
roles:
|
||||||
mindRoles:
|
mindRoles:
|
||||||
- ParadoxCloneRole
|
- ParadoxCloneRole
|
||||||
|
- type: Tag
|
||||||
|
tags:
|
||||||
|
- ParadoxCloneObjectiveBlacklist # don't copy the objectives from other clones
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: [BaseParadoxCloneObjective, BaseLivingObjective]
|
parent: [BaseParadoxCloneObjective, BaseLivingObjective]
|
||||||
|
|||||||
@@ -954,6 +954,9 @@
|
|||||||
- type: Tag
|
- type: Tag
|
||||||
id: Packet
|
id: Packet
|
||||||
|
|
||||||
|
- type: Tag
|
||||||
|
id: ParadoxCloneObjectiveBlacklist # objective entities with this tag don't get copied to paradox clones
|
||||||
|
|
||||||
- type: Tag
|
- type: Tag
|
||||||
id: Paper
|
id: Paper
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user