перенос файлов сервера из папки White в _White

This commit is contained in:
Remuchi
2024-01-28 18:18:54 +07:00
parent 21dbccfec9
commit 1e4ad59270
309 changed files with 450 additions and 437 deletions

View File

@@ -0,0 +1,20 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Shared.Access.Components;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class AiRunLockAspect : AspectSystem<AiRunLockAspectComponent>
{
protected override void Started(EntityUid uid, AiRunLockAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var query = EntityQueryEnumerator<AccessReaderComponent>();
while (query.MoveNext(out _, out var accessReaderComponent))
{
accessReaderComponent.Enabled = false;
}
}
}

View File

@@ -0,0 +1,87 @@
using System.Linq;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Humanoid;
using Content.Shared.White.NonPeacefulRoundEnd;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class BattledAspect : AspectSystem<BattledAspectComponent>
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
private NonPeacefulRoundItemsPrototype _nonPeacefulRoundItemsPrototype = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(HandleLateJoin);
}
protected override void Started(EntityUid uid, BattledAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var prototypes = _prototypeManager.EnumeratePrototypes<NonPeacefulRoundItemsPrototype>().ToList();
if (prototypes.Count == 0)
ForceEndSelf(uid, gameRule);
_nonPeacefulRoundItemsPrototype = _robustRandom.Pick(prototypes);
var query = EntityQueryEnumerator<HumanoidAppearanceComponent>();
while (query.MoveNext(out var ent, out _))
{
GiveItem(ent);
}
}
private void HandleLateJoin(PlayerSpawnCompleteEvent ev)
{
var query = EntityQueryEnumerator<BattledAspectComponent, GameRuleComponent>();
while (query.MoveNext(out var ruleEntity, out _, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(ruleEntity, gameRule))
continue;
if (!ev.LateJoin)
return;
var mob = ev.Mob;
GiveItem(mob);
}
}
#region Helpers
private void GiveItem(EntityUid player)
{
var item = _robustRandom.Pick(_nonPeacefulRoundItemsPrototype.Items);
var transform = CompOrNull<TransformComponent>(player);
if(transform == null)
return;
if(!HasComp<HandsComponent>(player))
return;
var weaponEntity = EntityManager.SpawnEntity(item, transform.Coordinates);
_handsSystem.TryDrop(player);
_handsSystem.PickupOrDrop(player, weaponEntity);
}
#endregion
}

View File

@@ -0,0 +1,26 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Shared.White;
using Robust.Shared.Configuration;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class BloodyAspect : AspectSystem<BloodyAspectComponent>
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
protected override void Started(EntityUid uid, BloodyAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
_cfg.SetCVar(WhiteCVars.DamageGetModifier, 2.5f);
}
protected override void Ended(EntityUid uid, BloodyAspectComponent component, GameRuleComponent gameRule, GameRuleEndedEvent args)
{
base.Ended(uid, component, gameRule, args);
_cfg.SetCVar(WhiteCVars.DamageGetModifier, 1.0f);
}
}

View File

@@ -0,0 +1,31 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Robust.Shared.Random;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class BombassAspect : AspectSystem<BombassAspectComponent>
{
[Dependency] private readonly IRobustRandom _random = default!;
protected override void Added(EntityUid uid, BombassAspectComponent component, GameRuleComponent gameRule, GameRuleAddedEvent args)
{
base.Added(uid, component, gameRule, args);
SpawnMines();
}
private void SpawnMines()
{
var minMines = _random.Next(40, 60);
for (var i = 0; i < minMines; i++)
{
if (!TryFindRandomTile(out _, out _, out _, out var targetCoords))
break;
EntityManager.SpawnEntity("LandMineAspectExplosive", targetCoords);
}
}
}

View File

@@ -0,0 +1,25 @@
using Content.Server.Cargo.Components;
using Content.Server.Cargo.Systems;
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class CargoRichAspect : AspectSystem<CargoRichAspectComponent>
{
[Dependency] private readonly CargoSystem _cargoSystem = default!;
protected override void Added(EntityUid uid, CargoRichAspectComponent component, GameRuleComponent gameRule, GameRuleAddedEvent args)
{
base.Added(uid, component, gameRule, args);
if (!TryGetRandomStation(out var station))
return;
if (!TryComp<StationBankAccountComponent>(station, out var stationBankAccountComponent))
return;
_cargoSystem.UpdateBankAccount(station, stationBankAccountComponent, 100000);
}
}

View File

