[Fix] move ninja objectives into NinjaRole (#15490)
Co-authored-by: deltanedas <@deltanedas:kde.org>
This commit is contained in:
43
Content.Server/Ninja/NinjaRole.cs
Normal file
43
Content.Server/Ninja/NinjaRole.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using Content.Server.Traitor;
|
||||||
|
using Content.Shared.Roles;
|
||||||
|
|
||||||
|
namespace Content.Server.Ninja;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores the ninja's objectives in the mind so if they die the rest of the greentext persists.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class NinjaRole : TraitorRole
|
||||||
|
{
|
||||||
|
public NinjaRole(Mind.Mind mind, AntagPrototype antagPrototype) : base(mind, antagPrototype) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of doors that have been doorjacked, used for objective
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public int DoorsJacked = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Research nodes that have been downloaded, used for objective
|
||||||
|
/// </summary>
|
||||||
|
// TODO: client doesn't need to know what nodes are downloaded, just how many
|
||||||
|
[ViewVariables]
|
||||||
|
public HashSet<string> DownloadedNodes = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Warp point that the spider charge has to target
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public EntityUid? SpiderChargeTarget = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the spider charge has been detonated on the target, used for objective
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public bool SpiderChargeDetonated;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the comms console has been hacked, used for objective
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables]
|
||||||
|
public bool CalledInThreat;
|
||||||
|
}
|
||||||
@@ -1,15 +1,20 @@
|
|||||||
using Content.Server.Communications;
|
using Content.Server.Communications;
|
||||||
using Content.Server.DoAfter;
|
using Content.Server.DoAfter;
|
||||||
|
using Content.Server.Ninja.Systems;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Ninja.Components;
|
using Content.Shared.Ninja.Components;
|
||||||
using Content.Shared.Ninja.Systems;
|
using Content.Shared.Ninja.Systems;
|
||||||
|
using Content.Shared.Popups;
|
||||||
|
using Content.Shared.Research.Components;
|
||||||
|
|
||||||
namespace Content.Server.Ninja.Systems;
|
namespace Content.Server.Ninja.Systems;
|
||||||
|
|
||||||
public sealed class NinjaGlovesSystem : SharedNinjaGlovesSystem
|
public sealed class NinjaGlovesSystem : SharedNinjaGlovesSystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly new NinjaSystem _ninja = default!;
|
||||||
|
|
||||||
protected override void OnDrain(EntityUid uid, NinjaDrainComponent comp, InteractionAttemptEvent args)
|
protected override void OnDrain(EntityUid uid, NinjaDrainComponent comp, InteractionAttemptEvent args)
|
||||||
{
|
{
|
||||||
if (!GloveCheck(uid, args, out var gloves, out var user, out var target)
|
if (!GloveCheck(uid, args, out var gloves, out var user, out var target)
|
||||||
@@ -29,8 +34,59 @@ public sealed class NinjaGlovesSystem : SharedNinjaGlovesSystem
|
|||||||
_doAfter.TryStartDoAfter(doAfterArgs);
|
_doAfter.TryStartDoAfter(doAfterArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool IsCommsConsole(EntityUid uid)
|
protected override void OnDownloadDoAfter(EntityUid uid, NinjaDownloadComponent comp, DownloadDoAfterEvent args)
|
||||||
{
|
{
|
||||||
return HasComp<CommunicationsConsoleComponent>(uid);
|
if (args.Cancelled || args.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var user = args.User;
|
||||||
|
var target = args.Target;
|
||||||
|
|
||||||
|
if (!TryComp<NinjaComponent>(user, out var ninja)
|
||||||
|
|| !TryComp<TechnologyDatabaseComponent>(target, out var database))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var gained = _ninja.Download(uid, database.TechnologyIds);
|
||||||
|
var str = gained == 0
|
||||||
|
? Loc.GetString("ninja-download-fail")
|
||||||
|
: Loc.GetString("ninja-download-success", ("count", gained), ("server", target));
|
||||||
|
|
||||||
|
Popups.PopupEntity(str, user, user, PopupType.Medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnTerror(EntityUid uid, NinjaTerrorComponent comp, InteractionAttemptEvent args)
|
||||||
|
{
|
||||||
|
if (!GloveCheck(uid, args, out var gloves, out var user, out var target)
|
||||||
|
|| !_ninja.GetNinjaRole(user, out var role)
|
||||||
|
|| !HasComp<CommunicationsConsoleComponent>(target))
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
// can only do it once
|
||||||
|
if (role.CalledInThreat)
|
||||||
|
{
|
||||||
|
Popups.PopupEntity(Loc.GetString("ninja-terror-already-called"), user, user);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var doAfterArgs = new DoAfterArgs(user, comp.TerrorTime, new TerrorDoAfterEvent(), target: target, used: uid, eventTarget: uid)
|
||||||
|
{
|
||||||
|
BreakOnDamage = true,
|
||||||
|
BreakOnUserMove = true,
|
||||||
|
MovementThreshold = 0.5f,
|
||||||
|
CancelDuplicate = false
|
||||||
|
};
|
||||||
|
|
||||||
|
_doAfter.TryStartDoAfter(doAfterArgs);
|
||||||
|
// FIXME: doesnt work, don't show the console popup
|
||||||
|
args.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnTerrorDoAfter(EntityUid uid, NinjaTerrorComponent comp, TerrorDoAfterEvent args)
|
||||||
|
{
|
||||||
|
if (args.Cancelled || args.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_ninja.CallInThreat(args.User);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ using Content.Server.GameTicking.Rules;
|
|||||||
using Content.Server.GameTicking.Rules.Configurations;
|
using Content.Server.GameTicking.Rules.Configurations;
|
||||||
using Content.Server.Ghost.Roles.Events;
|
using Content.Server.Ghost.Roles.Events;
|
||||||
using Content.Server.Mind.Components;
|
using Content.Server.Mind.Components;
|
||||||
|
using Content.Server.Ninja;
|
||||||
using Content.Server.Ninja.Components;
|
using Content.Server.Ninja.Components;
|
||||||
using Content.Server.Objectives;
|
using Content.Server.Objectives;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Server.PowerCell;
|
using Content.Server.PowerCell;
|
||||||
using Content.Server.Traitor;
|
|
||||||
using Content.Server.Warps;
|
using Content.Server.Warps;
|
||||||
using Content.Shared.Alert;
|
using Content.Shared.Alert;
|
||||||
using Content.Shared.Doors.Components;
|
using Content.Shared.Doors.Components;
|
||||||
@@ -32,6 +32,7 @@ using Robust.Shared.Player;
|
|||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Content.Server.Ninja.Systems;
|
namespace Content.Server.Ninja.Systems;
|
||||||
|
|
||||||
@@ -89,6 +90,49 @@ public sealed class NinjaSystem : SharedNinjaSystem
|
|||||||
GreetNinja(mind);
|
GreetNinja(mind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Download the given set of nodes, returning how many new nodes were downloaded.'
|
||||||
|
/// </summary>
|
||||||
|
public int Download(EntityUid uid, List<string> ids)
|
||||||
|
{
|
||||||
|
if (!GetNinjaRole(uid, out var role))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var oldCount = role.DownloadedNodes.Count;
|
||||||
|
role.DownloadedNodes.UnionWith(ids);
|
||||||
|
var newCount = role.DownloadedNodes.Count;
|
||||||
|
return newCount - oldCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a ninja's role using the player's mind
|
||||||
|
/// </summary>
|
||||||
|
public static bool GetNinjaRole(Mind.Mind? mind, [NotNullWhen(true)] out NinjaRole? role)
|
||||||
|
{
|
||||||
|
if (mind == null)
|
||||||
|
{
|
||||||
|
role = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
role = (NinjaRole?) mind.AllRoles
|
||||||
|
.Where(r => r is NinjaRole)
|
||||||
|
.FirstOrDefault();
|
||||||
|
return role != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a ninja's role using the player's entity id
|
||||||
|
/// </summary>
|
||||||
|
public bool GetNinjaRole(EntityUid uid, [NotNullWhen(true)] out NinjaRole? role)
|
||||||
|
{
|
||||||
|
role = null;
|
||||||
|
if (!TryComp<MindComponent>(uid, out var mind))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return GetNinjaRole(mind.Mind, out role);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the space ninja spawn gamerule's config
|
/// Returns the space ninja spawn gamerule's config
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -150,14 +194,17 @@ public sealed class NinjaSystem : SharedNinjaSystem
|
|||||||
return GetNinjaBattery(user, out var battery) && battery.TryUseCharge(charge);
|
return GetNinjaBattery(user, out var battery) && battery.TryUseCharge(charge);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void CallInThreat(NinjaComponent comp)
|
/// <summary>
|
||||||
|
/// Completes the objective, makes announcement and adds rule of a random threat.
|
||||||
|
/// </summary>
|
||||||
|
public void CallInThreat(EntityUid uid)
|
||||||
{
|
{
|
||||||
base.CallInThreat(comp);
|
|
||||||
|
|
||||||
var config = RuleConfig();
|
var config = RuleConfig();
|
||||||
if (config.Threats.Count == 0)
|
if (config.Threats.Count == 0 || !GetNinjaRole(uid, out var role) || role.CalledInThreat)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
role.CalledInThreat = true;
|
||||||
|
|
||||||
var threat = _random.Pick(config.Threats);
|
var threat = _random.Pick(config.Threats);
|
||||||
if (_proto.TryIndex<GameRulePrototype>(threat.Rule, out var rule))
|
if (_proto.TryIndex<GameRulePrototype>(threat.Rule, out var rule))
|
||||||
{
|
{
|
||||||
@@ -224,7 +271,38 @@ public sealed class NinjaSystem : SharedNinjaSystem
|
|||||||
|
|
||||||
_implants.ForceImplant(uid, implant, implantComp);
|
_implants.ForceImplant(uid, implant, implantComp);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnNinjaSpawned(EntityUid uid, NinjaComponent comp, GhostRoleSpawnerUsedEvent args)
|
||||||
|
{
|
||||||
|
// inherit spawner's station grid
|
||||||
|
if (TryComp<NinjaStationGridComponent>(args.Spawner, out var station))
|
||||||
|
SetNinjaStationGrid(uid, station.Grid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnNinjaMindAdded(EntityUid uid, NinjaComponent comp, MindAddedMessage args)
|
||||||
|
{
|
||||||
|
Logger.ErrorS("ninja_testing", "AMONG US 2 RELASED");
|
||||||
|
if (TryComp<MindComponent>(uid, out var mind) && mind.Mind != null)
|
||||||
|
GreetNinja(mind.Mind);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GreetNinja(Mind.Mind mind)
|
||||||
|
{
|
||||||
|
Logger.ErrorS("ninja_testing", "GREETING");
|
||||||
|
if (!mind.TryGetSession(out var session))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var config = RuleConfig();
|
||||||
|
var role = new NinjaRole(mind, _proto.Index<AntagPrototype>("SpaceNinja"));
|
||||||
|
mind.AddRole(role);
|
||||||
|
_traitorRule.Traitors.Add(role);
|
||||||
|
foreach (var objective in config.Objectives)
|
||||||
|
{
|
||||||
|
AddObjective(mind, objective);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.ErrorS("ninja_testing", "added role");
|
||||||
// choose spider charge detonation point
|
// choose spider charge detonation point
|
||||||
// currently based on warp points, something better could be done (but would likely require mapping work)
|
// currently based on warp points, something better could be done (but would likely require mapping work)
|
||||||
var warps = new List<EntityUid>();
|
var warps = new List<EntityUid>();
|
||||||
@@ -237,35 +315,7 @@ public sealed class NinjaSystem : SharedNinjaSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (warps.Count > 0)
|
if (warps.Count > 0)
|
||||||
comp.SpiderChargeTarget = _random.Pick(warps);
|
role.SpiderChargeTarget = _random.Pick(warps);
|
||||||
}
|
|
||||||
|
|
||||||
private void OnNinjaSpawned(EntityUid uid, NinjaComponent comp, GhostRoleSpawnerUsedEvent args)
|
|
||||||
{
|
|
||||||
// inherit spawner's station grid
|
|
||||||
if (TryComp<NinjaStationGridComponent>(args.Spawner, out var station))
|
|
||||||
SetNinjaStationGrid(uid, station.Grid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnNinjaMindAdded(EntityUid uid, NinjaComponent comp, MindAddedMessage args)
|
|
||||||
{
|
|
||||||
if (TryComp<MindComponent>(uid, out var mind) && mind.Mind != null)
|
|
||||||
GreetNinja(mind.Mind);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GreetNinja(Mind.Mind mind)
|
|
||||||
{
|
|
||||||
if (!mind.TryGetSession(out var session))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var config = RuleConfig();
|
|
||||||
var role = new TraitorRole(mind, _proto.Index<AntagPrototype>("SpaceNinja"));
|
|
||||||
mind.AddRole(role);
|
|
||||||
_traitorRule.Traitors.Add(role);
|
|
||||||
foreach (var objective in config.Objectives)
|
|
||||||
{
|
|
||||||
AddObjective(mind, objective);
|
|
||||||
}
|
|
||||||
|
|
||||||
_audio.PlayGlobal(config.GreetingSound, Filter.Empty().AddPlayer(session), false, AudioParams.Default);
|
_audio.PlayGlobal(config.GreetingSound, Filter.Empty().AddPlayer(session), false, AudioParams.Default);
|
||||||
_chatMan.DispatchServerMessage(session, Loc.GetString("ninja-role-greeting"));
|
_chatMan.DispatchServerMessage(session, Loc.GetString("ninja-role-greeting"));
|
||||||
@@ -285,8 +335,8 @@ public sealed class NinjaSystem : SharedNinjaSystem
|
|||||||
private void OnDoorEmagged(EntityUid uid, DoorComponent door, ref DoorEmaggedEvent args)
|
private void OnDoorEmagged(EntityUid uid, DoorComponent door, ref DoorEmaggedEvent args)
|
||||||
{
|
{
|
||||||
// make sure it's a ninja doorjacking it
|
// make sure it's a ninja doorjacking it
|
||||||
if (TryComp<NinjaComponent>(args.UserUid, out var ninja))
|
if (GetNinjaRole(args.UserUid, out var role))
|
||||||
ninja.DoorsJacked++;
|
role.DoorsJacked++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateNinja(EntityUid uid, NinjaComponent ninja, float frameTime)
|
private void UpdateNinja(EntityUid uid, NinjaComponent ninja, float frameTime)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public sealed class SpiderChargeSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
var user = args.User;
|
var user = args.User;
|
||||||
|
|
||||||
if (!TryComp<NinjaComponent>(user, out var ninja))
|
if (!_ninja.GetNinjaRole(user, out var role))
|
||||||
{
|
{
|
||||||
_popups.PopupEntity(Loc.GetString("spider-charge-not-ninja"), user, user);
|
_popups.PopupEntity(Loc.GetString("spider-charge-not-ninja"), user, user);
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
@@ -34,17 +34,16 @@ public sealed class SpiderChargeSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
// allow planting anywhere if there is no target, which should never happen
|
// allow planting anywhere if there is no target, which should never happen
|
||||||
if (ninja.SpiderChargeTarget != null)
|
if (role.SpiderChargeTarget == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// assumes warp point still exists
|
||||||
|
var target = Transform(role.SpiderChargeTarget.Value).MapPosition;
|
||||||
|
var coords = args.ClickLocation.ToMap(EntityManager, _transform);
|
||||||
|
if (!coords.InRange(target, comp.Range))
|
||||||
{
|
{
|
||||||
// assumes warp point still exists
|
_popups.PopupEntity(Loc.GetString("spider-charge-too-far"), user, user);
|
||||||
var target = Transform(ninja.SpiderChargeTarget.Value).MapPosition;
|
args.Handled = true;
|
||||||
var coords = args.ClickLocation.ToMap(EntityManager, _transform);
|
|
||||||
if (!coords.InRange(target, comp.Range))
|
|
||||||
{
|
|
||||||
_popups.PopupEntity(Loc.GetString("spider-charge-too-far"), user, user);
|
|
||||||
args.Handled = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,10 +54,10 @@ public sealed class SpiderChargeSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnExplode(EntityUid uid, SpiderChargeComponent comp, TriggerEvent args)
|
private void OnExplode(EntityUid uid, SpiderChargeComponent comp, TriggerEvent args)
|
||||||
{
|
{
|
||||||
if (comp.Planter == null || !TryComp<NinjaComponent>(comp.Planter, out var ninja))
|
if (comp.Planter == null || !_ninja.GetNinjaRole(comp.Planter.Value, out var role))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// assumes the target was destroyed, that the charge wasn't moved somehow
|
// assumes the target was destroyed, that the charge wasn't moved somehow
|
||||||
_ninja.DetonateSpiderCharge(ninja);
|
role.SpiderChargeDetonated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
using Content.Server.Ninja.Systems;
|
||||||
using Content.Server.Objectives.Interfaces;
|
using Content.Server.Objectives.Interfaces;
|
||||||
using Content.Shared.Ninja.Components;
|
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
@@ -30,16 +30,14 @@ public sealed class DoorjackCondition : IObjectiveCondition
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
|
||||||
if (_mind?.OwnedEntity == null
|
|
||||||
|| !entMan.TryGetComponent<NinjaComponent>(_mind.OwnedEntity, out var ninja))
|
|
||||||
return 0f;
|
|
||||||
|
|
||||||
// prevent divide-by-zero
|
// prevent divide-by-zero
|
||||||
if (_target == 0)
|
if (_target == 0)
|
||||||
return 1f;
|
return 1f;
|
||||||
|
|
||||||
return (float) ninja.DoorsJacked / (float) _target;
|
if (!NinjaSystem.GetNinjaRole(_mind, out var role))
|
||||||
|
return 0f;
|
||||||
|
|
||||||
|
return (float) role.DoorsJacked / (float) _target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
using Content.Server.Ninja.Systems;
|
||||||
using Content.Server.Objectives.Interfaces;
|
using Content.Server.Objectives.Interfaces;
|
||||||
using Content.Shared.Ninja.Components;
|
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
@@ -34,12 +34,10 @@ public sealed class DownloadCondition : IObjectiveCondition
|
|||||||
if (_target == 0)
|
if (_target == 0)
|
||||||
return 1f;
|
return 1f;
|
||||||
|
|
||||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
if (!NinjaSystem.GetNinjaRole(_mind, out var role))
|
||||||
if (_mind?.OwnedEntity == null
|
|
||||||
|| !entMan.TryGetComponent<NinjaComponent>(_mind.OwnedEntity, out var ninja))
|
|
||||||
return 0f;
|
return 0f;
|
||||||
|
|
||||||
return (float) ninja.DownloadedNodes.Count / (float) _target;
|
return (float) role.DownloadedNodes.Count / (float) _target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
using Content.Server.Ninja.Systems;
|
||||||
using Content.Server.Objectives.Interfaces;
|
using Content.Server.Objectives.Interfaces;
|
||||||
using Content.Server.Warps;
|
using Content.Server.Warps;
|
||||||
using Content.Shared.Ninja.Components;
|
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
@@ -23,12 +23,11 @@ public sealed class SpiderChargeCondition : IObjectiveCondition
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||||
if (_mind?.OwnedEntity == null
|
if (!NinjaSystem.GetNinjaRole(_mind, out var role)
|
||||||
|| !entMan.TryGetComponent<NinjaComponent>(_mind.OwnedEntity, out var ninja)
|
|| role.SpiderChargeTarget == null
|
||||||
|| ninja.SpiderChargeTarget == null
|
|| !entMan.TryGetComponent<WarpPointComponent>(role.SpiderChargeTarget, out var warp)
|
||||||
|| !entMan.TryGetComponent<WarpPointComponent>(ninja.SpiderChargeTarget, out var warp)
|
|
||||||
|| warp.Location == null)
|
|| warp.Location == null)
|
||||||
// if you are funny and microbomb then press c, you get this
|
// this should never really happen but eh
|
||||||
return Loc.GetString("objective-condition-spider-charge-no-target");
|
return Loc.GetString("objective-condition-spider-charge-no-target");
|
||||||
|
|
||||||
return Loc.GetString("objective-condition-spider-charge-title", ("location", warp.Location));
|
return Loc.GetString("objective-condition-spider-charge-title", ("location", warp.Location));
|
||||||
@@ -43,12 +42,10 @@ public sealed class SpiderChargeCondition : IObjectiveCondition
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
if (!NinjaSystem.GetNinjaRole(_mind, out var role))
|
||||||
if (_mind?.OwnedEntity == null
|
|
||||||
|| !entMan.TryGetComponent<NinjaComponent>(_mind.OwnedEntity, out var ninja))
|
|
||||||
return 0f;
|
return 0f;
|
||||||
|
|
||||||
return ninja.SpiderChargeDetonated ? 1f : 0f;
|
return role.SpiderChargeDetonated ? 1f : 0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,46 +1,43 @@
|
|||||||
using Content.Server.Objectives.Interfaces;
|
using Content.Server.Objectives.Interfaces;
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Objectives.Conditions
|
namespace Content.Server.Objectives.Conditions;
|
||||||
|
|
||||||
|
[DataDefinition]
|
||||||
|
public sealed class SurviveCondition : IObjectiveCondition
|
||||||
{
|
{
|
||||||
[UsedImplicitly]
|
private Mind.Mind? _mind;
|
||||||
[DataDefinition]
|
|
||||||
public sealed class SurviveCondition : IObjectiveCondition
|
public IObjectiveCondition GetAssigned(Mind.Mind mind)
|
||||||
{
|
{
|
||||||
private Mind.Mind? _mind;
|
return new SurviveCondition {_mind = mind};
|
||||||
|
}
|
||||||
|
|
||||||
public IObjectiveCondition GetAssigned(Mind.Mind mind)
|
public string Title => Loc.GetString("objective-condition-survive-title");
|
||||||
{
|
|
||||||
return new SurviveCondition {_mind = mind};
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Title => Loc.GetString("objective-condition-survive-title");
|
public string Description => Loc.GetString("objective-condition-survive-description");
|
||||||
|
|
||||||
public string Description => Loc.GetString("objective-condition-survive-description");
|
public SpriteSpecifier Icon => new SpriteSpecifier.Rsi(new ResourcePath("Clothing/Head/Helmets/spaceninja.rsi"), "icon");
|
||||||
|
|
||||||
public SpriteSpecifier Icon => new SpriteSpecifier.Rsi(new ResourcePath("Clothing/Head/Helmets/spaceninja.rsi"), "icon");
|
public float Difficulty => 0.5f;
|
||||||
|
|
||||||
public float Difficulty => 0.5f;
|
public float Progress => (_mind?.CharacterDeadIC ?? true) ? 0f : 1f;
|
||||||
|
|
||||||
public float Progress => (_mind?.CharacterDeadIC ?? true) ? 0f : 1f;
|
public bool Equals(IObjectiveCondition? other)
|
||||||
|
{
|
||||||
|
return other is SurviveCondition condition && Equals(_mind, condition._mind);
|
||||||
|
}
|
||||||
|
|
||||||
public bool Equals(IObjectiveCondition? other)
|
public override bool Equals(object? obj)
|
||||||
{
|
{
|
||||||
return other is SurviveCondition condition && Equals(_mind, condition._mind);
|
if (ReferenceEquals(null, obj)) return false;
|
||||||
}
|
if (ReferenceEquals(this, obj)) return true;
|
||||||
|
if (obj.GetType() != GetType()) return false;
|
||||||
|
return Equals((SurviveCondition) obj);
|
||||||
|
}
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
if (ReferenceEquals(null, obj)) return false;
|
return (_mind != null ? _mind.GetHashCode() : 0);
|
||||||
if (ReferenceEquals(this, obj)) return true;
|
|
||||||
if (obj.GetType() != GetType()) return false;
|
|
||||||
return Equals((SurviveCondition) obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return (_mind != null ? _mind.GetHashCode() : 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
using Content.Server.Ninja.Systems;
|
||||||
using Content.Server.Objectives.Interfaces;
|
using Content.Server.Objectives.Interfaces;
|
||||||
using Content.Shared.Ninja.Components;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Objectives.Conditions;
|
namespace Content.Server.Objectives.Conditions;
|
||||||
@@ -24,12 +24,10 @@ public sealed class TerrorCondition : IObjectiveCondition
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
if (!NinjaSystem.GetNinjaRole(_mind, out var role))
|
||||||
if (_mind?.OwnedEntity == null
|
|
||||||
|| !entMan.TryGetComponent<NinjaComponent>(_mind.OwnedEntity, out var ninja))
|
|
||||||
return 0f;
|
return 0f;
|
||||||
|
|
||||||
return ninja.CalledInThreat ? 1f : 0f;
|
return role.CalledInThreat ? 1f : 0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
Content.Server/Objectives/Requirements/NinjaRequirement.cs
Normal file
13
Content.Server/Objectives/Requirements/NinjaRequirement.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using Content.Server.Objectives.Interfaces;
|
||||||
|
using Content.Server.Ninja;
|
||||||
|
|
||||||
|
namespace Content.Server.Objectives.Requirements;
|
||||||
|
|
||||||
|
[DataDefinition]
|
||||||
|
public sealed class NinjaRequirement : IObjectiveRequirement
|
||||||
|
{
|
||||||
|
public bool CanBeAssigned(Mind.Mind mind)
|
||||||
|
{
|
||||||
|
return mind.HasRole<NinjaRole>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,8 @@ using Content.Shared.Roles;
|
|||||||
|
|
||||||
namespace Content.Server.Traitor
|
namespace Content.Server.Traitor
|
||||||
{
|
{
|
||||||
public sealed class TraitorRole : Role
|
[Virtual]
|
||||||
|
public class TraitorRole : Role
|
||||||
{
|
{
|
||||||
public AntagPrototype Prototype { get; }
|
public AntagPrototype Prototype { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ namespace Content.Shared.Ninja.Components;
|
|||||||
/// Component placed on a mob to make it a space ninja, able to use suit and glove powers.
|
/// Component placed on a mob to make it a space ninja, able to use suit and glove powers.
|
||||||
/// Contains ids of all ninja equipment.
|
/// Contains ids of all ninja equipment.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// TODO: Contains objective related stuff, might want to move it out somehow
|
|
||||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
[Access(typeof(SharedNinjaSystem))]
|
[Access(typeof(SharedNinjaSystem))]
|
||||||
public sealed partial class NinjaComponent : Component
|
public sealed partial class NinjaComponent : Component
|
||||||
@@ -16,6 +15,7 @@ public sealed partial class NinjaComponent : Component
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Grid entity of the station the ninja was spawned around. Set if spawned naturally by the event.
|
/// Grid entity of the station the ninja was spawned around. Set if spawned naturally by the event.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[ViewVariables, AutoNetworkedField]
|
||||||
public EntityUid? StationGrid;
|
public EntityUid? StationGrid;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -35,35 +35,4 @@ public sealed partial class NinjaComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public EntityUid? Katana = null;
|
public EntityUid? Katana = null;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Number of doors that have been doorjacked, used for objective
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables, AutoNetworkedField]
|
|
||||||
public int DoorsJacked = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Research nodes that have been downloaded, used for objective
|
|
||||||
/// </summary>
|
|
||||||
// TODO: client doesn't need to know what nodes are downloaded, just how many
|
|
||||||
[ViewVariables, AutoNetworkedField]
|
|
||||||
public HashSet<string> DownloadedNodes = new();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Warp point that the spider charge has to target
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables, AutoNetworkedField]
|
|
||||||
public EntityUid? SpiderChargeTarget = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the spider charge has been detonated on the target, used for objective
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables, AutoNetworkedField]
|
|
||||||
public bool SpiderChargeDetonated;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether the comms console has been hacked, used for objective
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables, AutoNetworkedField]
|
|
||||||
public bool CalledInThreat;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public abstract class SharedNinjaGlovesSystem : EntitySystem
|
|||||||
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
|
[Dependency] private readonly SharedInteractionSystem _interaction = default!;
|
||||||
[Dependency] private readonly INetManager _net = default!;
|
[Dependency] private readonly INetManager _net = default!;
|
||||||
[Dependency] private readonly SharedNinjaSystem _ninja = default!;
|
[Dependency] private readonly SharedNinjaSystem _ninja = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popups = default!;
|
[Dependency] protected readonly SharedPopupSystem Popups = default!;
|
||||||
[Dependency] private readonly TagSystem _tags = default!;
|
[Dependency] private readonly TagSystem _tags = default!;
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
||||||
@@ -72,7 +72,7 @@ public abstract class SharedNinjaGlovesSystem : EntitySystem
|
|||||||
if (comp.User != null)
|
if (comp.User != null)
|
||||||
{
|
{
|
||||||
comp.User = null;
|
comp.User = null;
|
||||||
_popups.PopupEntity(Loc.GetString("ninja-gloves-off"), user, user);
|
Popups.PopupEntity(Loc.GetString("ninja-gloves-off"), user, user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +191,7 @@ public abstract class SharedNinjaGlovesSystem : EntitySystem
|
|||||||
// take charge from battery
|
// take charge from battery
|
||||||
if (!_ninja.TryUseCharge(user, comp.StunCharge))
|
if (!_ninja.TryUseCharge(user, comp.StunCharge))
|
||||||
{
|
{
|
||||||
_popups.PopupEntity(Loc.GetString("ninja-no-power"), user, user);
|
Popups.PopupEntity(Loc.GetString("ninja-no-power"), user, user);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,76 +239,18 @@ public abstract class SharedNinjaGlovesSystem : EntitySystem
|
|||||||
args.Cancel();
|
args.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDownloadDoAfter(EntityUid uid, NinjaDownloadComponent comp, DownloadDoAfterEvent args)
|
// can't predict roles so only done on server.
|
||||||
{
|
protected virtual void OnDownloadDoAfter(EntityUid uid, NinjaDownloadComponent comp, DownloadDoAfterEvent args) { }
|
||||||
if (args.Cancelled || args.Handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var user = args.User;
|
// cant predict roles for checking if already called
|
||||||
var target = args.Target;
|
protected virtual void OnTerror(EntityUid uid, NinjaTerrorComponent comp, InteractionAttemptEvent args) { }
|
||||||
|
|
||||||
if (!TryComp<NinjaComponent>(user, out var ninja)
|
// can't predict roles or anything announcements related so only done on server.
|
||||||
|| !TryComp<TechnologyDatabaseComponent>(target, out var database))
|
protected virtual void OnTerrorDoAfter(EntityUid uid, NinjaTerrorComponent comp, TerrorDoAfterEvent args) { }
|
||||||
return;
|
|
||||||
|
|
||||||
var gained = _ninja.Download(ninja, database.TechnologyIds);
|
|
||||||
var str = gained == 0
|
|
||||||
? Loc.GetString("ninja-download-fail")
|
|
||||||
: Loc.GetString("ninja-download-success", ("count", gained), ("server", target));
|
|
||||||
|
|
||||||
_popups.PopupEntity(str, user, user, PopupType.Medium);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTerror(EntityUid uid, NinjaTerrorComponent comp, InteractionAttemptEvent args)
|
|
||||||
{
|
|
||||||
if (!GloveCheck(uid, args, out var gloves, out var user, out var target)
|
|
||||||
|| !TryComp<NinjaComponent>(user, out var ninja))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!IsCommsConsole(target))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// can only do it once
|
|
||||||
if (ninja.CalledInThreat)
|
|
||||||
{
|
|
||||||
_popups.PopupEntity(Loc.GetString("ninja-terror-already-called"), user, user);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var doAfterArgs = new DoAfterArgs(user, comp.TerrorTime, new TerrorDoAfterEvent(), target: target, used: uid, eventTarget: uid)
|
|
||||||
{
|
|
||||||
BreakOnDamage = true,
|
|
||||||
BreakOnUserMove = true,
|
|
||||||
MovementThreshold = 0.5f,
|
|
||||||
CancelDuplicate = false
|
|
||||||
};
|
|
||||||
|
|
||||||
_doAfter.TryStartDoAfter(doAfterArgs);
|
|
||||||
// FIXME: doesnt work, don't show the console popup
|
|
||||||
args.Cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
//for some reason shared comms console component isn't a component, so this has to be done server-side
|
|
||||||
protected virtual bool IsCommsConsole(EntityUid uid)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnTerrorDoAfter(EntityUid uid, NinjaTerrorComponent comp, TerrorDoAfterEvent args)
|
|
||||||
{
|
|
||||||
if (args.Cancelled || args.Handled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var user = args.User;
|
|
||||||
if (!TryComp<NinjaComponent>(user, out var ninja) || ninja.CalledInThreat)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_ninja.CallInThreat(ninja);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClientPopup(string msg, EntityUid user, PopupType type = PopupType.Small)
|
private void ClientPopup(string msg, EntityUid user, PopupType type = PopupType.Small)
|
||||||
{
|
{
|
||||||
if (_net.IsClient)
|
if (_net.IsClient)
|
||||||
_popups.PopupEntity(msg, user, user, type);
|
Popups.PopupEntity(msg, user, user, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,21 +48,6 @@ public abstract class SharedNinjaSystem : EntitySystem
|
|||||||
comp.Katana = katana;
|
comp.Katana = katana;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove when objective stuff moved into objectives somehow
|
|
||||||
public void DetonateSpiderCharge(NinjaComponent comp)
|
|
||||||
{
|
|
||||||
comp.SpiderChargeDetonated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Marks the objective as complete.
|
|
||||||
/// On server, makes announcement and adds rule of random threat.
|
|
||||||
/// </summary>
|
|
||||||
public virtual void CallInThreat(NinjaComponent comp)
|
|
||||||
{
|
|
||||||
comp.CalledInThreat = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Drain power from a target battery into the ninja's suit battery.
|
/// Drain power from a target battery into the ninja's suit battery.
|
||||||
/// Serverside only.
|
/// Serverside only.
|
||||||
@@ -71,17 +56,6 @@ public abstract class SharedNinjaSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Download the given set of nodes, returning how many new nodes were downloaded.'
|
|
||||||
/// </summary>
|
|
||||||
public int Download(NinjaComponent ninja, List<string> ids)
|
|
||||||
{
|
|
||||||
var oldCount = ninja.DownloadedNodes.Count;
|
|
||||||
ninja.DownloadedNodes.UnionWith(ids);
|
|
||||||
var newCount = ninja.DownloadedNodes.Count;
|
|
||||||
return newCount - oldCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the user's battery and tries to use some charge from it, returning true if successful.
|
/// Gets the user's battery and tries to use some charge from it, returning true if successful.
|
||||||
/// Serverside only.
|
/// Serverside only.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
id: DownloadObjective
|
id: DownloadObjective
|
||||||
issuer: spiderclan
|
issuer: spiderclan
|
||||||
requirements:
|
requirements:
|
||||||
- !type:TraitorRequirement {}
|
- !type:NinjaRequirement {}
|
||||||
conditions:
|
conditions:
|
||||||
- !type:DownloadCondition {}
|
- !type:DownloadCondition {}
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
id: DoorjackObjective
|
id: DoorjackObjective
|
||||||
issuer: spiderclan
|
issuer: spiderclan
|
||||||
requirements:
|
requirements:
|
||||||
- !type:TraitorRequirement {}
|
- !type:NinjaRequirement {}
|
||||||
conditions:
|
conditions:
|
||||||
- !type:DoorjackCondition {}
|
- !type:DoorjackCondition {}
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
id: SpiderChargeObjective
|
id: SpiderChargeObjective
|
||||||
issuer: spiderclan
|
issuer: spiderclan
|
||||||
requirements:
|
requirements:
|
||||||
- !type:TraitorRequirement {}
|
- !type:NinjaRequirement {}
|
||||||
conditions:
|
conditions:
|
||||||
- !type:SpiderChargeCondition {}
|
- !type:SpiderChargeCondition {}
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
id: TerrorObjective
|
id: TerrorObjective
|
||||||
issuer: spiderclan
|
issuer: spiderclan
|
||||||
requirements:
|
requirements:
|
||||||
- !type:TraitorRequirement {}
|
- !type:NinjaRequirement {}
|
||||||
conditions:
|
conditions:
|
||||||
- !type:TerrorCondition {}
|
- !type:TerrorCondition {}
|
||||||
|
|
||||||
@@ -34,6 +34,6 @@
|
|||||||
id: SurviveObjective
|
id: SurviveObjective
|
||||||
issuer: spiderclan
|
issuer: spiderclan
|
||||||
requirements:
|
requirements:
|
||||||
- !type:TraitorRequirement {}
|
- !type:NinjaRequirement {}
|
||||||
conditions:
|
conditions:
|
||||||
- !type:SurviveCondition {}
|
- !type:SurviveCondition {}
|
||||||
|
|||||||
Reference in New Issue
Block a user