mirror of
https://github.com/WWhiteDreamProject/wwdpublic.git
synced 2026-04-17 05:27:38 +03:00
329 lines
12 KiB
C#
329 lines
12 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using Content.Server.AlertLevel;
|
|
using Content.Server.Antag;
|
|
using Content.Server._Goobstation.Blob;
|
|
using Content.Server._Goobstation.Blob.Components;
|
|
using Content.Server.GameTicking.Rules.Components;
|
|
using Content.Server.Chat.Managers;
|
|
using Content.Server.Chat.Systems;
|
|
using Content.Server.GameTicking;
|
|
using Content.Server.GameTicking.Rules;
|
|
using Content.Server.Mind;
|
|
using Content.Server.Nuke;
|
|
using Content.Server.Objectives;
|
|
using Content.Server.RoundEnd;
|
|
using Content.Server.Station.Components;
|
|
using Content.Server.Station.Systems;
|
|
using Content.Shared._Goobstation.Blob.Components;
|
|
using Content.Shared.GameTicking.Components;
|
|
using Content.Shared.Objectives.Components;
|
|
using Robust.Shared.Audio;
|
|
using Robust.Shared.Player;
|
|
using Content.Server.Announcements.Systems;
|
|
|
|
namespace Content.Server.GameTicking.Rules;
|
|
|
|
public sealed class BlobRuleSystem : GameRuleSystem<BlobRuleComponent>
|
|
{
|
|
[Dependency] private readonly MindSystem _mindSystem = default!;
|
|
[Dependency] private readonly RoundEndSystem _roundEndSystem = default!;
|
|
[Dependency] private readonly NukeCodePaperSystem _nukeCode = default!;
|
|
[Dependency] private readonly StationSystem _stationSystem = default!;
|
|
[Dependency] private readonly ObjectivesSystem _objectivesSystem = default!;
|
|
[Dependency] private readonly AlertLevelSystem _alertLevelSystem = default!;
|
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
|
[Dependency] private readonly AnnouncerSystem _announcer = default!;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
SubscribeLocalEvent<BlobRuleComponent, AfterAntagEntitySelectedEvent>(AfterAntagSelected);
|
|
}
|
|
|
|
protected override void Started(EntityUid uid, BlobRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
|
|
{
|
|
var activeRules = QueryActiveRules();
|
|
while (activeRules.MoveNext(out var entityUid, out _, out _, out _))
|
|
{
|
|
if (uid == entityUid)
|
|
continue;
|
|
|
|
GameTicker.EndGameRule(uid, gameRule);
|
|
Log.Warning("blob is active!!! remove!");
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected override void ActiveTick(EntityUid uid, BlobRuleComponent component, GameRuleComponent gameRule, float frameTime)
|
|
{
|
|
component.Accumulator += frameTime;
|
|
|
|
if (component.Accumulator < 10)
|
|
return;
|
|
|
|
component.Accumulator = 0;
|
|
|
|
var check = new Dictionary<EntityUid, long>();
|
|
var blobCoreQuery = EntityQueryEnumerator<BlobCoreComponent, MetaDataComponent, TransformComponent>();
|
|
while (blobCoreQuery.MoveNext(out var ent, out var comp, out var md, out var xform))
|
|
{
|
|
if (TerminatingOrDeleted(ent, md) ||
|
|
!CheckBlobInStation(ent, xform, out var stationUid))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
check.TryAdd(stationUid.Value, 0);
|
|
|
|
check[stationUid.Value] += comp.BlobTiles.Count;
|
|
}
|
|
|
|
foreach (var (station, length) in check.AsParallel())
|
|
{
|
|
CheckChangeStage(station, component, length);
|
|
}
|
|
}
|
|
|
|
private bool CheckBlobInStation(EntityUid blobCore, TransformComponent? xform, [NotNullWhen(true)] out EntityUid? stationUid)
|
|
{
|
|
var station = _stationSystem.GetOwningStation(blobCore, xform);
|
|
if (station == null || !HasComp<StationEventEligibleComponent>(station.Value))
|
|
{
|
|
_chatManager.SendAdminAlert(blobCore, Loc.GetString("blob-alert-out-off-station"));
|
|
QueueDel(blobCore);
|
|
stationUid = null;
|
|
return false;
|
|
}
|
|
|
|
stationUid = station.Value;
|
|
return true;
|
|
}
|
|
|
|
private const string StationAlertCritical = "delta";
|
|
private const string StationAlertDetected = "red";
|
|
|
|
private void CheckChangeStage(
|
|
Entity<StationBlobConfigComponent?> stationUid,
|
|
BlobRuleComponent blobRuleComp,
|
|
long blobTilesCount)
|
|
{
|
|
Resolve(stationUid, ref stationUid.Comp, false);
|
|
|
|
if (blobTilesCount >= (stationUid.Comp?.StageBegin ?? StationBlobConfigComponent.DefaultStageBegin)
|
|
&& _roundEndSystem.ExpectedCountdownEnd != null)
|
|
{
|
|
_roundEndSystem.CancelRoundEndCountdown(checkCooldown: false);
|
|
|
|
_announcer.SendAnnouncement(
|
|
"blob-recall-shuttle",
|
|
Loc.GetString("blob-alert-recall-shuttle"),
|
|
colorOverride: Color.Red,
|
|
station: stationUid
|
|
);
|
|
}
|
|
|
|
switch (blobRuleComp.Stage)
|
|
{
|
|
case BlobStage.Default when blobTilesCount >= (stationUid.Comp?.StageBegin ?? StationBlobConfigComponent.DefaultStageBegin):
|
|
blobRuleComp.Stage = BlobStage.Begin;
|
|
|
|
_announcer.SendAnnouncement(
|
|
"blob-detect",
|
|
Loc.GetString("blob-alert-detect"),
|
|
colorOverride: Color.Red,
|
|
station: stationUid
|
|
);
|
|
|
|
// blobRuleComp.DetectedAudio,
|
|
|
|
_alertLevelSystem.SetLevel(stationUid, StationAlertDetected, true, true, true, true);
|
|
|
|
RaiseLocalEvent(stationUid,
|
|
new BlobChangeLevelEvent
|
|
{
|
|
Station = stationUid,
|
|
Level = blobRuleComp.Stage
|
|
},
|
|
broadcast: true);
|
|
return;
|
|
case BlobStage.Begin when blobTilesCount >= (stationUid.Comp?.StageCritical ?? StationBlobConfigComponent.DefaultStageCritical):
|
|
{
|
|
if (_nukeCode.SendNukeCodes(stationUid))//send the nuke code?
|
|
{
|
|
blobRuleComp.Stage = BlobStage.Critical;
|
|
|
|
_announcer.SendAnnouncement(
|
|
"blob-critical",
|
|
Loc.GetString("blob-alert-critical"),
|
|
colorOverride: Color.Red,
|
|
station: stationUid
|
|
);
|
|
// blobRuleComp.CriticalAudio
|
|
}
|
|
else
|
|
{
|
|
blobRuleComp.Stage = BlobStage.Critical;
|
|
|
|
_announcer.SendAnnouncement(
|
|
"blob-critical-no-nuke",
|
|
Loc.GetString("blob-alert-critical-NoNukeCode"),
|
|
colorOverride: Color.Red
|
|
);
|
|
// blobRuleComp.CriticalAudio
|
|
}
|
|
|
|
_alertLevelSystem.SetLevel(stationUid, StationAlertCritical, true, true, true, true);
|
|
|
|
RaiseLocalEvent(stationUid,
|
|
new BlobChangeLevelEvent
|
|
{
|
|
Station = stationUid,
|
|
Level = blobRuleComp.Stage
|
|
},
|
|
broadcast: true);
|
|
return;
|
|
}
|
|
case BlobStage.Critical when blobTilesCount >= (stationUid.Comp?.StageTheEnd ?? StationBlobConfigComponent.DefaultStageEnd):
|
|
{
|
|
blobRuleComp.Stage = BlobStage.TheEnd;
|
|
_roundEndSystem.EndRound();
|
|
|
|
RaiseLocalEvent(stationUid,
|
|
new BlobChangeLevelEvent
|
|
{
|
|
Station = stationUid,
|
|
Level = blobRuleComp.Stage
|
|
},
|
|
broadcast: true);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
private const string BlobIssuer = "objective-issuer-blob";
|
|
|
|
protected override void AppendRoundEndText(
|
|
EntityUid uid,
|
|
BlobRuleComponent blob,
|
|
GameRuleComponent gameRule,
|
|
ref RoundEndTextAppendEvent ev)
|
|
{
|
|
if (blob.Blobs.Count < 1)
|
|
return; // no blob no fun
|
|
|
|
var result = Loc.GetString("blob-round-end-result", ("blobCount", blob.Blobs.Count));
|
|
var totalPercentage = 0f;
|
|
|
|
// Get the total amount of blob tiles
|
|
foreach (var (mindId, mind) in blob.Blobs)
|
|
{
|
|
var objectives = mind.Objectives.ToArray();
|
|
|
|
foreach (var objective in objectives)
|
|
{
|
|
var comp = Comp<ObjectiveComponent>(objective);
|
|
if (comp.LocIssuer != Loc.GetString(BlobIssuer))
|
|
continue;
|
|
|
|
var info = _objectivesSystem.GetInfo(objective, mindId, mind);
|
|
totalPercentage += info?.Progress ?? 0;
|
|
}
|
|
}
|
|
|
|
if (totalPercentage >= 0.99f)
|
|
{
|
|
result += "\n" + Loc.GetString("blob-end-victory");
|
|
}
|
|
else
|
|
{
|
|
result += "\n" + Loc.GetString("blob-end-fail");
|
|
result += "\n" + Loc.GetString("blob-end-fail-progress", ("progress", (int) (totalPercentage * 100)));
|
|
}
|
|
|
|
result += "\n";
|
|
|
|
// yeah this is duplicated from traitor rules lol, there needs to be a generic rewrite where it just goes through all minds with objectives
|
|
foreach (var (mindId, mind) in blob.Blobs)
|
|
{
|
|
var name = mind.CharacterName;
|
|
_mindSystem.TryGetSession(mindId, out var session);
|
|
var username = session?.Name;
|
|
|
|
var objectives = mind.Objectives.ToArray();
|
|
if (objectives.Length == 0)
|
|
{
|
|
if (username != null)
|
|
{
|
|
if (name == null)
|
|
result += "\n" + Loc.GetString("blob-user-was-a-blob", ("user", username));
|
|
else
|
|
{
|
|
result += "\n" + Loc.GetString("blob-user-was-a-blob-named",
|
|
("user", username),
|
|
("name", name));
|
|
}
|
|
}
|
|
else if (name != null)
|
|
result += "\n" + Loc.GetString("blob-was-a-blob-named", ("name", name));
|
|
|
|
continue;
|
|
}
|
|
|
|
if (username != null)
|
|
{
|
|
if (name == null)
|
|
{
|
|
result += "\n" + Loc.GetString("blob-user-was-a-blob-with-objectives",
|
|
("user", username));
|
|
}
|
|
else
|
|
{
|
|
result += "\n" + Loc.GetString("blob-user-was-a-blob-with-objectives-named",
|
|
("user", username),
|
|
("name", name));
|
|
}
|
|
}
|
|
else if (name != null)
|
|
result += "\n" + Loc.GetString("blob-was-a-blob-with-objectives-named", ("name", name));
|
|
|
|
foreach (var objectiveGroup in objectives.GroupBy(o => Comp<ObjectiveComponent>(o).LocIssuer == Loc.GetString(BlobIssuer)))
|
|
{
|
|
if (!objectiveGroup.Key)
|
|
continue;
|
|
|
|
foreach (var objective in objectiveGroup)
|
|
{
|
|
|
|
var info = _objectivesSystem.GetInfo(objective, mindId, mind);
|
|
if (info == null)
|
|
continue;
|
|
|
|
var progress = info.Value.Progress;
|
|
|
|
result += "\n- " + Loc.GetString(
|
|
"blob-objective-percentage",
|
|
("progress", (int) (progress * 100))
|
|
);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
ev.AddLine(result);
|
|
}
|
|
|
|
public void MakeBlob(EntityUid player)
|
|
{
|
|
var comp = EnsureComp<BlobCarrierComponent>(player);
|
|
comp.HasMind = HasComp<ActorComponent>(player);
|
|
comp.TransformationDelay = 10 * 60; // 10min
|
|
}
|
|
|
|
private void AfterAntagSelected(EntityUid uid, BlobRuleComponent component, AfterAntagEntitySelectedEvent args)
|
|
{
|
|
MakeBlob(args.EntityUid);
|
|
}
|
|
}
|