@@ -0,0 +1,157 @@
using Content.Server.Chat.Systems;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Speech.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Shared.GameTicking;
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
using Content.Shared.Speech;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class CatEarsAspect : AspectSystem<CatEarsAspectComponent>
{
[Dependency] private readonly IPrototypeManager _protoMan = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ChatSystem _chat = default!;
private MarkingPrototype _ears = default!;
private MarkingPrototype _tail = default!;
private const string FemaleFelinidVoices = "FemaleFelinid";
private const string MaleFelinidVoices = "MaleFelinid";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(HandleLateJoin);
SubscribeLocalEvent<RoundEndedEvent>(OnRoundEnd);
_ears = _protoMan.Index<MarkingPrototype>("FelinidEarsBasic");
_tail = _protoMan.Index<MarkingPrototype>("FelinidTailBasic");
}
private void OnRoundEnd(RoundEndedEvent ev)
{
var query = EntityQueryEnumerator<CatEarsAspectComponent, GameRuleComponent>();
while (query.MoveNext(out var ruleEntity, out _, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(ruleEntity, gameRule))
continue;
var entQuery = EntityQueryEnumerator<SpeechComponent, HumanoidAppearanceComponent>();
while (entQuery.MoveNext(out var ent, out _, out _))
{
_chat.TrySendInGameICMessage(ent, _random.Pick(new[] { "Мяу", "Мур", "Ня" }), InGameICChatType.Speak,
ChatTransmitRange.Normal);
}
}
}
protected override void Started(
EntityUid uid,
CatEarsAspectComponent component,
GameRuleComponent gameRule,
GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var query = EntityQueryEnumerator<HumanoidAppearanceComponent>();
while (query.MoveNext(out var ent, out var appearance))
{
AddMarkings(ent, appearance);
}
}
private void HandleLateJoin(PlayerSpawnCompleteEvent ev)
{
var query = EntityQueryEnumerator<CatEarsAspectComponent, GameRuleComponent>();
while (query.MoveNext(out var ruleEntity, out _, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(ruleEntity, gameRule))
continue;
if (!ev.LateJoin)
return;
AddMarkings(ev.Mob);
}
}
private void AddMarkings(EntityUid uid, HumanoidAppearanceComponent? appearance = null)
{
if (!Resolve(uid, ref appearance, false))
return;
switch (appearance.Species)
{
case "Felinid":
return;
case "Human":
{
if (!appearance.MarkingSet.TryGetCategory(MarkingCategories.HeadTop, out var markings) ||
markings.Count == 0)
AddEars(appearance);
if (!appearance.MarkingSet.TryGetCategory(MarkingCategories.Tail, out markings) || markings.Count == 0)
AddTail(appearance);
Dirty(uid, appearance);
ChangeEmotesVoice(uid, appearance);
return;
}
default:
AddEars(appearance);
AddTail(appearance);
Dirty(uid, appearance);
ChangeEmotesVoice(uid, appearance);
break;
}
}
private List<Color> GetColors(HumanoidAppearanceComponent appearance, MarkingPrototype prototype)
{
return MarkingColoring.GetMarkingLayerColors(prototype, appearance.SkinColor, appearance.EyeColor,
appearance.MarkingSet);
}
private void AddTail(HumanoidAppearanceComponent appearance)
{
if (!appearance.MarkingSet.TryGetMarking(MarkingCategories.Tail, _tail.ID, out _))
{
appearance.MarkingSet.AddFront(MarkingCategories.Tail,
new Marking(_tail.ID, GetColors(appearance, _tail)) { Forced = true });
}
}
private void AddEars(HumanoidAppearanceComponent appearance)
{
if (!appearance.MarkingSet.TryGetMarking(MarkingCategories.HeadTop, _tail.ID, out _))
{
appearance.MarkingSet.AddFront(MarkingCategories.HeadTop,
new Marking(_ears.ID, GetColors(appearance, _ears)) { Forced = true });
}
}
private void ChangeEmotesVoice(EntityUid user, HumanoidAppearanceComponent appearanceComponent)
{
if (!TryComp(user, out VocalComponent? vocals))
{
return;
}
switch (appearanceComponent.Gender)
{
case Gender.Female:
_protoMan.TryIndex(FemaleFelinidVoices, out vocals.EmoteSounds);
break;
case Gender.Male:
_protoMan.TryIndex(MaleFelinidVoices, out vocals.EmoteSounds);
break;
}
}
}

View File

@@ -0,0 +1,28 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Server._White.Other;
using Content.Shared.Buckle;
using Content.Shared.Buckle.Components;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class ChairLeakAspect : AspectSystem<ChairLeakAspectComponent>
{
[Dependency] private readonly SharedBuckleSystem _buckle = default!;
protected override void Started(EntityUid uid, ChairLeakAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var query = EntityQueryEnumerator<ChairMarkComponent>();
while (query.MoveNext(out var ent, out _))
{
if (TryComp(ent, out StrapComponent? strap))
_buckle.StrapRemoveAll(strap);
EntityManager.DeleteEntity(ent);
}
}
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class AiRunLockAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class BattledAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class BloodyAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class BombassAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class CargoRichAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class CatEarsAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class ChairLeakAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class DancingAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class DarknessAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class DrunkAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class FastAndFuriousAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class NoEngineAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class NothingAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class PresentAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class RandomAccentAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class RandomAppearanceAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class ReflectAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class SkeletonAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class SlipperyAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class StolenFloorAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class TraitorRichAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class TraitoredAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class WeakAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class WeakWallsAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class WhisperAspectComponent : Component
{
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._White.AspectsSystem.Aspects.Components;
[RegisterComponent]
public sealed partial class WindowLeakAspectComponent : Component
{
}

View File

@@ -0,0 +1,49 @@
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.Animations;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Shared.Mobs.Components;
using Content.Shared.White.Animations;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class DancingAspect : AspectSystem<DancingAspectComponent>
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(HandleLateJoin);
}
protected override void Started(
EntityUid uid,
DancingAspectComponent component,
GameRuleComponent gameRule,
GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var query = EntityQueryEnumerator<EmoteAnimationComponent, MobStateComponent>();
while (query.MoveNext(out var ent, out _, out _))
{
EnsureComp<DancingComponent>(ent);
}
}
private void HandleLateJoin(PlayerSpawnCompleteEvent ev)
{
var query = EntityQueryEnumerator<DancingAspectComponent, GameRuleComponent>();
while (query.MoveNext(out var ruleEntity, out _, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(ruleEntity, gameRule))
continue;
if (!ev.LateJoin)
return;
var mob = ev.Mob;
EnsureComp<DancingComponent>(mob);
}
}
}

View File

@@ -0,0 +1,20 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Server._White.Other;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class DarknessAspect : AspectSystem<DarknessAspectComponent>
{
protected override void Started(EntityUid uid, DarknessAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var query = EntityQueryEnumerator<LightMarkComponent>();
while (query.MoveNext(out var ent, out _))
{
EntityManager.DeleteEntity(ent);
}
}
}

View File

@@ -0,0 +1,48 @@
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Shared.Drunk;
using Content.Shared.Humanoid;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class DrunkAspect : AspectSystem<DrunkAspectComponent>
{
[Dependency] private readonly SharedDrunkSystem _drunkSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(HandleLateJoin);
}
protected override void Started(EntityUid uid, DrunkAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var query = EntityQueryEnumerator<HumanoidAppearanceComponent>();
while (query.MoveNext(out var ent, out _))
{
_drunkSystem.TryApplyDrunkenness(ent, 50);
}
}
private void HandleLateJoin(PlayerSpawnCompleteEvent ev)
{
var query = EntityQueryEnumerator<DrunkAspectComponent, GameRuleComponent>();
while (query.MoveNext(out var ruleEntity, out _, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(ruleEntity, gameRule))
continue;
if (!ev.LateJoin)
return;
var mob = ev.Mob;
_drunkSystem.TryApplyDrunkenness(mob, 50);
}
}
}

View File

