forked from space-syndicate/space-station-14
feat: add 11 copy-paste features from ss14-wega and ss14-wl
From ss14-wega (_Wega): - DeleteOnDrop: auto-delete items when dropped - FriendlyFaction: prevent friendly fire by faction - NullRod: holy weapon that removes magic - EdibleMatter: edible entity component - Ghost Respawn: allow ghosts to respawn to lobby - Barks: NPC voice sounds system (99 audio files) From ss14-wl (_WL): - Day/Night Cycle: automatic lighting cycle for maps - Sleep on Buckle: sleep action when buckled - Height System: tall entities become large items - Freeze Component: freeze entities at high cold damage - Suckable Food: mouth-slot consumables (lollipops, gum, etc.) - GolemHeat: bonus feature (heat mechanics for golems) Includes: - 34 C# files - 99 audio files - 68 texture files - 9 prototype files - 2 locale files - WegaCVars configuration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
104
Content.Client/_Wega/Barks/BarkSystem.cs
Normal file
104
Content.Client/_Wega/Barks/BarkSystem.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using Content.Client.Audio;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Speech.Synthesis;
|
||||
using Robust.Client.Audio;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
using Content.Shared.SoundInsolation;
|
||||
|
||||
namespace Content.Client.Speech.Synthesis.System;
|
||||
|
||||
/// <summary>
|
||||
/// Система отвечающая за прогрышь звука для каждого калиента
|
||||
/// </summary>
|
||||
public sealed class BarkSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly SoundInsulationSystem _soundInsulation = default!;
|
||||
|
||||
private const float MinimalVolume = -10f;
|
||||
private const float WhisperFade = 4f;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeNetworkEvent<PlayBarkEvent>(OnPlayBark);
|
||||
}
|
||||
|
||||
public void RequestPreviewBark(string barkVoiceId)
|
||||
{
|
||||
RaiseNetworkEvent(new RequestPreviewBarkEvent(barkVoiceId));
|
||||
}
|
||||
|
||||
private void OnPlayBark(PlayBarkEvent ev)
|
||||
{
|
||||
var sourceEntity = _entityManager.GetEntity(ev.SourceUid);
|
||||
if (!_entityManager.EntityExists(sourceEntity) || _entityManager.Deleted(sourceEntity) || !HasComp<TransformComponent>(sourceEntity))
|
||||
return;
|
||||
|
||||
float volumeMultiplier = 1f;
|
||||
if (_player.LocalEntity != null && HasComp<TransformComponent>(_player.LocalEntity.Value))
|
||||
{
|
||||
var sourceTransform = Transform(sourceEntity);
|
||||
var playerTransform = Transform(_player.LocalEntity.Value);
|
||||
|
||||
if (sourceTransform.Coordinates.TryDistance(EntityManager, playerTransform.Coordinates, out var distance) &&
|
||||
distance > SharedChatSystem.VoiceRange)
|
||||
return;
|
||||
|
||||
var insulation = _soundInsulation.GetSoundInsulation(sourceEntity, _player.LocalEntity.Value);
|
||||
if (insulation >= 0.95f)
|
||||
return;
|
||||
|
||||
if (insulation > 0.1f && insulation < 0.95f)
|
||||
{
|
||||
volumeMultiplier = 1f - MathHelper.Lerp(0.1f, 0.9f, insulation);
|
||||
volumeMultiplier = Math.Clamp(volumeMultiplier, 0.1f, 0.9f);
|
||||
}
|
||||
}
|
||||
|
||||
var userVolume = _cfg.GetCVar(WegaCVars.BarksVolume);
|
||||
var baseVolume = SharedAudioSystem.GainToVolume(userVolume * ContentAudioSystem.BarksMultiplier);
|
||||
|
||||
float volume = MinimalVolume + baseVolume * volumeMultiplier;
|
||||
if (ev.Obfuscated)
|
||||
volume -= WhisperFade;
|
||||
|
||||
var audioParams = new AudioParams
|
||||
{
|
||||
Volume = volume,
|
||||
Variation = 0.125f
|
||||
};
|
||||
|
||||
int messageLength = ev.Message.Length;
|
||||
float totalDuration = messageLength * 0.05f;
|
||||
float soundInterval = 0.15f / ev.PlaybackSpeed;
|
||||
|
||||
int soundCount = (int)(totalDuration / soundInterval);
|
||||
soundCount = Math.Max(soundCount, 1);
|
||||
|
||||
var audioResource = new AudioResource();
|
||||
audioResource.Load(IoCManager.Instance!, new ResPath(ev.SoundPath));
|
||||
|
||||
var soundSpecifier = new ResolvedPathSpecifier(ev.SoundPath);
|
||||
|
||||
for (int i = 0; i < soundCount; i++)
|
||||
{
|
||||
Timer.Spawn(TimeSpan.FromSeconds(i * soundInterval), () =>
|
||||
{
|
||||
if (!_entityManager.EntityExists(sourceEntity) || _entityManager.Deleted(sourceEntity))
|
||||
return;
|
||||
|
||||
_audio.PlayEntity(audioResource.AudioStream, sourceEntity, soundSpecifier, audioParams);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
63
Content.Client/_Wega/Barks/HumanoidProfileEditor.Barks.cs
Normal file
63
Content.Client/_Wega/Barks/HumanoidProfileEditor.Barks.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System.Linq;
|
||||
using Content.Client.Lobby;
|
||||
using Content.Shared.Speech.Synthesis;
|
||||
using Content.Client.Speech.Synthesis.System;
|
||||
|
||||
namespace Content.Client.Lobby.UI;
|
||||
|
||||
public sealed partial class HumanoidProfileEditor
|
||||
{
|
||||
private List<BarkPrototype> _barkVoiceList = new();
|
||||
|
||||
private void InitializeBarkVoice()
|
||||
{
|
||||
_barkVoiceList = _prototypeManager
|
||||
.EnumeratePrototypes<BarkPrototype>()
|
||||
.Where(o => o.RoundStart)
|
||||
.OrderBy(o => Loc.GetString(o.Name))
|
||||
.ToList();
|
||||
|
||||
BarkVoiceButton.OnItemSelected += args =>
|
||||
{
|
||||
BarkVoiceButton.SelectId(args.Id);
|
||||
SetBarkVoice(_barkVoiceList[args.Id].ID);
|
||||
};
|
||||
|
||||
BarkVoicePlayButton.OnPressed += _ => PlayPreviewBark();
|
||||
}
|
||||
|
||||
private void UpdateBarkVoicesControls()
|
||||
{
|
||||
if (Profile is null)
|
||||
return;
|
||||
|
||||
BarkVoiceButton.Clear();
|
||||
|
||||
var firstVoiceChoiceId = 1;
|
||||
for (var i = 0; i < _barkVoiceList.Count; i++)
|
||||
{
|
||||
var voice = _barkVoiceList[i];
|
||||
|
||||
var name = Loc.GetString(voice.Name);
|
||||
BarkVoiceButton.AddItem(name, i);
|
||||
|
||||
if (firstVoiceChoiceId == 1)
|
||||
firstVoiceChoiceId = i;
|
||||
}
|
||||
|
||||
var voiceChoiceId = _barkVoiceList.FindIndex(x => x.ID == Profile.BarkVoice);
|
||||
if (!BarkVoiceButton.TrySelectId(voiceChoiceId) &&
|
||||
BarkVoiceButton.TrySelectId(firstVoiceChoiceId))
|
||||
{
|
||||
SetBarkVoice(_barkVoiceList[firstVoiceChoiceId].ID);
|
||||
}
|
||||
}
|
||||
|
||||
private void PlayPreviewBark()
|
||||
{
|
||||
if (Profile is null)
|
||||
return;
|
||||
|
||||
_entManager.System<BarkSystem>().RequestPreviewBark(Profile.BarkVoice);
|
||||
}
|
||||
}
|
||||
20
Content.Client/_Wega/Ghost/GhostRespawnSystem.cs
Normal file
20
Content.Client/_Wega/Ghost/GhostRespawnSystem.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Content.Shared.Wega.Ghost.Respawn;
|
||||
|
||||
namespace Content.Client.Wega.Ghost.Respawn;
|
||||
|
||||
public sealed class GhostRespawnSystem : EntitySystem
|
||||
{
|
||||
public TimeSpan? GhostRespawnTime { get; private set; }
|
||||
public event Action? GhostRespawn;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeNetworkEvent<GhostRespawnEvent>(OnGhostRespawnReset);
|
||||
}
|
||||
|
||||
private void OnGhostRespawnReset(GhostRespawnEvent e)
|
||||
{
|
||||
GhostRespawnTime = e.Time;
|
||||
GhostRespawn?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Content.Server._WL.AddHeightItem;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class AddHeightItemComponent : Component
|
||||
{
|
||||
|
||||
}
|
||||
43
Content.Server/_WL/AddHeightItem/AddHeightItemSystem.cs
Normal file
43
Content.Server/_WL/AddHeightItem/AddHeightItemSystem.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using Content.Server.Resist;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Item;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._WL.AddHeightItem
|
||||
{
|
||||
public sealed partial class AddHeightItemSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedItemSystem _item = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<AddHeightItemComponent, ComponentInit>(OnADHI);
|
||||
}
|
||||
/// <summary>
|
||||
/// Add item component depending on height
|
||||
/// </summary>
|
||||
private void OnADHI(EntityUid uid, AddHeightItemComponent com, ComponentInit args)
|
||||
{
|
||||
if (!TryComp<HumanoidAppearanceComponent>(uid, out var humanoid))
|
||||
return;
|
||||
|
||||
if (!_proto.TryIndex(humanoid.Species, out var speciesProto))
|
||||
return;
|
||||
|
||||
if (speciesProto.MaxItemHeight >= humanoid.Height)
|
||||
{
|
||||
var size1 = "Ginormous";
|
||||
|
||||
var item = EnsureComp<ItemComponent>(uid);
|
||||
_item.SetSize(uid, size1, item);
|
||||
|
||||
EnsureComp<MultiHandedItemComponent>(uid);
|
||||
|
||||
var escape = EnsureComp<CanEscapeInventoryComponent>(uid);
|
||||
escape.BaseResistTime = 1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
127
Content.Server/_WL/Administration/Commands/DayNightCommand.cs
Normal file
127
Content.Server/_WL/Administration/Commands/DayNightCommand.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using Content.Server._WL.DayNight;
|
||||
using Content.Server.Administration;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Map;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Content.Server._WL.Administration.Commands
|
||||
{
|
||||
[AdminCommand(AdminFlags.Mapping)]
|
||||
public sealed partial class DayNightCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
[Dependency] private readonly IMapManager _mapMan = default!;
|
||||
|
||||
public override string Command => "daynight";
|
||||
public override string Description
|
||||
=>
|
||||
"""
|
||||
Добавляет карте смену дня и ночи.
|
||||
Желательно, чтоб это была планета.
|
||||
Также желательно, чтобы эта команда использовалась только с неинициализированными картами.
|
||||
""";
|
||||
|
||||
public override string Help => "daynight <mapId> <fullCycle> <dayRatio> <nightRatio> <dayColor> <nightColor>";
|
||||
|
||||
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
|
||||
{
|
||||
if (args.Length == 1)
|
||||
{
|
||||
return CompletionResult.FromHintOptions(_mapMan.GetAllMapIds().Select(x => x.ToString()), "MapId");
|
||||
}
|
||||
else if (args.Length == 2)
|
||||
{
|
||||
return CompletionResult.FromHint("FullCycle in seconds");
|
||||
}
|
||||
else if (args.Length == 3)
|
||||
{
|
||||
return CompletionResult.FromHint("Day ratio an integer");
|
||||
}
|
||||
else if (args.Length == 4)
|
||||
{
|
||||
return CompletionResult.FromHint("Night ration an integer");
|
||||
}
|
||||
else if (args.Length == 5)
|
||||
{
|
||||
return CompletionResult.FromHint("Day Hex");
|
||||
}
|
||||
else if (args.Length == 6)
|
||||
{
|
||||
return CompletionResult.FromHint("Night Hex");
|
||||
}
|
||||
|
||||
return CompletionResult.Empty;
|
||||
}
|
||||
|
||||
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length != 6 && args.Length != 4)
|
||||
{
|
||||
shell.WriteError(LocalizationManager.GetString("shell-wrong-arguments-number"));
|
||||
return;
|
||||
}
|
||||
|
||||
var mapSys = _entMan.System<MapSystem>();
|
||||
|
||||
if (!int.TryParse(args[0], out var mapIntegerId))
|
||||
{
|
||||
shell.WriteError("MapId должно быть числом!");
|
||||
return;
|
||||
}
|
||||
|
||||
var mapId = new MapId(mapIntegerId);
|
||||
|
||||
if (!mapSys.MapExists(mapId))
|
||||
{
|
||||
shell.WriteError($"Карты с ID равнм {mapIntegerId} не существует!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(args[1], out var fullCycleTime) || fullCycleTime <= 0)
|
||||
{
|
||||
shell.WriteError("fullCycleTime должен представлять целое число большее нуля!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(args[2], out var dayRatio) || dayRatio <= 0)
|
||||
{
|
||||
shell.WriteError("dayRatio должен представлять целое число большее нуля!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(args[3], out var nightRatio) || nightRatio <= 0)
|
||||
{
|
||||
shell.WriteError("nightRatio должен представлять целое число большее нуля!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mapSys.TryGetMap(mapId, out var mapUid) || mapUid == null)
|
||||
{
|
||||
shell.WriteError("Неизвестная ошибка.");
|
||||
return;
|
||||
}
|
||||
|
||||
var dayNnightComp = _entMan.EnsureComponent<DayNightComponent>(mapUid.Value);
|
||||
|
||||
dayNnightComp.DayNightRatio = new Vector2(dayRatio, nightRatio);
|
||||
dayNnightComp.FullCycle = TimeSpan.FromSeconds(fullCycleTime);
|
||||
|
||||
if (args.Length != 6)
|
||||
return;
|
||||
|
||||
var dayColor = Color.TryFromHex(args[4]);
|
||||
var nightColor = Color.TryFromHex(args[5]);
|
||||
if (dayColor != null)
|
||||
{
|
||||
dayNnightComp.DayHex = args[4];
|
||||
}
|
||||
if (nightColor != null)
|
||||
{
|
||||
dayNnightComp.NightHex = args[5];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Content.Server/_WL/DayNight/DayNightComponent.cs
Normal file
30
Content.Server/_WL/DayNight/DayNightComponent.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Content.Server._WL.DayNight
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed partial class DayNightComponent : Component
|
||||
{
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[DataField]
|
||||
public TimeSpan FullCycle = TimeSpan.FromSeconds(1200);
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[DataField("ratio")]
|
||||
public Vector2 DayNightRatio = new(6, 4);
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[DataField("day")]
|
||||
public string DayHex = "#F7CA68FF";
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
[DataField("night")]
|
||||
public string NightHex = "#0f1026";
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public bool WasInit = false;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public TimeSpan NextCycle;
|
||||
}
|
||||
}
|
||||
97
Content.Server/_WL/DayNight/DayNightSystem.cs
Normal file
97
Content.Server/_WL/DayNight/DayNightSystem.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Content.Server._WL.DayNight
|
||||
{
|
||||
public sealed partial class DayNightSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTime = default!;
|
||||
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
||||
[Dependency] private readonly MapSystem _mapSys = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DayNightComponent, MapInitEvent>(OnMapInit, after: [typeof(SharedMapSystem)]);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<DayNightComponent>();
|
||||
while (query.MoveNext(out var map, out var dayNightComp))
|
||||
{
|
||||
if (!TryComp<MapLightComponent>(map, out var mapLightComp))
|
||||
continue;
|
||||
|
||||
if (!TryComp<MapComponent>(map, out var mapComponent))
|
||||
continue;
|
||||
|
||||
if (!dayNightComp.WasInit || mapComponent.MapPaused)
|
||||
continue;
|
||||
|
||||
if (_gameTime.CurTime >= dayNightComp.NextCycle)
|
||||
dayNightComp.NextCycle += dayNightComp.FullCycle;
|
||||
|
||||
var color = CalculateColor(
|
||||
_gameTime.CurTime,
|
||||
dayNightComp.FullCycle,
|
||||
dayNightComp.NextCycle,
|
||||
Color.FromHex(dayNightComp.DayHex),
|
||||
Color.FromHex(dayNightComp.NightHex),
|
||||
dayNightComp.DayNightRatio);
|
||||
|
||||
if (color == mapLightComp.AmbientLightColor) //Оптимизация для случаев, если цикл дня и ночи огромен.
|
||||
continue;
|
||||
|
||||
_mapSys.SetAmbientLight(mapComponent.MapId, color);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMapInit(EntityUid station, DayNightComponent comp, MapInitEvent args)
|
||||
{
|
||||
if (!TryComp<MapComponent>(station, out var mapComponent))
|
||||
return;
|
||||
|
||||
_mapSys.SetAmbientLight(mapComponent.MapId, Color.FromHex(comp.DayHex));
|
||||
comp.NextCycle = _gameTime.CurTime + comp.FullCycle;
|
||||
comp.WasInit = true;
|
||||
}
|
||||
|
||||
public static Color CalculateColor(TimeSpan currentTime, TimeSpan fullCycle, TimeSpan nextCycle, Color dayColor, Color nightColor, Vector2 dayNightRatio)
|
||||
{
|
||||
currentTime = currentTime - (nextCycle - fullCycle);
|
||||
|
||||
var pair = dayNightRatio.X + dayNightRatio.Y;
|
||||
|
||||
var dayTime = fullCycle.TotalMinutes / pair * dayNightRatio.X;
|
||||
var nightTime = fullCycle.TotalMinutes / pair * dayNightRatio.Y;
|
||||
|
||||
var isDay = currentTime.TotalMinutes <= dayTime;
|
||||
|
||||
var filledPercentage = isDay
|
||||
? currentTime.TotalMinutes / dayTime
|
||||
: (currentTime.TotalMinutes - dayTime) / nightTime;
|
||||
|
||||
var r = isDay
|
||||
? dayColor.R + (nightColor.R - dayColor.R) * filledPercentage
|
||||
: nightColor.R + (dayColor.R - nightColor.R) * filledPercentage;
|
||||
var g = isDay
|
||||
? dayColor.G + (nightColor.G - dayColor.G) * filledPercentage
|
||||
: nightColor.G + (dayColor.G - nightColor.G) * filledPercentage;
|
||||
var b = isDay
|
||||
? dayColor.B + (nightColor.B - dayColor.B) * filledPercentage
|
||||
: nightColor.B + (dayColor.B - nightColor.B) * filledPercentage;
|
||||
|
||||
var result = new Color((float) r, (float) g, (float) b);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._WL.Destructible.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed partial class FrozenComponent : Component
|
||||
{
|
||||
[DataField] public LocId FrozenPrefix = "frozen-entity-prefix";
|
||||
|
||||
[DataField] public LocId FrozenPopup = "frozen-entity-popup";
|
||||
[DataField] public LocId FrozenHealthString = "frozen-entity-health-string";
|
||||
|
||||
[DataField] public string BaseName;
|
||||
[DataField] public Color BaseSkinColor;
|
||||
|
||||
[DataField] public ProtoId<DamageTypePrototype> FrozenDamage = "Cold";
|
||||
}
|
||||
}
|
||||
62
Content.Server/_WL/Destructible/Systems/FrozenSystem.cs
Normal file
62
Content.Server/_WL/Destructible/Systems/FrozenSystem.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using Content.Server._WL.Destructible.Components;
|
||||
using Content.Server.Humanoid;
|
||||
using Content.Shared.Cloning;
|
||||
using Content.Shared.Cloning.Events;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Events;
|
||||
using Content.Shared.Damage.Systems;
|
||||
using Content.Shared.HealthExaminable;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Content.Shared.Rejuvenate;
|
||||
|
||||
namespace Content.Server._WL.Destructible.Systems
|
||||
{
|
||||
public sealed partial class FrozenSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly HumanoidAppearanceSystem _appearance = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<FrozenComponent, RefreshNameModifiersEvent>(OnRefreshName);
|
||||
SubscribeLocalEvent<FrozenComponent, BeforeDamageChangedEvent>(BeforeDamageChanged);
|
||||
SubscribeLocalEvent<FrozenComponent, CloningEvent>(OnClone);
|
||||
SubscribeLocalEvent<FrozenComponent, HealthBeingExaminedEvent>(OnHealthExamine);
|
||||
SubscribeLocalEvent<FrozenComponent, RejuvenateEvent>(OnRejuvenate);
|
||||
}
|
||||
|
||||
private void OnRefreshName(EntityUid ent, FrozenComponent comp, RefreshNameModifiersEvent args)
|
||||
{
|
||||
args.AddModifier(comp.FrozenPrefix);
|
||||
args.AddModifier(comp.BaseName, int.MinValue);
|
||||
}
|
||||
|
||||
private void BeforeDamageChanged(EntityUid ent, FrozenComponent comp, ref BeforeDamageChangedEvent args)
|
||||
{
|
||||
args.Damage.DamageDict[comp.FrozenDamage.Id] = 0f;
|
||||
args.Damage.TrimZeros();
|
||||
}
|
||||
|
||||
private void OnClone(EntityUid ent, FrozenComponent comp, ref CloningEvent args)
|
||||
{
|
||||
var target = args.CloneUid;
|
||||
_metaData.SetEntityName(target, comp.BaseName, raiseEvents: true);
|
||||
_appearance.SetSkinColor(target, comp.BaseSkinColor);
|
||||
}
|
||||
|
||||
private void OnHealthExamine(EntityUid ent, FrozenComponent comp, HealthBeingExaminedEvent args)
|
||||
{
|
||||
args.Message.AddMarkupOrThrow("\n" + Loc.GetString(comp.FrozenHealthString));
|
||||
}
|
||||
|
||||
private void OnRejuvenate(EntityUid ent, FrozenComponent comp, RejuvenateEvent args)
|
||||
{
|
||||
_metaData.SetEntityName(ent, comp.BaseName, raiseEvents: true);
|
||||
_appearance.SetSkinColor(ent, comp.BaseSkinColor);
|
||||
|
||||
RemComp<FrozenComponent>(ent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using Content.Server._WL.Destructible.Components;
|
||||
using Content.Server.Destructible;
|
||||
using Content.Server.Destructible.Thresholds.Behaviors;
|
||||
using Content.Server.Humanoid;
|
||||
using Content.Shared.Atmos.Rotting;
|
||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.NameModifier.Components;
|
||||
using Content.Shared.NameModifier.EntitySystems;
|
||||
using Content.Shared.Popups;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Enums;
|
||||
|
||||
namespace Content.Server._WL.Destructible.Thresholds.Behaviors
|
||||
{
|
||||
[UsedImplicitly]
|
||||
[DataDefinition]
|
||||
public sealed partial class FrozeBodyBehavior : IThresholdBehavior
|
||||
{
|
||||
public const float InterpolateStrength = 0.88f;
|
||||
public static readonly Color InterpolateColor = Color.CadetBlue;
|
||||
|
||||
public void Execute(EntityUid bodyId, DestructibleSystem system, EntityUid? cause = null)
|
||||
{
|
||||
var entMan = system.EntityManager;
|
||||
var humanoidAppearanceSys = entMan.System<HumanoidAppearanceSystem>();
|
||||
var transformSys = entMan.System<TransformSystem>();
|
||||
var popupSys = entMan.System<SharedPopupSystem>();
|
||||
var metaDataSys = entMan.System<MetaDataSystem>();
|
||||
|
||||
var frozenComp = entMan.EnsureComponent<FrozenComponent>(bodyId);
|
||||
|
||||
//Обновляем цвет кожи
|
||||
if (!entMan.TryGetComponent<HumanoidAppearanceComponent>(bodyId, out var humanoidAppearnceComp))
|
||||
return;
|
||||
|
||||
var curColor = humanoidAppearnceComp.SkinColor;
|
||||
frozenComp.BaseSkinColor = curColor;
|
||||
|
||||
humanoidAppearanceSys.SetSkinColor(
|
||||
bodyId,
|
||||
Color.InterpolateBetween(curColor, InterpolateColor, InterpolateStrength),
|
||||
sync: true,
|
||||
verify: false
|
||||
);
|
||||
|
||||
//Устанавливаем префикс
|
||||
var baseName = Identity.Name(bodyId, entMan);
|
||||
frozenComp.BaseName = baseName;
|
||||
|
||||
var genderString = humanoidAppearnceComp.Gender switch
|
||||
{
|
||||
Gender.Male => "male",
|
||||
Gender.Female => "female",
|
||||
_ => "other"
|
||||
};
|
||||
|
||||
var newName = $"{Loc.GetString(frozenComp.FrozenPrefix, ("gender", genderString))} {baseName}";
|
||||
|
||||
metaDataSys.SetEntityName(bodyId, newName);
|
||||
|
||||
//Запрещаем хил тела и разрешаем клонирование, убрав компонент гниения
|
||||
entMan.RemoveComponent<PerishableComponent>(bodyId);
|
||||
entMan.RemoveComponent<InjectableSolutionComponent>(bodyId);
|
||||
|
||||
//Поп-ап
|
||||
var msg = Loc.GetString(frozenComp.FrozenPopup,
|
||||
("name", baseName),
|
||||
("gender", genderString));
|
||||
|
||||
popupSys.PopupCoordinates(
|
||||
msg,
|
||||
transformSys.GetMoverCoordinates(bodyId),
|
||||
Robust.Shared.Player.Filter.Pvs(bodyId),
|
||||
true,
|
||||
PopupType.LargeCaution);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Content.Server._WL.Nutrition.Components;
|
||||
[RegisterComponent]
|
||||
public sealed partial class GolemHeatComponent : Component
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Content.Server._WL.Nutrition.Systems;
|
||||
using Content.Shared.Clothing.Components;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._WL.Nutrition.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class SuckableFoodComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public string Solution { get; set; } = "food";
|
||||
|
||||
/// <summary>
|
||||
/// Количество поглощаемой из контейнера жидкости в секунду.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public FixedPoint2 DissolveAmount { get; set; } = FixedPoint2.New(0.05f);
|
||||
|
||||
/// <summary>
|
||||
/// Не указывайте сущности в прототипе, у которых есть <see cref="SuckableFoodComponent"/>, иначе будет runtime-ошибочка.
|
||||
/// </summary>
|
||||
[DataField("entityOnDissolve")]
|
||||
public EntProtoId<ClothingComponent>? EquippedEntityOnDissolve { get; set; }
|
||||
|
||||
[DataField]
|
||||
public ComponentRegistry? ComponentsOverride { get; set; }
|
||||
|
||||
[DataField]
|
||||
public bool CanSuck { get; set; } = true;
|
||||
|
||||
[DataField]
|
||||
public bool DeleteOnEmpty { get; set; } = true;
|
||||
|
||||
public bool IsSucking => SuckingEntity != null && CanSuck;
|
||||
|
||||
[Access(typeof(SuckableFoodSystem))]
|
||||
public EntityUid? SuckingEntity;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Content.Server._WL.Nutrition.Components;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
namespace Content.Server._WL.Nutrition.Events;
|
||||
|
||||
public sealed partial class SuckableFoodDissolvedEvent : EntityEventArgs
|
||||
{
|
||||
public Entity<SuckableFoodComponent> Suckable { get; }
|
||||
public BaseContainer Container { get; }
|
||||
|
||||
public EntityUid Sucker { get; }
|
||||
|
||||
public SuckableFoodDissolvedEvent(Entity<SuckableFoodComponent> suckable, BaseContainer container, EntityUid sucker)
|
||||
{
|
||||
Suckable = suckable;
|
||||
Container = container;
|
||||
Sucker = sucker;
|
||||
}
|
||||
}
|
||||
57
Content.Server/_WL/Nutrition/Systems/GolemHeatSystem.cs
Normal file
57
Content.Server/_WL/Nutrition/Systems/GolemHeatSystem.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Content.Server._WL.Nutrition.Components;
|
||||
using Content.Server.Temperature.Components;
|
||||
using Content.Server.Temperature.Systems;
|
||||
using Content.Shared.Body.Systems;
|
||||
using Content.Shared.Temperature.Components;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Nutrition.Components;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Server._WL.Nutrition.Systems;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class GolemHeatSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _systemManager = default!;
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _movement = default!;
|
||||
[Dependency] private readonly SharedBodySystem _bodySystem = default!;
|
||||
|
||||
private const int HeatChangeAmount = 4000;
|
||||
private const float SprintSpeed = 3.24f;
|
||||
private const float WalkSpeed = 1.8f;
|
||||
private const int Acceleration = 20;
|
||||
|
||||
private void ChangeGolemHeat(EntityUid uid)
|
||||
{
|
||||
if (!_entityManager.TryGetComponent(uid, out HungerComponent? hungerComponent))
|
||||
return;
|
||||
|
||||
if (hungerComponent.CurrentThreshold != HungerThreshold.Overfed)
|
||||
{
|
||||
_bodySystem.UpdateMovementSpeed(uid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TryComp(uid, out TemperatureComponent? temperatureComponent))
|
||||
return;
|
||||
|
||||
var temperatureSystem = _systemManager.GetEntitySystem<TemperatureSystem>();
|
||||
temperatureSystem.ChangeHeat(uid, HeatChangeAmount, true, temperatureComponent);
|
||||
|
||||
var movementSpeed = EnsureComp<MovementSpeedModifierComponent>(uid);
|
||||
_movement.ChangeBaseSpeed(uid, WalkSpeed, SprintSpeed, Acceleration, movementSpeed);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<GolemHeatComponent>();
|
||||
while (query.MoveNext(out var uid, out var comp))
|
||||
{
|
||||
ChangeGolemHeat(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
189
Content.Server/_WL/Nutrition/Systems/SuckableFoodSystem.cs
Normal file
189
Content.Server/_WL/Nutrition/Systems/SuckableFoodSystem.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
using Content.Server._WL.Nutrition.Components;
|
||||
using Content.Server._WL.Nutrition.Events;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||
using Content.Server.Forensics;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.Nutrition.EntitySystems;
|
||||
using Content.Shared.Prototypes;
|
||||
using Robust.Server.Containers;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Content.Server._WL.Nutrition.Systems;
|
||||
|
||||
public sealed partial class SuckableFoodSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ReactiveSystem _reactiveSystem = default!;
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
|
||||
[Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!;
|
||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||
[Dependency] private readonly ContainerSystem _container = default!;
|
||||
[Dependency] private readonly ForensicsSystem _forensics = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
||||
[Dependency] private readonly IComponentFactory _componentFactory = default!;
|
||||
[Dependency] private readonly FlavorProfileSystem _flavor = default!;
|
||||
|
||||
private const float UpdatePeriod = 2f; // in seconds
|
||||
private float _updateTimer = 0f;
|
||||
|
||||
private static readonly LocId PutInMouthLoc = "food-sweets-put-in-mouth-popup-message";
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SuckableFoodComponent, GotEquippedEvent>(OnEquip);
|
||||
SubscribeLocalEvent<SuckableFoodComponent, GotUnequippedEvent>(ResetSucker);
|
||||
|
||||
SubscribeLocalEvent<SuckableFoodComponent, ComponentShutdown>(ResetSucker);
|
||||
|
||||
SubscribeLocalEvent<SuckableFoodComponent, SuckableFoodDissolvedEvent>(OnDissolved);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
_updateTimer += frameTime;
|
||||
|
||||
var isNewLoop = _updateTimer >= UpdatePeriod;
|
||||
|
||||
var query = EntityQueryEnumerator<SuckableFoodComponent, SolutionContainerManagerComponent>();
|
||||
while (query.MoveNext(out var food, out var suckableComp, out var solContainerManComp))
|
||||
{
|
||||
if (!Exists(suckableComp.SuckingEntity))
|
||||
{
|
||||
suckableComp.SuckingEntity = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isNewLoop)
|
||||
{
|
||||
var sucker = suckableComp.SuckingEntity.Value;
|
||||
|
||||
if (!TryComp<BloodstreamComponent>(sucker, out var bloodstreamComp))
|
||||
continue;
|
||||
|
||||
suckableComp.CanSuck = _mobState.IsAlive(sucker); // TODO: вынести в отдельное событие
|
||||
if (!suckableComp.IsSucking)
|
||||
continue;
|
||||
|
||||
if (!EnsureSolutionEntity((food, suckableComp, solContainerManComp), out var solutionEntity, out var solution))
|
||||
continue;
|
||||
|
||||
var dissolvedSol = _solutionContainerSystem.SplitSolution(solutionEntity.Value, suckableComp.DissolveAmount * UpdatePeriod);
|
||||
|
||||
if (solution.Volume == FixedPoint2.Zero)
|
||||
{
|
||||
if (_container.TryGetContainingContainer(food, out var container))
|
||||
{
|
||||
var ev = new SuckableFoodDissolvedEvent((food, suckableComp), container, sucker);
|
||||
|
||||
RaiseLocalEvent(food, ev);
|
||||
RaiseLocalEvent(ev);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
_reactiveSystem.DoEntityReaction(sucker, dissolvedSol, ReactionMethod.Ingestion);
|
||||
_bloodstreamSystem.TryAddToChemicals((sucker, bloodstreamComp), dissolvedSol);
|
||||
}
|
||||
}
|
||||
|
||||
if (isNewLoop)
|
||||
_updateTimer -= UpdatePeriod;
|
||||
}
|
||||
|
||||
public void SetState(Entity<SuckableFoodComponent> foodEnt, EntityUid? sucker)
|
||||
{
|
||||
var (food, comp) = foodEnt;
|
||||
|
||||
comp.SuckingEntity = sucker;
|
||||
}
|
||||
|
||||
public bool EnsureSolutionEntity(
|
||||
Entity<SuckableFoodComponent, SolutionContainerManagerComponent?> foodEnt,
|
||||
[NotNullWhen(true)] out Entity<SolutionComponent>? solEnt,
|
||||
[NotNullWhen(true)] out Solution? solution)
|
||||
{
|
||||
solEnt = null;
|
||||
solution = null;
|
||||
|
||||
if (!Resolve(foodEnt, ref foodEnt.Comp2, false))
|
||||
return false;
|
||||
|
||||
if (!_solutionContainerSystem.EnsureSolutionEntity((foodEnt, foodEnt.Comp2), foodEnt.Comp1.Solution, out var ent))
|
||||
return false;
|
||||
|
||||
solEnt = ent;
|
||||
solution = ent.Value.Comp.Solution;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnEquip(EntityUid food, SuckableFoodComponent comp, GotEquippedEvent ev)
|
||||
{
|
||||
if (ev.SlotFlags.HasFlag(SlotFlags.MASK))
|
||||
_forensics.TransferDna(food, ev.Equipee);
|
||||
|
||||
SetState((food, comp), ev.Equipee);
|
||||
|
||||
if (!EnsureSolutionEntity((food, comp), out _, out var sol))
|
||||
return;
|
||||
|
||||
var flavor = _flavor.GetLocalizedFlavorsMessage(food, ev.Equipee, sol);
|
||||
if (string.IsNullOrEmpty(flavor))
|
||||
return;
|
||||
|
||||
var msg = Loc.GetString(PutInMouthLoc, ("flavor", flavor), ("entity", Identity.Name(food, EntityManager, ev.Equipee)));
|
||||
|
||||
_popup.PopupEntity(msg, ev.Equipee, Filter.Entities(ev.Equipee), false);
|
||||
}
|
||||
|
||||
private void ResetSucker<T>(EntityUid food, SuckableFoodComponent comp, T ev)
|
||||
{
|
||||
SetState((food, comp), null);
|
||||
}
|
||||
|
||||
|
||||
private void OnDissolved(EntityUid food, SuckableFoodComponent comp, SuckableFoodDissolvedEvent ev)
|
||||
{
|
||||
if (comp.DeleteOnEmpty)
|
||||
{
|
||||
_inventory.TryUnequip(ev.Sucker, ev.Container.ID, true, true);
|
||||
|
||||
var msg = Loc.GetString("food-sweets-got-dissolved-popup-message", ("entity", Identity.Name(food, EntityManager)));
|
||||
_popup.PopupEntity(msg, ev.Sucker, Filter.Entities(ev.Sucker), true, Shared.Popups.PopupType.Medium);
|
||||
|
||||
TryQueueDel(food);
|
||||
}
|
||||
|
||||
if (comp.EquippedEntityOnDissolve != null)
|
||||
{
|
||||
if (_protoMan.TryIndex(comp.EquippedEntityOnDissolve.Value, out var proto)
|
||||
&& proto.HasComponent<SuckableFoodComponent>(_componentFactory))
|
||||
{
|
||||
Log.Error($"EquippedEntityOnDissolve {comp.EquippedEntityOnDissolve.Value} on entity {ToPrettyString(food)} has {nameof(SuckableFoodComponent)}!");
|
||||
return;
|
||||
}
|
||||
|
||||
var ent = SpawnNextToOrDrop(comp.EquippedEntityOnDissolve.Value, ev.Sucker, overrides: comp.ComponentsOverride);
|
||||
_inventory.TryEquip(ev.Sucker, ent, ev.Container.ID, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Content.Server/_Wega/Barks/BarkSystem.cs
Normal file
60
Content.Server/_Wega/Barks/BarkSystem.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Speech.Synthesis;
|
||||
using Content.Shared.Speech.Synthesis.Components;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Content.Shared.Chat;
|
||||
|
||||
namespace Content.Server.Speech.Synthesis.System;
|
||||
|
||||
/// <summary>
|
||||
/// Обрабатывает барки для сущностей.
|
||||
/// </summary>
|
||||
public sealed class BarkSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<SpeechSynthesisComponent, EntitySpokeEvent>(OnEntitySpoke);
|
||||
|
||||
SubscribeNetworkEvent<RequestPreviewBarkEvent>(OnRequestPreviewBark);
|
||||
}
|
||||
|
||||
private void OnEntitySpoke(EntityUid uid, SpeechSynthesisComponent comp, EntitySpokeEvent args)
|
||||
{
|
||||
if (comp.VoicePrototypeId is null ||
|
||||
!_prototypeManager.TryIndex<BarkPrototype>(comp.VoicePrototypeId, out var barkProto) ||
|
||||
!_configurationManager.GetCVar(WegaCVars.BarksEnabled))
|
||||
return;
|
||||
|
||||
bool isObfuscated = args.ObfuscatedMessage != null;
|
||||
var sourceEntity = _entityManager.GetNetEntity(uid);
|
||||
var soundPath = barkProto.SoundFiles[new Random().Next(barkProto.SoundFiles.Count)];
|
||||
RaiseNetworkEvent(new PlayBarkEvent(soundPath, sourceEntity, args.Message, comp.PlaybackSpeed, isObfuscated));
|
||||
}
|
||||
|
||||
private async void OnRequestPreviewBark(RequestPreviewBarkEvent ev, EntitySessionEventArgs args)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ev.BarkVoiceId) || !_prototypeManager.TryIndex<BarkPrototype>(ev.BarkVoiceId, out var barkProto)
|
||||
|| !_configurationManager.GetCVar(WegaCVars.BarksEnabled))
|
||||
return;
|
||||
|
||||
var soundPath = barkProto.SoundFiles[new Random().Next(barkProto.SoundFiles.Count)];
|
||||
var soundSpecifier = new SoundPathSpecifier(soundPath);
|
||||
|
||||
var audioParams = new AudioParams
|
||||
{
|
||||
Pitch = 1.0f,
|
||||
Volume = 4f,
|
||||
Variation = 0.125f
|
||||
};
|
||||
|
||||
_audio.PlayGlobal(soundSpecifier, args.SenderSession, audioParams);
|
||||
}
|
||||
}
|
||||
67
Content.Server/_Wega/Commands/GhostRespawnCommand.cs
Normal file
67
Content.Server/_Wega/Commands/GhostRespawnCommand.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Mind;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Ghost;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Wega.Commands;
|
||||
|
||||
[AnyCommand()]
|
||||
public sealed class GhostRespawnCommand : IConsoleCommand
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||
|
||||
public string Command => "ghostrespawn";
|
||||
public string Description => "Allows the player to return to the lobby if they've been dead long enough, allowing re-entering the round AS ANOTHER CHARACTER.";
|
||||
public string Help => $"{Command}";
|
||||
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (!_configurationManager.GetCVar(WegaCVars.GhostRespawnEnabled))
|
||||
{
|
||||
shell.WriteLine("Respawning is disabled, ask an admin to respawn you.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (shell.Player is null)
|
||||
{
|
||||
shell.WriteLine("You cannot run this from the console!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (shell.Player.AttachedEntity is null)
|
||||
{
|
||||
shell.WriteLine("You cannot run this in the lobby, or without an entity.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_entityManager.TryGetComponent<GhostComponent>(shell.Player.AttachedEntity, out var ghost))
|
||||
{
|
||||
shell.WriteLine("You are not a ghost.");
|
||||
return;
|
||||
}
|
||||
|
||||
var mindSystem = _entityManager.EntitySysManager.GetEntitySystem<MindSystem>();
|
||||
if (!mindSystem.TryGetMind(shell.Player, out _, out _))
|
||||
{
|
||||
shell.WriteLine("You have no mind.");
|
||||
return;
|
||||
}
|
||||
var time = (_gameTiming.CurTime - ghost.TimeOfDeath);
|
||||
var respawnTime = _configurationManager.GetCVar(WegaCVars.GhostRespawnTime);
|
||||
|
||||
if (respawnTime > time.TotalSeconds)
|
||||
{
|
||||
shell.WriteLine($"You haven't been dead long enough. You have been dead {time.TotalSeconds} seconds of the required {respawnTime}.");
|
||||
return;
|
||||
}
|
||||
|
||||
var gameTicker = _entityManager.EntitySysManager.GetEntitySystem<GameTicker>();
|
||||
gameTicker.Respawn(shell.Player);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Friendly.Faction;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Weapons.Melee.Events;
|
||||
|
||||
namespace Content.Server.Friendly.Faction
|
||||
{
|
||||
public sealed partial class FriendlyFactionSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<FriendlyFactionComponent, MeleeHitEvent>(OnMeleeHit);
|
||||
}
|
||||
|
||||
private void OnMeleeHit(EntityUid uid, FriendlyFactionComponent component, MeleeHitEvent args)
|
||||
{
|
||||
if (!TryComp<FriendlyFactionComponent>(args.User, out _))
|
||||
return;
|
||||
|
||||
if (!args.HitEntities.Any())
|
||||
return;
|
||||
|
||||
foreach (var entity in args.HitEntities)
|
||||
{
|
||||
if (args.User == entity)
|
||||
continue;
|
||||
|
||||
if (!TryComp<MobStateComponent>(entity, out _))
|
||||
continue;
|
||||
|
||||
if (TryComp<FriendlyFactionComponent>(entity, out var friendlyFaction)
|
||||
&& friendlyFaction.Faction == component.Faction)
|
||||
{
|
||||
args.BonusDamage = -args.BaseDamage;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
76
Content.Server/_Wega/Ghost/GhostRespawnSystem.cs
Normal file
76
Content.Server/_Wega/Ghost/GhostRespawnSystem.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Content.Shared.Wega.Ghost.Respawn;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Wega.Ghost.Respawn;
|
||||
|
||||
public sealed class GhostRespawnSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
|
||||
private readonly Dictionary<ICommonSession, TimeSpan> _respawnResetTimes = [];
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<MobStateChangedEvent>(OnMobStateChanged);
|
||||
SubscribeLocalEvent<MindContainerComponent, MindRemovedMessage>(OnMindRemoved);
|
||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestartCleanup);
|
||||
_player.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||
}
|
||||
|
||||
private void OnMobStateChanged(MobStateChangedEvent e)
|
||||
{
|
||||
if (e.NewMobState != MobState.Dead)
|
||||
return;
|
||||
if (!_player.TryGetSessionByEntity(e.Target, out var session))
|
||||
return;
|
||||
ResetRespawnTime(e.Target, session);
|
||||
}
|
||||
|
||||
private void OnMindRemoved(EntityUid entity, MindContainerComponent component, MindRemovedMessage e)
|
||||
{
|
||||
if (e.Mind.Comp.UserId is null)
|
||||
return;
|
||||
if (TryComp<MobStateComponent>(entity, out var state) && state.CurrentState == MobState.Dead)
|
||||
return;
|
||||
if (!_player.TryGetSessionById(e.Mind.Comp.UserId.Value, out var session))
|
||||
return;
|
||||
|
||||
ResetRespawnTime(entity, session);
|
||||
}
|
||||
|
||||
private void OnRoundRestartCleanup(RoundRestartCleanupEvent e)
|
||||
{
|
||||
_respawnResetTimes.Clear();
|
||||
}
|
||||
|
||||
private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||
{
|
||||
if (e.NewStatus == Robust.Shared.Enums.SessionStatus.Connected)
|
||||
SendRespawnResetTime(e.Session, GetRespawnResetTime(e.Session));
|
||||
}
|
||||
|
||||
private void ResetRespawnTime(EntityUid entity, ICommonSession session)
|
||||
{
|
||||
ref var respawnTime = ref CollectionsMarshal.GetValueRefOrAddDefault(_respawnResetTimes, session, out _);
|
||||
respawnTime = _timing.CurTime;
|
||||
SendRespawnResetTime(session, _timing.CurTime);
|
||||
}
|
||||
|
||||
private void SendRespawnResetTime(ICommonSession session, TimeSpan? time)
|
||||
{
|
||||
RaiseNetworkEvent(new GhostRespawnEvent(time), session);
|
||||
}
|
||||
|
||||
public TimeSpan? GetRespawnResetTime(ICommonSession session)
|
||||
{
|
||||
return _respawnResetTimes.TryGetValue(session, out var time) ? time : null;
|
||||
}
|
||||
}
|
||||
45
Content.Server/_Wega/Interaction/DeleteOnDropSystem.cs
Normal file
45
Content.Server/_Wega/Interaction/DeleteOnDropSystem.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Interaction.Components;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory.Events;
|
||||
|
||||
namespace Content.Server.Interaction;
|
||||
|
||||
public sealed class DeleteOnDropSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<DeleteOnDropComponent, GotUnequippedEvent>(OnUnequip);
|
||||
SubscribeLocalEvent<DeleteOnDropComponent, GotUnequippedHandEvent>(OnUnequipHand);
|
||||
SubscribeLocalEvent<DeleteOnDropComponent, DroppedEvent>(OnDropped);
|
||||
}
|
||||
|
||||
private void OnUnequip(EntityUid uid, DeleteOnDropComponent item, GotUnequippedEvent args)
|
||||
{
|
||||
if (!item.DeleteOnDrop || !_entityManager.EntityExists(uid))
|
||||
return;
|
||||
|
||||
QueueDel(uid);
|
||||
}
|
||||
|
||||
private void OnUnequipHand(EntityUid uid, DeleteOnDropComponent item, GotUnequippedHandEvent args)
|
||||
{
|
||||
if (!item.DeleteOnDrop || !_entityManager.EntityExists(uid))
|
||||
return;
|
||||
|
||||
QueueDel(uid);
|
||||
}
|
||||
|
||||
private void OnDropped(EntityUid uid, DeleteOnDropComponent item, DroppedEvent args)
|
||||
{
|
||||
if (!item.DeleteOnDrop || !_entityManager.EntityExists(uid))
|
||||
return;
|
||||
|
||||
QueueDel(uid);
|
||||
}
|
||||
}
|
||||
|
||||
51
Content.Server/_Wega/NullRod/NullRodSystem.cs
Normal file
51
Content.Server/_Wega/NullRod/NullRodSystem.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using Content.Server.Bible.Components;
|
||||
using Content.Shared.Hands;
|
||||
using Content.Shared.Inventory.Events;
|
||||
using Content.Shared.NullRod.Components;
|
||||
|
||||
namespace Content.Server.NullRod;
|
||||
|
||||
public sealed class NullRodSystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<NullRodComponent, GotEquippedEvent>(OnDidEquip);
|
||||
SubscribeLocalEvent<NullRodComponent, GotEquippedHandEvent>(OnHandEquipped);
|
||||
SubscribeLocalEvent<NullRodComponent, GotUnequippedEvent>(OnDidUnequip);
|
||||
SubscribeLocalEvent<NullRodComponent, GotUnequippedHandEvent>(OnHandUnequipped);
|
||||
}
|
||||
|
||||
private void OnDidEquip(Entity<NullRodComponent> ent, ref GotEquippedEvent args)
|
||||
{
|
||||
if (!HasComp<BibleUserComponent>(args.Equipee) || HasComp<NullRodOwnerComponent>(args.Equipee))
|
||||
return;
|
||||
|
||||
EnsureComp<NullRodOwnerComponent>(args.Equipee);
|
||||
}
|
||||
|
||||
private void OnHandEquipped(Entity<NullRodComponent> ent, ref GotEquippedHandEvent args)
|
||||
{
|
||||
if (!HasComp<BibleUserComponent>(args.User) || HasComp<NullRodOwnerComponent>(args.User))
|
||||
return;
|
||||
|
||||
EnsureComp<NullRodOwnerComponent>(args.User);
|
||||
}
|
||||
|
||||
private void OnDidUnequip(Entity<NullRodComponent> ent, ref GotUnequippedEvent args)
|
||||
{
|
||||
if (!HasComp<NullRodOwnerComponent>(args.Equipee))
|
||||
return;
|
||||
|
||||
RemComp<NullRodOwnerComponent>(args.Equipee);
|
||||
}
|
||||
|
||||
private void OnHandUnequipped(Entity<NullRodComponent> ent, ref GotUnequippedHandEvent args)
|
||||
{
|
||||
if (!HasComp<NullRodOwnerComponent>(args.User))
|
||||
return;
|
||||
|
||||
RemComp<NullRodOwnerComponent>(args.User);
|
||||
}
|
||||
}
|
||||
22
Content.Shared/_WL/Sleep/SleepOnBuckleComponent.cs
Normal file
22
Content.Shared/_WL/Sleep/SleepOnBuckleComponent.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._WL.Sleep;
|
||||
|
||||
/// <summary>
|
||||
/// Allows entities buckled to this strap to sleep.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class SleepOnBuckleComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The sleep action entity that will be granted to buckled entities.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityUid? SleepAction;
|
||||
|
||||
/// <summary>
|
||||
/// Who unbuckle entity
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntityUid? User;
|
||||
}
|
||||
66
Content.Shared/_WL/Sleep/SleepOnBuckleSystem.cs
Normal file
66
Content.Shared/_WL/Sleep/SleepOnBuckleSystem.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Standing;
|
||||
using Content.Shared.Buckle.Components;
|
||||
using Content.Shared.Stunnable;
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.Actions.Components;
|
||||
|
||||
namespace Content.Shared._WL.Sleep;
|
||||
|
||||
public sealed class SleepOnBuckleSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ActionContainerSystem _actConts = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
|
||||
[Dependency] private readonly SleepingSystem _sleepingSystem = default!;
|
||||
[Dependency] protected readonly StandingStateSystem _standing = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SleepOnBuckleComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<SleepOnBuckleComponent, StrappedEvent>(OnStrapped);
|
||||
SubscribeLocalEvent<SleepOnBuckleComponent, UnstrappedEvent>(OnUnstrapped);
|
||||
SubscribeLocalEvent<SleepOnBuckleComponent, UnstrapAttemptEvent>(OnUnstrapAttempt);
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<SleepOnBuckleComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
_actConts.EnsureAction(ent.Owner, ref ent.Comp.SleepAction, SleepingSystem.SleepActionId);
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
private void OnStrapped(Entity<SleepOnBuckleComponent> ent, ref StrappedEvent args)
|
||||
{
|
||||
if (TryComp<StandingStateComponent>(args.Buckle, out var standing)
|
||||
&& standing.SleepAction != null
|
||||
&& TryComp<ActionComponent>(standing.SleepAction.Value, out var actionComp)
|
||||
&& actionComp.AttachedEntity == args.Buckle.Owner)
|
||||
_actionsSystem.RemoveAction(args.Buckle.Owner, standing.SleepAction);
|
||||
|
||||
_actionsSystem.AddAction(args.Buckle, ref ent.Comp.SleepAction, SleepingSystem.SleepActionId, ent);
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
private void OnUnstrapped(Entity<SleepOnBuckleComponent> ent, ref UnstrappedEvent args)
|
||||
{
|
||||
if (!Terminating(args.Buckle.Owner))
|
||||
{
|
||||
_actionsSystem.RemoveAction(args.Buckle.Owner, ent.Comp.SleepAction);
|
||||
_sleepingSystem.TryWaking(args.Buckle.Owner);
|
||||
|
||||
if (ent.Comp.User == args.Buckle.Owner)
|
||||
{
|
||||
RemComp<KnockedDownComponent>(args.Buckle.Owner);
|
||||
RemComp<StunnedComponent>(args.Buckle.Owner);
|
||||
|
||||
_standing.Stand(args.Buckle.Owner, force: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnUnstrapAttempt(Entity<SleepOnBuckleComponent> ent, ref UnstrapAttemptEvent args)
|
||||
{
|
||||
ent.Comp.User = args.User;
|
||||
}
|
||||
}
|
||||
31
Content.Shared/_Wega/Barks/BarkPrototype.cs
Normal file
31
Content.Shared/_Wega/Barks/BarkPrototype.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Speech.Synthesis;
|
||||
|
||||
/// <summary>
|
||||
/// Прототип для доступных барков.
|
||||
/// </summary>
|
||||
[Prototype("bark")]
|
||||
public sealed class BarkPrototype : IPrototype
|
||||
{
|
||||
[IdDataField]
|
||||
public string ID { get; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Название голоса.
|
||||
/// </summary>
|
||||
[DataField("name")]
|
||||
public string Name { get; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Набор звуков, используемых для речи.
|
||||
/// </summary>
|
||||
[DataField("soundFiles", required: true)]
|
||||
public List<string> SoundFiles { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Доступен ли на старте раунда.
|
||||
/// </summary>
|
||||
[DataField("roundStart")]
|
||||
public bool RoundStart { get; } = true;
|
||||
}
|
||||
28
Content.Shared/_Wega/Barks/RequestBarkEvents.cs
Normal file
28
Content.Shared/_Wega/Barks/RequestBarkEvents.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Speech.Synthesis;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class RequestPreviewBarkEvent(string barkVoiceId) : EntityEventArgs
|
||||
{
|
||||
public string BarkVoiceId { get; } = barkVoiceId;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class PlayBarkEvent : EntityEventArgs
|
||||
{
|
||||
public string SoundPath { get; }
|
||||
public NetEntity SourceUid { get; }
|
||||
public string Message { get; }
|
||||
public float PlaybackSpeed { get; }
|
||||
public bool Obfuscated { get; }
|
||||
|
||||
public PlayBarkEvent(string soundPath, NetEntity sourceUid, string message, float playbackSpeed, bool obfuscated)
|
||||
{
|
||||
SoundPath = soundPath;
|
||||
SourceUid = sourceUid;
|
||||
Message = message;
|
||||
PlaybackSpeed = playbackSpeed;
|
||||
Obfuscated = obfuscated;
|
||||
}
|
||||
}
|
||||
39
Content.Shared/_Wega/Barks/SpeechSynthesis.cs
Normal file
39
Content.Shared/_Wega/Barks/SpeechSynthesis.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Shared.Speech.Synthesis.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Применяет звуки барков для сущности.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class SpeechSynthesisComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Прототип голоса для барков.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("voice", customTypeSerializer: typeof(PrototypeIdSerializer<BarkPrototype>))]
|
||||
public string? VoicePrototypeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Скорость воспроизведения звука.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("playbackSpeed")]
|
||||
public float PlaybackSpeed { get; set; } = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Тональность звука.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("pitch")]
|
||||
public float Pitch { get; set; } = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Выразительность речи.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("expression")]
|
||||
public float Expression { get; set; } = 1.0f;
|
||||
}
|
||||
121
Content.Shared/_Wega/CCCVars/CCVars.cs
Normal file
121
Content.Shared/_Wega/CCCVars/CCVars.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using Robust.Shared.Configuration;
|
||||
|
||||
namespace Content.Shared.CCVar;
|
||||
|
||||
[CVarDefs]
|
||||
public sealed class WegaCVars
|
||||
{
|
||||
/*
|
||||
Ghost Respawn CVars
|
||||
*/
|
||||
/// <summary>
|
||||
/// Whether or not respawning is enabled.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> GhostRespawnEnabled =
|
||||
CVarDef.Create("wega.respawn_enabled", false, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Respawn time, how long the player has to wait in seconds after death.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float> GhostRespawnTime =
|
||||
CVarDef.Create("wega.respawn_time", 1200.0f, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/*
|
||||
Barks CVars
|
||||
*/
|
||||
/// <summary>
|
||||
/// Responsible for turning on and off the bark system.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> BarksEnabled =
|
||||
CVarDef.Create("wega.barks_enabled", false, CVar.SERVER | CVar.REPLICATED | CVar.ARCHIVE);
|
||||
|
||||
/// <summary>
|
||||
/// Default volume setting of Barks sound.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float> BarksVolume =
|
||||
CVarDef.Create("wega.barks_volume", 0f, CVar.CLIENTONLY | CVar.ARCHIVE);
|
||||
|
||||
/*
|
||||
Night Light System CVars
|
||||
*/
|
||||
/// <summary>
|
||||
/// Responsible for switching the night light system.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> NightLightEnabled =
|
||||
CVarDef.Create("wega.night_light_enabled", false, CVar.SERVER | CVar.REPLICATED | CVar.ARCHIVE);
|
||||
|
||||
/// <summary>
|
||||
/// Switching adjusts all the lamps to the holiday mode according to the logic of updating the night lighting.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> PartyEnabled =
|
||||
CVarDef.Create("wega.party_enabled", false, CVar.SERVER | CVar.REPLICATED | CVar.ARCHIVE);
|
||||
|
||||
/*
|
||||
Sound insulation CVars
|
||||
*/
|
||||
/// <summary>
|
||||
/// If you enable this mode, it will process the sound with sound isolation.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> SoundInsulationEnabled =
|
||||
CVarDef.Create("wega.sound_insulation_enabled", false, CVar.SERVER | CVar.REPLICATED | CVar.ARCHIVE);
|
||||
|
||||
/*
|
||||
Vote CVars
|
||||
*/
|
||||
/// <summary>
|
||||
/// If enabled forcibly, it will trigger a vote for the mode at the end of the round.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> VoteRoundEndEnabled =
|
||||
CVarDef.Create("wega.roundend_vote_enabled", false, CVar.SERVERONLY);
|
||||
|
||||
/*
|
||||
Ic Flavors
|
||||
*/
|
||||
/// <summary>
|
||||
/// Sets the maximum length for OOC flavor text.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<int> OOCMaxFlavorTextLength =
|
||||
CVarDef.Create("ic.oocflavor_text_length", 2048, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the maximum length for character description text.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<int> CharacterDescriptionLength =
|
||||
CVarDef.Create("ic.character_description_length", 2048, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the maximum length for green preferences text.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<int> GreenPreferencesLength =
|
||||
CVarDef.Create("ic.green_preferences_length", 256, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the maximum length for yellow preferences text.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<int> YellowPreferencesLength =
|
||||
CVarDef.Create("ic.yellow_preferences_length", 256, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the maximum length for red preferences text.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<int> RedPreferencesLength =
|
||||
CVarDef.Create("ic.red_preferences_length", 256, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the maximum length for tags text.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<int> TagsLength =
|
||||
CVarDef.Create("ic.tags_length", 128, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the maximum length for links text.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<int> LinksLength =
|
||||
CVarDef.Create("ic.links_length", 512, CVar.SERVER | CVar.REPLICATED);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the maximum length for NSFW preferences text.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<int> NSFWPreferencesLength =
|
||||
CVarDef.Create("ic.nsfw_preferences_length", 1024, CVar.SERVER | CVar.REPLICATED);
|
||||
}
|
||||
11
Content.Shared/_Wega/Food/EdibleMatterComponent.cs
Normal file
11
Content.Shared/_Wega/Food/EdibleMatterComponent.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Content.Shared.Edible.Matter;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class EdibleMatterComponent : Component
|
||||
{
|
||||
[DataField("nutritionValue")]
|
||||
public float NutritionValue = 5f;
|
||||
|
||||
[DataField("canBeEaten")]
|
||||
public bool CanBeEaten = true;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Content.Shared.NPC.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Friendly.Faction;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class FriendlyFactionComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public ProtoId<NpcFactionPrototype>? Faction;
|
||||
}
|
||||
9
Content.Shared/_Wega/Ghost/GhostRespawnEvent.cs
Normal file
9
Content.Shared/_Wega/Ghost/GhostRespawnEvent.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Wega.Ghost.Respawn;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class GhostRespawnEvent(TimeSpan? time) : EntityEventArgs
|
||||
{
|
||||
public readonly TimeSpan? Time = time;
|
||||
}
|
||||
11
Content.Shared/_Wega/Interaction/DeleteOnDropComponent.cs
Normal file
11
Content.Shared/_Wega/Interaction/DeleteOnDropComponent.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Interaction.Components
|
||||
{
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class DeleteOnDropComponent : Component
|
||||
{
|
||||
[DataField("deleteOnDrop")]
|
||||
public bool DeleteOnDrop = true;
|
||||
}
|
||||
}
|
||||
13
Content.Shared/_Wega/NullRod/NullRodComponent.cs
Normal file
13
Content.Shared/_Wega/NullRod/NullRodComponent.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Shared.NullRod.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class NullRodComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public FixedPoint2 FirstNullDamage = 30;
|
||||
|
||||
[DataField]
|
||||
public FixedPoint2 NullDamage = 15;
|
||||
}
|
||||
6
Content.Shared/_Wega/NullRod/NullRodOwnerComponent.cs
Normal file
6
Content.Shared/_Wega/NullRod/NullRodOwnerComponent.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Shared.NullRod.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class NullRodOwnerComponent : Component;
|
||||
BIN
Resources/Audio/_Wega/Voice/Barks/aa_blip.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/aa_blip.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/aa_blip_typewriter.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/aa_blip_typewriter.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/aa_dd_blip.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/aa_dd_blip.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/aa_tgaa_blip.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/aa_tgaa_blip.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/ahuh.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/ahuh.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/bark1.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/bark1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/birdwhistle.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/birdwhistle.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/birdwhistle2.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/birdwhistle2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/bleat_bark.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/bleat_bark.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/bloop.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/bloop.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/blub.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/blub.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/bottalk_1.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/bottalk_1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/bottalk_2.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/bottalk_2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/bottalk_3.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/bottalk_3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/bottalk_4.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/bottalk_4.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/bulletflyby.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/bulletflyby.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/buwoo.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/buwoo.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/c2.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/c2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/c3.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/c3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/c4.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/c4.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/caw.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/caw.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/caw2.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/caw2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/caw3.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/caw3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/chitter.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/chitter.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/cn3.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/cn3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/cn4.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/cn4.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/cow.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/cow.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/cry.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/cry.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/dwoop.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/dwoop.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/ehh.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/ehh.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/ehh2.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/ehh2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/ehh3.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/ehh3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/ehh4.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/ehh4.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/ehh5.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/ehh5.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/eugh.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/eugh.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/faucet.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/faucet.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/faucet2.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/faucet2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/growl.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/growl.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/growl2.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/growl2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/haha.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/haha.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/hoot.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/hoot.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/integration_cog_install.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/integration_cog_install.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/lizard.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/lizard.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/merp.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/merp.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/moan1.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/moan1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/moan2.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/moan2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/moan3.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/moan3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/mothsqueak.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/mothsqueak.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/nomi.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/nomi.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/nya.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/nya.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/poyo.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/poyo.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/pug.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/pug.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/pugg.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/pugg.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/raah1.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/raah1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/raah2.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/raah2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/radio.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/radio.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/radio2.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/radio2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/radio_ai.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/radio_ai.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/ribbit.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/ribbit.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/roach.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/roach.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/skelly.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/skelly.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/slurp.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/slurp.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/speak_1.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/speak_1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/speak_2.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/speak_2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/speak_3.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/speak_3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_Wega/Voice/Barks/speak_4.ogg
Normal file
BIN
Resources/Audio/_Wega/Voice/Barks/speak_4.ogg
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user