@@ -0,0 +1,75 @@
using Content.Server.Cloning;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Shared.Cloning;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class FastAndFuriousAspect : AspectSystem<FastAndFuriousAspectComponent>
{
[Dependency] private readonly MovementSpeedModifierSystem _movementSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(HandleLateJoin);
SubscribeLocalEvent<MovementSpeedModifierComponent, CloningEvent>(HandleCloning);
}
protected override void Started(EntityUid uid, FastAndFuriousAspectComponent component, GameRuleComponent gameRule,
GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var query = EntityQueryEnumerator<MovementSpeedModifierComponent>();
while (query.MoveNext(out var ent, out var speedModifierComponent))
{
_movementSystem.ChangeBaseSpeed(ent, speedModifierComponent.BaseWalkSpeed,
speedModifierComponent.BaseSprintSpeed + 3, speedModifierComponent.Acceleration);
}
}
protected override void Ended(EntityUid uid, FastAndFuriousAspectComponent component, GameRuleComponent gameRule,
GameRuleEndedEvent args)
{
base.Ended(uid, component, gameRule, args);
var query = EntityQueryEnumerator<MovementSpeedModifierComponent>();
while (query.MoveNext(out var ent, out var speedModifierComponent))
{
_movementSystem.ChangeBaseSpeed(ent, speedModifierComponent.BaseWalkSpeed,
speedModifierComponent.BaseSprintSpeed, speedModifierComponent.Acceleration);
}
}
private void HandleCloning(EntityUid uid, MovementSpeedModifierComponent component, ref CloningEvent ev)
{
ModifySpeedIfActive(ev.Target);
}
private void HandleLateJoin(PlayerSpawnCompleteEvent ev)
{
if (!ev.LateJoin)
return;
ModifySpeedIfActive(ev.Mob);
}
private void ModifySpeedIfActive(EntityUid mob)
{
var query = EntityQueryEnumerator<FastAndFuriousAspectComponent, GameRuleComponent>();
while (query.MoveNext(out var ruleEntity, out _, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(ruleEntity, gameRule))
continue;
if (!TryComp<MovementSpeedModifierComponent>(mob, out var speedModifierComponent))
return;
_movementSystem.ChangeBaseSpeed(mob, speedModifierComponent.BaseWalkSpeed,
speedModifierComponent.BaseSprintSpeed + 3, speedModifierComponent.Acceleration);
}
}
}

View File

@@ -0,0 +1,21 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Server._White.Other;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class NoEngineAspect : AspectSystem<NoEngineAspectComponent>
{
protected override void Started(EntityUid uid, NoEngineAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var query = EntityQueryEnumerator<EngineMarkComponent>();
while (query.MoveNext(out var ent, out _))
{
EntityManager.DeleteEntity(ent);
}
}
}

View File

@@ -0,0 +1,8 @@
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class NothingAspect : AspectSystem<NothingAspectComponent>
{
}

View File

@@ -0,0 +1,31 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Robust.Shared.Random;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class PresentAspect : AspectSystem<PresentAspectComponent>
{
[Dependency] private readonly IRobustRandom _random = default!;
protected override void Added(EntityUid uid, PresentAspectComponent component, GameRuleComponent gameRule, GameRuleAddedEvent args)
{
base.Added(uid, component, gameRule, args);
SpawnPresents();
}
private void SpawnPresents()
{
var minPresents = _random.Next(150, 200);
for (var i = 0; i < minPresents; i++)
{
if (!TryFindRandomTile(out _, out _, out _, out var targetCoords))
break;
EntityManager.SpawnEntity("PresentRandomUnsafe", targetCoords);
}
}
}

View File

@@ -0,0 +1,107 @@
using System.Linq;
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Speech.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Shared.Mind.Components;
using Robust.Shared.Random;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class RandomAccentAspect : AspectSystem<RandomAccentAspectComponent>
{
[Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(HandleLateJoin);
}
protected override void Started(EntityUid uid, RandomAccentAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var query = EntityQueryEnumerator<MindContainerComponent>();
while (query.MoveNext(out var ent, out _))
{
ApplyRandomAccent(ent);
}
}
private void HandleLateJoin(PlayerSpawnCompleteEvent ev)
{
var query = EntityQueryEnumerator<RandomAccentAspectComponent, GameRuleComponent>();
while (query.MoveNext(out var ruleEntity, out _, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(ruleEntity, gameRule))
continue;
if (!ev.LateJoin)
return;
var mob = ev.Mob;
ApplyRandomAccent(mob);
}
}
#region Helpers
private enum AccentType
{
Stuttering,
Spanish,
Slurred,
Scrambled,
Pirate,
Russian,
Anime,
Lizard,
Backwards
}
private void ApplyRandomAccent(EntityUid uid)
{
var allAccents = Enum.GetValues(typeof(AccentType)).Cast<AccentType>().ToList();
var randomIndex = _random.Next(allAccents.Count);
var selectedAccent = allAccents[randomIndex];
ApplyAccent(uid, selectedAccent);
}
private void ApplyAccent(EntityUid uid, AccentType accentType)
{
switch (accentType)
{
case AccentType.Stuttering:
EntityManager.EnsureComponent<StutteringAccentComponent>(uid);
break;
case AccentType.Spanish:
EntityManager.EnsureComponent<SpanishAccentComponent>(uid);
break;
case AccentType.Slurred:
EntityManager.EnsureComponent<SlurredAccentComponent>(uid);
break;
case AccentType.Scrambled:
EntityManager.EnsureComponent<ScrambledAccentComponent>(uid);
break;
case AccentType.Pirate:
EntityManager.EnsureComponent<PirateAccentComponent>(uid);
break;
case AccentType.Russian:
EntityManager.EnsureComponent<RussianAccentComponent>(uid);
break;
case AccentType.Anime:
EntityManager.EnsureComponent<OwOAccentComponent>(uid);
break;
case AccentType.Lizard:
EntityManager.EnsureComponent<LizardAccentComponent>(uid);
break;
case AccentType.Backwards:
EntityManager.EnsureComponent<BackwardsAccentComponent>(uid);
break;
}
}
#endregion
}

View File

@@ -0,0 +1,44 @@
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Server._White.Other.RandomHumanSystem;
using Content.Shared.Humanoid;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class RandomAppearanceAspect : AspectSystem<RandomAppearanceAspectComponent>
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(HandleLateJoin);
}
protected override void Started(EntityUid uid, RandomAppearanceAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var query = EntityQueryEnumerator<HumanoidAppearanceComponent>();
while (query.MoveNext(out var ent, out _))
{
EnsureComp<RandomHumanComponent>(ent);
}
}
private void HandleLateJoin(PlayerSpawnCompleteEvent ev)
{
var query = EntityQueryEnumerator<RandomAppearanceAspectComponent, GameRuleComponent>();
while (query.MoveNext(out var ruleEntity, out _, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(ruleEntity, gameRule))
continue;
if (!ev.LateJoin)
return;
var mob = ev.Mob;
EnsureComp<RandomHumanComponent>(mob);
}
}
}

View File

@@ -0,0 +1,24 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Server._White.Other;
using Content.Shared.Weapons.Reflect;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class ReflectAspect : AspectSystem<ReflectAspectComponent>
{
protected override void Started(EntityUid uid, ReflectAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var query = EntityQueryEnumerator<ReflectAspectMarkComponent>();
while (query.MoveNext(out var ent, out _))
{
var reflect = EnsureComp<ReflectComponent>(ent);
reflect.ReflectProb = 1;
reflect.Reflects = ReflectType.Energy | ReflectType.NonEnergy;
}
}
}

View File

@@ -0,0 +1,71 @@
using Content.Server.GameTicking;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Humanoid;
using Content.Server.Polymorph.Systems;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Shared.Humanoid;
using Content.Shared.Polymorph;
using Robust.Shared.Prototypes;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class SkeletonAspect : AspectSystem<SkeletonAspectComponent>
{
[Dependency] private readonly IPrototypeManager _protoMan = default!;
[Dependency] private readonly PolymorphSystem _polymorph = default!;
[Dependency] private readonly HumanoidAppearanceSystem _humanoidAppearance = default!;
private PolymorphPrototype _proto = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(HandleLateJoin);
_proto = _protoMan.Index<PolymorphPrototype>("AspectForcedSkeleton");
}
protected override void Started(EntityUid uid, SkeletonAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
Dictionary<EntityUid, HumanoidAppearanceComponent> entitiesToPolymorph = new();
var query = EntityQueryEnumerator<HumanoidAppearanceComponent>();
while (query.MoveNext(out var ent, out var humanoid))
{
entitiesToPolymorph[ent] = humanoid;
}
foreach (var ent in entitiesToPolymorph)
{
PolymorphEntity(ent.Key, ent.Value);
}
}
private void HandleLateJoin(PlayerSpawnCompleteEvent ev)
{
var query = EntityQueryEnumerator<SkeletonAspectComponent, GameRuleComponent>();
while (query.MoveNext(out var ruleEntity, out _, out var gameRule))
{
if (!GameTicker.IsGameRuleAdded(ruleEntity, gameRule))
continue;
if (!ev.LateJoin)
return;
PolymorphEntity(ev.Mob);
}
}
private void PolymorphEntity(EntityUid uid, HumanoidAppearanceComponent? humanoid = null)
{
if (!Resolve(uid, ref humanoid, false))
return;
_humanoidAppearance.SetSpecies(uid, "Skeleton", false, humanoid);
//_humanoidAppearance.SetBodyType(uid, "SkeletonNormal", false, humanoid);
_polymorph.PolymorphEntity(uid, _proto);
}
}

View File

@@ -0,0 +1,26 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Shared.White;
using Robust.Shared.Configuration;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class SlipperyAspect : AspectSystem<SlipperyAspectComponent>
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
protected override void Started(EntityUid uid, SlipperyAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
_cfg.SetCVar(WhiteCVars.SlipPowerModifier, 2f);
}
protected override void Ended(EntityUid uid, SlipperyAspectComponent component, GameRuleComponent gameRule, GameRuleEndedEvent args)
{
base.Ended(uid, component, gameRule, args);
_cfg.SetCVar(WhiteCVars.SlipPowerModifier, 1f);
}
}

View File

@@ -0,0 +1,36 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Maps;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Shared.Maps;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class StolenFloorAspect : AspectSystem<StolenFloorAspectComponent>
{
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
[Dependency] private readonly TileSystem _tileSystem = default!;
protected override void Started(EntityUid uid, StolenFloorAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
if (!TryGetStationGrids(out _, out var grids))
return;
foreach (var grid in grids)
{
foreach (var tile in Comp<MapGridComponent>(grid).GetAllTiles())
{
var tileDef = (ContentTileDefinition) _tileDefinitionManager[tile.Tile.TypeId];
if (!tileDef.CanCrowbar)
continue;
_tileSystem.DeconstructTile(tile, false);
}
}
}
}

View File

@@ -0,0 +1,74 @@
using System.Linq;
using Content.Server.Chat.Managers;
using Content.Server.GameTicking.Rules;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Store.Components;
using Content.Server.Store.Systems;
using Content.Server.Traitor.Uplink;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Shared.FixedPoint;
using Content.Shared.Mind;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class TraitorRichAspect : AspectSystem<TraitorRichAspectComponent>
{
[Dependency] private readonly TraitorRuleSystem _traitorRuleSystem = default!;
[Dependency] private readonly UplinkSystem _uplinkSystem = default!;
[Dependency] private readonly StoreSystem _store = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
private const string BriefingExtra =
"Поздравляем! Было принято решение выделить для вас 10 дополнительных телекристаллов.";
protected override void Started(EntityUid uid, TraitorRichAspectComponent component, GameRuleComponent gameRule,
GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
if (!HasTraitorGameRule())
ForceEndSelf(uid, gameRule);
RewardTraitors();
}
private void RewardTraitors()
{
var traitors = _traitorRuleSystem.GetAllLivingConnectedTraitors();
foreach (var traitor in traitors)
{
var ent = traitor.Mind.CurrentEntity;
if (ent == null)
continue;
var uplink = _uplinkSystem.FindUplinkTarget(ent.Value);
if (uplink == null || !TryComp(uplink, out StoreComponent? store) || store.AccountOwner != ent ||
store.Preset != "StorePresetUplink")
continue;
if (_store.TryAddCurrency(
new Dictionary<string, FixedPoint2> {{UplinkSystem.TelecrystalCurrencyPrototype, 10}}, uplink.Value,
store))
{
NotifyTraitor(traitor.Mind, _chatManager);
}
}
}
public static void NotifyTraitor(MindComponent mind, IChatManager chatManager)
{
if (mind.Session == null)
return;
chatManager.DispatchServerMessage(mind.Session, BriefingExtra);
}
private bool HasTraitorGameRule()
{
return EntityQuery<TraitorRuleComponent>().Any();
}
}

View File

@@ -0,0 +1,130 @@
using System.Linq;
using Content.Server.Chat.Managers;
using Content.Server.Chat.Systems;
using Content.Server.GameTicking.Rules;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Mind;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Random;
namespace Content.Server._White.AspectsSystem.Aspects
{
public sealed class TraitoredAspect : AspectSystem<TraitoredAspectComponent>
{
[Dependency] private readonly TraitorRuleSystem _traitorRuleSystem = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
[Dependency] private readonly ChatSystem _chatSystem = default!;
[Dependency] private readonly MindSystem _mindSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly IRobustRandom _random = default!;
private bool _announcedForTators;
private float _timeElapsed;
private float _timeElapsedForTators;
private float _wacky;
private const float WackyAaa = 60;
protected override void Started(EntityUid uid, TraitoredAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
// Just to make sure
ResetValues();
if (!HasTraitorGameRule())
ForceEndSelf(uid, gameRule);
_wacky = _random.Next(300, 360);
}
protected override void ActiveTick(EntityUid uid, TraitoredAspectComponent component, GameRuleComponent gameRule, float frameTime)
{
base.ActiveTick(uid, component, gameRule, frameTime);
_timeElapsedForTators += frameTime;
_timeElapsed += frameTime;
if (_timeElapsedForTators >= WackyAaa && !_announcedForTators)
{
AnnounceToTators(uid, gameRule);
_announcedForTators = true;
}
if (_timeElapsed >= _wacky)
{
AnnounceToAll(uid, gameRule);
}
}
protected override void Ended(EntityUid uid, TraitoredAspectComponent component, GameRuleComponent gameRule, GameRuleEndedEvent args)
{
base.Ended(uid, component, gameRule, args);
ResetValues();
}
#region Helpers
private void AnnounceToTators(EntityUid uid, GameRuleComponent rule)
{
var tators = _traitorRuleSystem.GetAllLivingConnectedTraitors();
if (tators.Count == 0)
{
ForceEndSelf(uid, rule);
}
foreach (var tator in tators)
{
if (!_mindSystem.TryGetSession(tator.Mind, out var session))
continue;
var nig = tator.Mind.OwnedEntity;
if (nig == null)
return;
_chatManager.DispatchServerMessage(session, "Внимание, коммуникации синдиката перехвачены, вас раскрыли!");
_audio.PlayEntity("/Audio/White/Aspects/palevo.ogg", nig.Value, nig.Value);
}
}
private void AnnounceToAll(EntityUid uid, GameRuleComponent rule)
{
var tators = _traitorRuleSystem.GetAllLivingConnectedTraitors();
var msg = "Станция, служба контрразведки нанотрейзен рассекретила секретную передачу Синдиката и выяснила имена проникниших на вашу станцию агентов. Агенты имеют следующие имена: \n";
foreach (var tator in tators)
{
var name = tator.Mind.CharacterName;
if (!string.IsNullOrEmpty(name))
{
msg += $" {name} - УБЕЙТЕ ЕГО НАХУЙ\n";
}
}
_chatSystem.DispatchGlobalAnnouncement(msg, "Мяукиман Крысус", colorOverride: Color.Aquamarine);
ForceEndSelf(uid, rule);
}
private void ResetValues()
{
_announcedForTators = false;
_timeElapsed = 0;
_timeElapsedForTators = 0;
}
private bool HasTraitorGameRule()
{
return EntityQuery<TraitorRuleComponent>().Any();
}
#endregion
}
}

View File

@@ -0,0 +1,26 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Shared.White;
using Robust.Shared.Configuration;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class WeakAspect : AspectSystem<WeakAspectComponent>
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
protected override void Started(EntityUid uid, WeakAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
_cfg.SetCVar(WhiteCVars.DamageGetModifier, 0.5f);
}
protected override void Ended(EntityUid uid, WeakAspectComponent component, GameRuleComponent gameRule, GameRuleEndedEvent args)
{
base.Ended(uid, component, gameRule, args);
_cfg.SetCVar(WhiteCVars.DamageGetModifier, 1.0f);
}
}

View File

@@ -0,0 +1,41 @@
using System.Linq;
using Content.Server.Destructible;
using Content.Server.Destructible.Thresholds.Triggers;
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Server._White.Other;
using Content.Shared.Damage;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class WeakWallsAspect : AspectSystem<WeakWallsAspectComponent>
{
[Dependency] private readonly DamageableSystem _damageable = default!;
private const float DamageMultiplier = 0.15f;
protected override void Started(EntityUid uid, WeakWallsAspectComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var query = EntityQueryEnumerator<WallMarkComponent>();
while (query.MoveNext(out var ent, out _))
{
if (!TryComp<DestructibleComponent>(ent, out var destructible) ||
!TryComp<DamageableComponent>(ent, out var damageable))
continue;
_damageable.SetDamageModifierSetId(ent, null, damageable);
var trigger = (DamageTrigger?) destructible.Thresholds
.LastOrDefault(threshold => threshold.Trigger is DamageTrigger)?.Trigger;
if (trigger == null)
continue;
trigger.Damage = (int) (trigger.Damage * DamageMultiplier);
}
}
}

View File

@@ -0,0 +1,8 @@
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class WhisperAspect : AspectSystem<WhisperAspectComponent>
{
}

View File

@@ -0,0 +1,39 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server._White.AspectsSystem.Aspects.Components;
using Content.Server._White.AspectsSystem.Base;
using Content.Server._White.Other;
using Content.Shared.Coordinates.Helpers;
using Content.Shared.Tag;
using Robust.Shared.Map;
namespace Content.Server._White.AspectsSystem.Aspects;
public sealed class WindowLeakAspect : AspectSystem<WindowLeakAspectComponent>
{
[Dependency] private readonly TagSystem _tag = default!;
protected override void Started(EntityUid uid, WindowLeakAspectComponent component, GameRuleComponent gameRule,
GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
HashSet<EntityCoordinates> coordinatesSet = new();
var query = EntityQueryEnumerator<WindowMarkComponent, TransformComponent>();
while (query.MoveNext(out var ent, out var window, out var windowXform))
{
var coords = windowXform.Coordinates;
coordinatesSet.Add(coords);
EntityManager.DeleteEntity(ent);
EntityManager.SpawnEntity(window.ReplacementProto, coords.SnapToGrid(EntityManager));
}
var xformQuery = EntityQueryEnumerator<TransformComponent>();
while (xformQuery.MoveNext(out var tileEnt, out var xform))
{
if (coordinatesSet.Contains(xform.Coordinates) && _tag.HasTag(tileEnt, "DeleteWithWindows"))
EntityManager.DeleteEntity(tileEnt);
}
}
}

View File

@@ -0,0 +1,39 @@
using Robust.Shared.Audio;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server._White.AspectsSystem.Base
{
[RegisterComponent]
public sealed partial class AspectComponent : Component
{
[DataField("name")]
public string? Name;
[DataField("description")]
public string? Description;
[DataField("requires")]
public string? Requires;
[DataField("weight")]
public float Weight = 1.0f;
[DataField("forbidden")]
public bool IsForbidden;
[DataField("hidden")]
public bool IsHidden;
[DataField("startAudio")]
public SoundSpecifier? StartAudio;
[DataField("endAudio")]
public SoundSpecifier? EndAudio;
[DataField("startDelay")]
public TimeSpan StartDelay = TimeSpan.Zero;
[DataField("startTime", customTypeSerializer: typeof(TimeOffsetSerializer))]
public TimeSpan StartTime;
}
}

View File

@@ -0,0 +1,246 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Chat.Systems;
using Content.Server.GameTicking.Rules;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Station.Components;
using Content.Shared.Database;
using Content.Shared.Physics;
using Robust.Server.GameObjects;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Collections;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server._White.AspectsSystem.Base
{
/// <summary>
/// Base class for aspect systems.
/// </summary>
/// <typeparam name="T">The type of component to which the system is applied.</typeparam>
public abstract class AspectSystem<T> : GameRuleSystem<T> where T : Component
{
[Dependency] private readonly IAdminLogManager _adminLogManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly ChatSystem _chatSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
[Dependency] private readonly TransformSystem _transform = default!;
protected ISawmill Sawmill = default!;
public override void Initialize()
{
base.Initialize();
Sawmill = Logger.GetSawmill("aspects");
}
/// <summary>
/// Called every tick when this aspect is running.
/// </summary>
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<AspectComponent, GameRuleComponent>();
while (query.MoveNext(out var uid, out var aspect, out var ruleData))
{
if (!GameTicker.IsGameRuleAdded(uid, ruleData))
continue;
if (!GameTicker.IsGameRuleActive(uid, ruleData) && _timing.CurTime >= aspect.StartTime)
{
GameTicker.StartGameRule(uid, ruleData);
}
}
}
/// <summary>
/// Called when an aspect is added to an entity.
/// </summary>
protected override void Added(EntityUid uid, T component, GameRuleComponent gameRule, GameRuleAddedEvent args)
{
base.Added(uid, component, gameRule, args);
if (!TryComp<AspectComponent>(uid, out var aspect))
return;
_adminLogManager.Add(LogType.AspectAnnounced, $"Aspect added {ToPrettyString(uid)}");
if (aspect is { Description: not null, IsHidden: false })
{
_chatSystem.DispatchGlobalAnnouncement(aspect.Description, playSound: false, colorOverride: Color.Aquamarine);
}
_audio.PlayGlobal(aspect.StartAudio, Filter.Broadcast(), true);
aspect.StartTime = _timing.CurTime + aspect.StartDelay;
}
/// <summary>
/// Called when an aspect is started.
/// </summary>
protected override void Started(EntityUid uid, T component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
if (!TryComp<AspectComponent>(uid, out _))
return;
_adminLogManager.Add(LogType.AspectStarted, LogImpact.High, $"Aspect started: {ToPrettyString(uid)}");
}
/// <summary>
/// Called when an aspect is ended.
/// </summary>
protected override void Ended(EntityUid uid, T component, GameRuleComponent gameRule, GameRuleEndedEvent args)
{
base.Ended(uid, component, gameRule, args);
if (!TryComp<AspectComponent>(uid, out var aspect))
return;
_adminLogManager.Add(LogType.AspectStopped, $"Aspect ended: {ToPrettyString(uid)}");
if (aspect is { Name: not null, IsHidden: false })
{
_chatSystem.DispatchGlobalAnnouncement($"Именем аспекта являлось: {aspect.Name}", playSound: false, colorOverride: Color.Aquamarine);
}
_audio.PlayGlobal(aspect.EndAudio, Filter.Broadcast(), true);
}
#region Helpers
/// <summary>
/// Forces this aspect to end prematurely.
/// </summary>
/// <param name="uid">The entity UID on which the aspect is being performed.</param>
/// <param name="component">The game rule component associated with this aspect (optional).</param>
protected void ForceEndSelf(EntityUid uid, GameRuleComponent? component = null)
{
GameTicker.EndGameRule(uid, component);
}
protected bool TryGetRandomStation([NotNullWhen(true)] out EntityUid? station, Func<EntityUid, bool>? filter = null)
{
var stations = new ValueList<EntityUid>();
if (filter == null)
{
stations.EnsureCapacity(Count<StationEventEligibleComponent>());
}
filter ??= _ => true;
var query = AllEntityQuery<StationEventEligibleComponent>();
while (query.MoveNext(out var uid, out _))
{
if (!filter(uid))
continue;
stations.Add(uid);
}
if (stations.Count == 0)
{
station = null;
return false;
}
station = stations[_robustRandom.Next(stations.Count)];
return true;
}
protected bool TryGetStationGrids([NotNullWhen(true)] out EntityUid? targetStation,
[NotNullWhen(true)] out HashSet<EntityUid>? grids)
{
if (!TryGetRandomStation(out targetStation))
{
targetStation = EntityUid.Invalid;
grids = null;
return false;
}
grids = Comp<StationDataComponent>(targetStation.Value).Grids;
return grids.Count > 0;
}
protected bool TryFindRandomTile(out Vector2i tile, [NotNullWhen(true)] out EntityUid? targetStation, out EntityUid targetGrid, out EntityCoordinates targetCoords)
{
tile = default;
targetCoords = EntityCoordinates.Invalid;
if (!TryGetStationGrids(out targetStation, out var possibleTargets))
{
targetGrid = EntityUid.Invalid;
return false;
}
targetGrid = _robustRandom.Pick(possibleTargets);
foreach (var target in possibleTargets.Where(HasComp<BecomesStationComponent>))
{
targetGrid = target;
break;
}
if (!TryComp<MapGridComponent>(targetGrid, out var gridComp))
return false;
var found = false;
var gridBounds = gridComp.LocalAABB.Scale(0.6f);
for (var i = 0; i < 10; i++)
{
var randomX = _robustRandom.Next((int) gridBounds.Left, (int) gridBounds.Right);
var randomY = _robustRandom.Next((int) gridBounds.Bottom, (int) gridBounds.Top);
tile = new Vector2i(randomX, randomY);
if (_atmosphere.IsTileSpace(targetGrid, Transform(targetGrid).MapUid, tile,
mapGridComp: gridComp)
|| _atmosphere.IsTileAirBlocked(targetGrid, tile, mapGridComp: gridComp))
{
continue;
}
var physQuery = GetEntityQuery<PhysicsComponent>();
var valid = true;
foreach (var ent in gridComp.GetAnchoredEntities(tile))
{
if (!physQuery.TryGetComponent(ent, out var body))
continue;
if (body.BodyType != BodyType.Static ||
!body.Hard ||
(body.CollisionLayer & (int) CollisionGroup.Impassable) == 0)
continue;
valid = false;
break;
}
if (!valid)
continue;
found = true;
targetCoords = gridComp.GridTileToLocal(tile);
break;
}
return found;
}
#endregion
}
}

View File

@@ -0,0 +1,145 @@
using Content.Server.Administration;
using Content.Server.GameTicking;
using Content.Server._White.AspectsSystem.Managers;
using Content.Shared.Administration;
using Robust.Shared.Console;
namespace Content.Server._White.AspectsSystem.Commands
{
[AdminCommand(AdminFlags.Fun)]
public sealed class ForceAspectCommand : IConsoleCommand
{
public string Command => "forceaspect";
public string Description => "Принудительно форсит аспект по его ID.";
public string Help => "forceaspect <aspectId>";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var ticker = EntitySystem.Get<GameTicker>();
if (ticker.RunLevel != GameRunLevel.PreRoundLobby)
{
shell.WriteLine("This can only be executed while the game is in the pre-round lobby.");
return;
}
if (args.Length != 1)
{
shell.WriteError("Использование: forceaspect <aspectId>");
return;
}
var aspectId = args[0];
var aspectManager = EntitySystem.Get<AspectManager>();
var result = aspectManager.ForceAspect(aspectId);
shell.WriteLine(result);
}
}
[AdminCommand(AdminFlags.Fun)]
public sealed class DeForceAspectCommand : IConsoleCommand
{
public string Command => "deforceaspect";
public string Description => "Дефорсит принудительно установленный аспект.";
public string Help => "deforceaspect";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var ticker = EntitySystem.Get<GameTicker>();
if (ticker.RunLevel != GameRunLevel.PreRoundLobby)
{
shell.WriteLine("This can only be executed while the game is in the pre-round lobby.");
return;
}
var aspectManager = EntitySystem.Get<AspectManager>();
var result = aspectManager.DeForceAspect();
shell.WriteLine(result);
}
}
[AdminCommand(AdminFlags.Fun)]
public sealed class GetForcedAspectCommand : IConsoleCommand
{
public string Command => "getforcedaspect";
public string Description => "Получает информацию о принудительно установленном аспекте.";
public string Help => "getforcedaspect";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var ticker = EntitySystem.Get<GameTicker>();
if (ticker.RunLevel != GameRunLevel.PreRoundLobby)
{
shell.WriteLine("This can only be executed while the game is in the pre-round lobby.");
return;
}
var aspectManager = EntitySystem.Get<AspectManager>();
var result = aspectManager.GetForcedAspect();
shell.WriteLine(result);
}
}
[AdminCommand(AdminFlags.Fun)]
public sealed class ListAspectsCommand : IConsoleCommand
{
public string Command => "listaspects";
public string Description => "Список всех доступных аспектов.";
public string Help => "listaspects";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var aspectManager = EntitySystem.Get<AspectManager>();
var aspectIds = aspectManager.GetAllAspectIds();
if (aspectIds.Count == 0)
{
shell.WriteLine("Нет доступных аспектов.");
}
else
{
shell.WriteLine("Список доступных аспектов:");
foreach (var aspectId in aspectIds)
{
shell.WriteLine(aspectId);
}
}
}
}
[AdminCommand(AdminFlags.Fun)]
public sealed class RunAspectCommand : IConsoleCommand
{
public string Command => "runaspect";
public string Description => "Запускает аспект по его ID.";
public string Help => "runaspect <aspectId>";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != 1)
{
shell.WriteError("Использование: runaspect <aspectId>");
return;
}
var aspectId = args[0];
var aspectManager = EntitySystem.Get<AspectManager>();
var result = aspectManager.RunAspect(aspectId);
shell.WriteLine(result);
}
}
[AdminCommand(AdminFlags.Fun)]
public sealed class RunRandomAspectCommand : IConsoleCommand
{
public string Command => "runrandomaspect";
public string Description => "Запускает случайный аспект.";
public string Help => "runrandomaspect";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
var aspectManager = EntitySystem.Get<AspectManager>();
var result = aspectManager.RunRandomAspect();
shell.WriteLine(result);
}
}
}

View File

@@ -0,0 +1,382 @@
using Content.Server.GameTicking;
using Content.Server._White.AspectsSystem.Base;
using Content.Shared.GameTicking;
using Content.Shared.White;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server._White.AspectsSystem.Managers
{
/// <summary>
/// Manager for aspects.
/// </summary>
public sealed class AspectManager : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly GameTicker _gameTicker = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
private ISawmill _sawmill = default!;
private bool AspectsEnabled { get; set; }
private double Chance { get; set; }
private string? ForcedAspect { get; set; }
private void SetEnabled(bool value) => AspectsEnabled = value;
private void SetChance(double value) => Chance = value;
private void SetForcedAspect(string? value) => ForcedAspect = value;
public override void Initialize()
{
base.Initialize();
_sawmill = Logger.GetSawmill("aspects");
_cfg.OnValueChanged(WhiteCVars.IsAspectsEnabled, SetEnabled, true);
_cfg.OnValueChanged(WhiteCVars.AspectChance, SetChance, true);
SubscribeLocalEvent<RoundStartedEvent>(OnRoundStarted);
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRestart);
}
#region Handlers
private void OnRoundStarted(RoundStartedEvent ev)
{
if (!AspectsEnabled)
return;
if (ForcedAspect != null)
{
RunAspect(ForcedAspect);
SetForcedAspect(null);
return;
}
if (_random.NextDouble() <= Chance)
{
RunRandomAspect();
}
}
// Put here needed cleanup.
private void OnRestart(RoundRestartCleanupEvent ev)
{
_cfg.SetCVar(WhiteCVars.DamageModifier, 1.0f);
_cfg.SetCVar(WhiteCVars.DamageGetModifier, 1.0f);
_cfg.SetCVar(WhiteCVars.SlipPowerModifier, 1.0f);
}
#endregion
#region PublicApi
/// <summary>
/// Forces a specific aspect by its prototype ID.
/// </summary>
/// <param name="aspectProtoId">The prototype ID of the aspect to be forced.</param>
public string ForceAspect(string aspectProtoId)
{
if (!AspectsEnabled)
{
var disabledStr = "Aspects disabled.";
_sawmill.Warning("Someone tried to force aspect when they disabled!");
return disabledStr;
}
if (!_prototype.TryIndex<EntityPrototype>(aspectProtoId, out var entityPrototype))
{
var response = "Aspect not found. Can`t find proto";
_sawmill.Warning("Someone tried to force invalid Aspect!");
return response;
}
if (!entityPrototype.TryGetComponent<AspectComponent>(out _))
{
var errStr = $"Aspect with ID '{aspectProtoId}' not found or does not have an AspectComponent!";
_sawmill.Error(errStr);
return errStr;
}
if (ForcedAspect == aspectProtoId)
{
var errStr = $"Aspect with ID '{aspectProtoId}' already forced!";
_sawmill.Error(errStr);
return errStr;
}
SetForcedAspect(aspectProtoId);
var str = $"Successfully forced Aspect with ID '{aspectProtoId}'";
_sawmill.Info(str);
return str;
}
/// <summary>
/// DeForces a ForcedAspect, if any.
/// </summary>
public string DeForceAspect()
{
string response;
if (ForcedAspect != null)
{
response = $"DeForced Aspect : {ForcedAspect}";
SetForcedAspect(null);
}
else
{
response = "How to DeForce if no aspect forced, retard..";
}
return response;
}
/// <summary>
/// Retrieves information about the currently forced aspect, if any.
/// </summary>
public string GetForcedAspect()
{
var response = ForcedAspect != null
? $"Current forced Aspect : {ForcedAspect}"
: "No forced Aspects";
return response;
}
/// <summary>
/// Retrieves a list of IDs for all available aspects.
/// </summary>
/// <returns>A list of IDs for available aspects.</returns>
public List<string> GetAllAspectIds()
{
var availableAspects = AllAspects();
var aspectIds = new List<string>();
foreach (var (proto, aspect) in availableAspects)
{
var initialAspectId = proto.ID;
var returnedAspectId = proto.ID;
if (aspect.Requires != null)
{
returnedAspectId += $" (Requires: {aspect.Requires})";
}
if (aspect.IsForbidden)
{
returnedAspectId += " (ShitSpawn)";
}
if (ForcedAspect == initialAspectId)
{
returnedAspectId += " (Forced)";
}
if (CheckIfAspectAlreadyRunning(initialAspectId))
{
returnedAspectId += " (Already Running)";
}
aspectIds.Add(returnedAspectId);
}
return aspectIds;
}
/// <summary>
/// Runs the specified aspect and adds it as a game rule.
/// </summary>
/// <param name="aspectId">The ID of the aspect to run.</param>
public string RunAspect(string aspectId)
{
if (!AspectsEnabled)
{
var disabledStr = "Aspects disabled.";
_sawmill.Warning("Someone tried to run aspects when they disabled!");
return disabledStr;
}
if (!_prototype.TryIndex<EntityPrototype>(aspectId, out var entityPrototype))
{
var response = "Aspect not found. Can`t find proto";
_sawmill.Warning("Someone tried to run invalid Aspect!");
return response;
}
if (!entityPrototype.TryGetComponent<AspectComponent>(out var aspect))
{
var errStr = $"Aspect with ID '{aspectId}' not found or does not have an AspectComponent!";
_sawmill.Error(errStr);
return errStr;
}
if (CheckIfAspectAlreadyRunning(aspectId))
{
var alreadyRunningStr = $"Aspect '{aspectId}' is already running!";
_sawmill.Warning(alreadyRunningStr);
return alreadyRunningStr;
}
var ent = _gameTicker.AddGameRule(aspectId);
var str = $"Ran {aspect.Name ?? "Unnamed Aspect"} ({ToPrettyString(ent)})!!";
_sawmill.Info(str);
return str;
}
/// <summary>
/// Runs a random aspect and adds it as a game rule.
/// </summary>
public string RunRandomAspect()
{
if (!AspectsEnabled)
{
var disabledStr = "Aspects disabled.";
_sawmill.Warning("Someone tried to run aspects when they disabled!");
return disabledStr;
}
var randomAspect = PickRandomAspect();
if (randomAspect == null)
{
var errStr = "Oopsie, no valid aspects found! Sorry.";
_sawmill.Error(errStr);
return errStr;
}
var ent = _gameTicker.AddGameRule(randomAspect);
var str = $"Ran {ToPrettyString(ent)}!!";
_sawmill.Info(str);
return str;
}
#endregion
#region Helpers
/// <summary>
/// Picks a random aspect based on their weight.
/// </summary>
/// <param name="allowForbidden">Allow selecting forbidden aspects.</param>
/// <returns>The ID of the selected aspect or null if no aspect was selected.</returns>
private string? PickRandomAspect(bool allowForbidden = false)
{
var availableAspects = AllAspects();
_sawmill.Info($"Picking from {availableAspects.Count} total available aspects");
return FindAspect(availableAspects, allowForbidden);
}
/// <summary>
/// Finds a suitable aspect from the available aspects.
/// </summary>
/// <param name="availableAspects">A dictionary of available aspects.</param>
/// <param name="allowForbidden">Allow selecting forbidden aspects.</param>
/// <returns>The ID of the selected aspect or null if no aspect was found.</returns>
private string? FindAspect(Dictionary<EntityPrototype, AspectComponent> availableAspects, bool allowForbidden = false)
{
if (availableAspects.Count == 0)
{
_sawmill.Warning("No aspects were available to run!");
return null;
}
var sumOfWeights = 0;
foreach (var (_, aspect) in availableAspects)
{
if (!allowForbidden && aspect.IsForbidden)
{
continue;
}
sumOfWeights += (int)aspect.Weight;
}
sumOfWeights = _random.Next(sumOfWeights);
foreach (var (proto, aspect) in availableAspects)
{
if (!allowForbidden && aspect.IsForbidden)
{
continue;
}
if (CheckIfAspectAlreadyRunning(proto.ID))
{
continue;
}
sumOfWeights -= (int)aspect.Weight;
if (sumOfWeights <= 0)
{
return proto.ID;
}
}
_sawmill.Error("Aspect was not found after weighted pick process!");
return null;
}
/// <summary>
/// Checking if aspect is already running, needed to avoid repeating.
/// </summary>
private bool CheckIfAspectAlreadyRunning(string aspectId)
{
var activeRules = _gameTicker.GetActiveGameRules();
foreach (var gameRule in activeRules)
{
if (!HasComp<AspectComponent>(gameRule))
continue;
if (!TryComp<MetaDataComponent>(gameRule, out var metaDataComponent))
continue;
var runningAspectId = metaDataComponent.EntityPrototype?.ID;
if (runningAspectId == aspectId)
{
return true;
}
}
return false;
}
/// <summary>
/// Retrieves a dictionary of all available aspects from prototypes.
/// </summary>
/// <returns>A dictionary of available aspects.</returns>
private Dictionary<EntityPrototype, AspectComponent> AllAspects()
{
var allAspects = new Dictionary<EntityPrototype, AspectComponent>();
foreach (var prototype in _prototype.EnumeratePrototypes<EntityPrototype>())
{
if (prototype.Abstract)
continue;
if (!prototype.TryGetComponent<AspectComponent>(out var aspect))
continue;
allAspects.Add(prototype, aspect);
}
return allAspects;
}
#endregion
}
}