Merge remote-tracking branch 'upstream/master'
@@ -56,23 +56,39 @@ public sealed class ChargeActionSystem : SharedChargingSystem
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
if (_playerManager.LocalEntity is not { } user)
|
||||
if (!_timing.IsFirstTimePredicted)
|
||||
return;
|
||||
|
||||
if (_playerManager.LocalEntity is not { } user)
|
||||
{
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_mobState.IsAlive(user) || _statusEffects.HasStatusEffect(user, "Incorporeal"))
|
||||
{
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_timing.IsFirstTimePredicted || _controller == null || _controller.SelectingTargetFor is not { } actionId)
|
||||
if (_controller == null || _controller.SelectingTargetFor is not { } actionId)
|
||||
{
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_actionsSystem.TryGetActionData(actionId, out var baseAction) ||
|
||||
baseAction is not BaseTargetActionComponent action || !action.IsChargeEnabled)
|
||||
{
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!action.Enabled
|
||||
|| action is { Charges: 0, RenewCharges: false }
|
||||
|| action.Cooldown.HasValue && action.Cooldown.Value.End > _timing.CurTime)
|
||||
{
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -139,6 +155,17 @@ public sealed class ChargeActionSystem : SharedChargingSystem
|
||||
}
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
_charging = false;
|
||||
_prevCharging = false;
|
||||
_chargeTime = 0f;
|
||||
_chargeLevel = 0;
|
||||
_prevChargeLevel = 0;
|
||||
_isChargingPlaying = false;
|
||||
_isChargedPlaying = false;
|
||||
}
|
||||
|
||||
private void HandleAction(EntityUid actionId, BaseTargetActionComponent action, EntityUid user, int chargeLevel)
|
||||
{
|
||||
var mousePos = _eyeManager.PixelToMap(_inputManager.MouseScreenPosition);
|
||||
|
||||
@@ -87,7 +87,7 @@ public sealed partial class HumanoidProfileEditor
|
||||
if (_previewDummy is null || Profile is null)
|
||||
return;
|
||||
|
||||
_ttsSys.StopAllStreams();
|
||||
_ttsSys.StopCurrentTTS(_previewDummy.Value);
|
||||
_ttsMgr.RequestTTS(_previewDummy.Value, IoCManager.Resolve<IRobustRandom>().Pick(_sampleText), Profile.Voice);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +1,29 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Content.Shared.Physics;
|
||||
using System.IO;
|
||||
using Content.Shared._White;
|
||||
using Content.Shared._White.TTS;
|
||||
using Robust.Client.Audio;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Audio.Sources;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Components;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Physics;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace Content.Client._White.TTS;
|
||||
|
||||
/// <summary>
|
||||
/// Plays TTS audio in world
|
||||
/// </summary>
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public sealed class TTSSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IAudioManager _audioSystem = default!;
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
[Dependency] private readonly IEyeManager _eye = default!;
|
||||
[Dependency] private readonly IAudioManager _audioManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _broadPhase = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
[Dependency] private readonly AudioSystem _audioSystem = default!;
|
||||
|
||||
private float _volume;
|
||||
private const int TTSCollisionMask = (int)CollisionGroup.Impassable;
|
||||
|
||||
private readonly HashSet<AudioStream> _currentStreams = new();
|
||||
private readonly Dictionary<EntityUid, Queue<AudioStream>> _entityQueues = new();
|
||||
private readonly Dictionary<EntityUid, AudioComponent> _currentlyPlaying = new();
|
||||
private readonly Dictionary<EntityUid, Queue<AudioStreamWithParams>> _enquedStreams = new();
|
||||
|
||||
// Same as Server.ChatSystem.VoiceRange
|
||||
private const float VoiceRange = 10;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -44,54 +35,35 @@ public sealed class TTSSystem : EntitySystem
|
||||
{
|
||||
base.Shutdown();
|
||||
_cfg.UnsubValueChanged(WhiteCVars.TtsVolume, OnTtsVolumeChanged);
|
||||
EndStreams();
|
||||
ClearQueues();
|
||||
}
|
||||
|
||||
// Little bit of duplication logic from AudioSystem
|
||||
public override void FrameUpdate(float frameTime)
|
||||
{
|
||||
var streamToRemove = new HashSet<AudioStream>();
|
||||
|
||||
var ourPos = _eye.CurrentEye.Position.Position;
|
||||
foreach (var stream in _currentStreams)
|
||||
foreach (var (uid, audioComponent) in _currentlyPlaying)
|
||||
{
|
||||
if (!stream.Source.Playing ||
|
||||
!_entity.TryGetComponent<MetaDataComponent>(stream.Uid, out var meta) ||
|
||||
Deleted(stream.Uid, meta) ||
|
||||
!_entity.TryGetComponent<TransformComponent>(stream.Uid, out var xform))
|
||||
{
|
||||
stream.Source.Dispose();
|
||||
streamToRemove.Add(stream);
|
||||
continue;
|
||||
}
|
||||
|
||||
var mapPos = _transform.GetMapCoordinates(xform);
|
||||
if (mapPos.MapId != MapId.Nullspace)
|
||||
{
|
||||
stream.Source.Position = mapPos.Position;
|
||||
}
|
||||
|
||||
if (mapPos.MapId != _eye.CurrentMap)
|
||||
if (audioComponent is { Running: true, Playing: true })
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var sourceRelative = ourPos - mapPos.Position;
|
||||
var occlusion = 0f;
|
||||
if (sourceRelative.Length() > 0)
|
||||
if (!_enquedStreams.TryGetValue(uid, out var queue))
|
||||
{
|
||||
occlusion = _broadPhase.IntersectRayPenetration(mapPos.MapId,
|
||||
new CollisionRay(mapPos.Position, sourceRelative.Normalized(), TTSCollisionMask),
|
||||
sourceRelative.Length(), stream.Uid);
|
||||
continue;
|
||||
}
|
||||
|
||||
stream.Source.Occlusion = occlusion;
|
||||
}
|
||||
if (!queue.TryDequeue(out var toPlay))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var audioStream in streamToRemove)
|
||||
{
|
||||
_currentStreams.Remove(audioStream);
|
||||
ProcessEntityQueue(audioStream.Uid);
|
||||
var audio = _audioSystem.PlayEntity(toPlay.Stream, uid, toPlay.Params);
|
||||
if (!audio.HasValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_currentlyPlaying[uid] = audio.Value.Component;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,114 +74,76 @@ public sealed class TTSSystem : EntitySystem
|
||||
|
||||
private void OnPlayTTS(PlayTTSEvent ev)
|
||||
{
|
||||
if (_volume <= -20f)
|
||||
return;
|
||||
|
||||
var volume = _volume;
|
||||
if (ev.BoostVolume)
|
||||
volume += 5f;
|
||||
if (!TryCreateAudioSource(ev.Data, out var source, volume))
|
||||
return;
|
||||
|
||||
var stream = new AudioStream(GetEntity(ev.Uid), source);
|
||||
AddEntityStreamToQueue(stream);
|
||||
PlayTTS(GetEntity(ev.Uid), ev.Data, ev.BoostVolume ? _volume + 5 : _volume);
|
||||
}
|
||||
|
||||
public void PlayCustomText(string text)
|
||||
public void PlayTTS(EntityUid uid, byte[] data, float volume)
|
||||
{
|
||||
RaiseNetworkEvent(new RequestTTSEvent(text));
|
||||
if (_volume <= -20f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var stream = CreateAudioStream(data);
|
||||
|
||||
var audioParams = new AudioParams
|
||||
{
|
||||
Volume = volume,
|
||||
MaxDistance = VoiceRange
|
||||
};
|
||||
|
||||
var audioStream = new AudioStreamWithParams(stream, audioParams);
|
||||
EnqueueAudio(uid, audioStream);
|
||||
}
|
||||
|
||||
private bool TryCreateAudioSource(byte[] data, [NotNullWhen(true)] out IAudioSource? source, float volume = 0f)
|
||||
public void StopCurrentTTS(EntityUid uid)
|
||||
{
|
||||
if (!_currentlyPlaying.TryGetValue(uid, out var audio))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_audioSystem.Stop(audio.Owner);
|
||||
}
|
||||
|
||||
private void EnqueueAudio(EntityUid uid, AudioStreamWithParams audioStream)
|
||||
{
|
||||
if (!_currentlyPlaying.ContainsKey(uid))
|
||||
{
|
||||
var audio = _audioSystem.PlayEntity(audioStream.Stream, uid, audioStream.Params);
|
||||
if (!audio.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_currentlyPlaying[uid] = audio.Value.Component;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_enquedStreams.TryGetValue(uid, out var queue))
|
||||
{
|
||||
queue.Enqueue(audioStream);
|
||||
return;
|
||||
}
|
||||
|
||||
queue = new Queue<AudioStreamWithParams>();
|
||||
queue.Enqueue(audioStream);
|
||||
_enquedStreams[uid] = queue;
|
||||
}
|
||||
|
||||
private void ClearQueues()
|
||||
{
|
||||
foreach (var (_, queue) in _enquedStreams)
|
||||
{
|
||||
queue.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private AudioStream CreateAudioStream(byte[] data)
|
||||
{
|
||||
var dataStream = new MemoryStream(data) { Position = 0 };
|
||||
var audioStream = _audioSystem.LoadAudioOggVorbis(dataStream);
|
||||
source = _audioSystem.CreateAudioSource(audioStream);
|
||||
if (source == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
source.Volume = volume == 0f ? _volume : volume;
|
||||
return true;
|
||||
return _audioManager.LoadAudioOggVorbis(dataStream);
|
||||
}
|
||||
|
||||
private void AddEntityStreamToQueue(AudioStream stream)
|
||||
{
|
||||
if (_entityQueues.TryGetValue(stream.Uid, out var queue))
|
||||
{
|
||||
queue.Enqueue(stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
_entityQueues.Add(stream.Uid, new Queue<AudioStream>(new[] { stream }));
|
||||
|
||||
if (!IsEntityCurrentlyPlayStream(stream.Uid))
|
||||
ProcessEntityQueue(stream.Uid);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsEntityCurrentlyPlayStream(EntityUid uid)
|
||||
{
|
||||
return _currentStreams.Any(s => s.Uid == uid);
|
||||
}
|
||||
|
||||
private void ProcessEntityQueue(EntityUid uid)
|
||||
{
|
||||
if (TryTakeEntityStreamFromQueue(uid, out var stream))
|
||||
PlayEntity(stream);
|
||||
}
|
||||
|
||||
private bool TryTakeEntityStreamFromQueue(EntityUid uid, [NotNullWhen(true)] out AudioStream? stream)
|
||||
{
|
||||
if (_entityQueues.TryGetValue(uid, out var queue))
|
||||
{
|
||||
stream = queue.Dequeue();
|
||||
if (queue.Count == 0)
|
||||
_entityQueues.Remove(uid);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
stream = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void PlayEntity(AudioStream stream)
|
||||
{
|
||||
if (!_entity.TryGetComponent<TransformComponent>(stream.Uid, out var xform))
|
||||
return;
|
||||
|
||||
stream.Source.Position = _transform.GetWorldPosition(xform);
|
||||
stream.Source.StartPlaying();
|
||||
_currentStreams.Add(stream);
|
||||
}
|
||||
|
||||
public void StopAllStreams()
|
||||
{
|
||||
foreach (var stream in _currentStreams)
|
||||
{
|
||||
stream.Source.StopPlaying();
|
||||
}
|
||||
}
|
||||
|
||||
private void EndStreams()
|
||||
{
|
||||
foreach (var stream in _currentStreams)
|
||||
{
|
||||
stream.Source.StopPlaying();
|
||||
stream.Source.Dispose();
|
||||
}
|
||||
|
||||
_currentStreams.Clear();
|
||||
_entityQueues.Clear();
|
||||
}
|
||||
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private sealed class AudioStream(EntityUid uid, IAudioSource source)
|
||||
{
|
||||
public EntityUid Uid { get; } = uid;
|
||||
|
||||
public IAudioSource Source { get; } = source;
|
||||
}
|
||||
private record AudioStreamWithParams(AudioStream Stream, AudioParams Params);
|
||||
}
|
||||
@@ -152,7 +152,7 @@ public sealed partial class AdminVerbSystem
|
||||
Act = () =>
|
||||
{
|
||||
// Fuck you. Burn Forever.
|
||||
flammable.FireStacks = flammable.MaximumFireStacks;
|
||||
flammable.FireStacks = FlammableSystem.MaximumFireStacks;
|
||||
_flammableSystem.Ignite(args.Target, args.User);
|
||||
var xform = Transform(args.Target);
|
||||
_popupSystem.PopupEntity(Loc.GetString("admin-smite-set-alight-self"), args.Target,
|
||||
|
||||
@@ -11,65 +11,49 @@ namespace Content.Server.Atmos.Components
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public bool OnFire;
|
||||
public bool OnFire { get; set; }
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public float FireStacks;
|
||||
public float FireStacks { get; set; }
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public float MaximumFireStacks = 10f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public float MinimumFireStacks = -10f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public string FlammableFixtureID = "flammable";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
public float MinIgnitionTemperature = 373.15f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
[DataField("fireSpread")]
|
||||
public bool FireSpread { get; private set; } = false;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
[DataField("canResistFire")]
|
||||
public bool CanResistFire { get; private set; } = false;
|
||||
|
||||
[DataField(required: true)]
|
||||
[DataField("damage", required: true)]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public DamageSpecifier Damage = new(); // Empty by default, we don't want any funny NREs.
|
||||
|
||||
/// <summary>
|
||||
/// Used for the fixture created to handle passing firestacks when two flammable objects collide.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
[DataField("flammableCollisionShape")]
|
||||
public IPhysShape FlammableCollisionShape = new PhysShapeCircle(0.35f);
|
||||
|
||||
/// <summary>
|
||||
/// Should the component be set on fire by interactions with isHot entities
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
[DataField("alwaysCombustible")]
|
||||
public bool AlwaysCombustible = false;
|
||||
|
||||
/// <summary>
|
||||
/// Can the component anyhow lose its FireStacks?
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
[DataField("canExtinguish")]
|
||||
public bool CanExtinguish = true;
|
||||
|
||||
/// <summary>
|
||||
/// How many firestacks should be applied to component when being set on fire?
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField]
|
||||
[DataField("firestacksOnIgnite")]
|
||||
public float FirestacksOnIgnite = 2.0f;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -52,11 +52,13 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SpellBladeSystem _spellBlade = default!; // WD
|
||||
|
||||
private EntityQuery<PhysicsComponent> _physicsQuery;
|
||||
|
||||
// This should probably be moved to the component, requires a rewrite, all fires tick at the same time
|
||||
public const float MinimumFireStacks = -10f;
|
||||
public const float MaximumFireStacks = 20f;
|
||||
private const float UpdateTime = 1f;
|
||||
|
||||
public const float MinIgnitionTemperature = 373.15f;
|
||||
public const string FlammableFixtureID = "flammable";
|
||||
|
||||
private float _timer;
|
||||
|
||||
private readonly Dictionary<Entity<FlammableComponent>, float> _fireEvents = new();
|
||||
@@ -65,8 +67,6 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
{
|
||||
UpdatesAfter.Add(typeof(AtmosphereSystem));
|
||||
|
||||
_physicsQuery = GetEntityQuery<PhysicsComponent>();
|
||||
|
||||
SubscribeLocalEvent<FlammableComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<FlammableComponent, InteractUsingEvent>(OnInteractUsing);
|
||||
SubscribeLocalEvent<FlammableComponent, StartCollideEvent>(OnCollide);
|
||||
@@ -141,7 +141,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
if (!TryComp<PhysicsComponent>(uid, out var body))
|
||||
return;
|
||||
|
||||
_fixture.TryCreateFixture(uid, component.FlammableCollisionShape, component.FlammableFixtureID, hard: false,
|
||||
_fixture.TryCreateFixture(uid, component.FlammableCollisionShape, FlammableFixtureID, hard: false,
|
||||
collisionMask: (int) CollisionGroup.FullTileLayer, body: body);
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
|
||||
// Normal hard collisions, though this isn't generally possible since most flammable things are mobs
|
||||
// which don't collide with one another, shouldn't work here.
|
||||
if (args.OtherFixtureId != flammable.FlammableFixtureID && args.OurFixtureId != flammable.FlammableFixtureID)
|
||||
if (args.OtherFixtureId != FlammableFixtureID && args.OurFixtureId != FlammableFixtureID)
|
||||
return;
|
||||
|
||||
if (!flammable.FireSpread)
|
||||
@@ -211,30 +211,49 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
if (!flammable.OnFire && !otherFlammable.OnFire)
|
||||
return; // Neither are on fire
|
||||
|
||||
// Both are on fire -> equalize fire stacks.
|
||||
// Weight each thing's firestacks by its mass
|
||||
var mass1 = 1f;
|
||||
var mass2 = 1f;
|
||||
if (_physicsQuery.TryComp(uid, out var physics) && _physicsQuery.TryComp(otherUid, out var otherPhys))
|
||||
// WD START
|
||||
var weHold = _spellBlade.IsHoldingItemWithComponent<FireAspectComponent>(uid);
|
||||
var theyHold = _spellBlade.IsHoldingItemWithComponent<FireAspectComponent>(otherUid);
|
||||
// WD END
|
||||
|
||||
if (flammable.OnFire && otherFlammable.OnFire)
|
||||
{
|
||||
mass1 = physics.Mass;
|
||||
mass2 = otherPhys.Mass;
|
||||
if (weHold && !theyHold || theyHold && !weHold) // WD
|
||||
return;
|
||||
// Both are on fire -> equalize fire stacks.
|
||||
var avg = (flammable.FireStacks + otherFlammable.FireStacks) / 2;
|
||||
flammable.FireStacks = flammable.CanExtinguish ? avg : Math.Max(flammable.FireStacks, avg);
|
||||
otherFlammable.FireStacks = otherFlammable.CanExtinguish ? avg : Math.Max(otherFlammable.FireStacks, avg);
|
||||
UpdateAppearance(uid, flammable);
|
||||
UpdateAppearance(otherUid, otherFlammable);
|
||||
return;
|
||||
}
|
||||
|
||||
// when the thing on fire is more massive than the other, the following happens:
|
||||
// - the thing on fire loses a small number of firestacks
|
||||
// - the other thing gains a large number of firestacks
|
||||
// so a person on fire engulfs a mouse, but an engulfed mouse barely does anything to a person
|
||||
var total = mass1 + mass2;
|
||||
var avg = (flammable.FireStacks + otherFlammable.FireStacks) / total;
|
||||
|
||||
// swap the entity losing stacks depending on whichever has the most firestack kilos
|
||||
var (src, dest) = flammable.FireStacks * mass1 > otherFlammable.FireStacks * mass2
|
||||
? (-1f, 1f)
|
||||
: (1f, -1f);
|
||||
// bring each entity to the same firestack mass, firestacks being scaled by the other's mass
|
||||
AdjustFireStacks(uid, src * avg * mass2, flammable, ignite: true);
|
||||
AdjustFireStacks(otherUid, dest * avg * mass1, otherFlammable, ignite: true);
|
||||
// Only one is on fire -> attempt to spread the fire.
|
||||
if (flammable.OnFire)
|
||||
{
|
||||
if (theyHold) // WD
|
||||
return;
|
||||
otherFlammable.FireStacks += flammable.FireStacks / 2;
|
||||
Ignite(otherUid, uid, otherFlammable);
|
||||
if (flammable.CanExtinguish)
|
||||
{
|
||||
flammable.FireStacks /= 2;
|
||||
UpdateAppearance(uid, flammable);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (weHold) // WD
|
||||
return;
|
||||
flammable.FireStacks += otherFlammable.FireStacks / 2;
|
||||
Ignite(uid, otherUid, flammable);
|
||||
if (otherFlammable.CanExtinguish)
|
||||
{
|
||||
otherFlammable.FireStacks /= 2;
|
||||
UpdateAppearance(otherUid, otherFlammable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIsHot(EntityUid uid, FlammableComponent flammable, IsHotEvent args)
|
||||
@@ -244,7 +263,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
|
||||
private void OnTileFire(Entity<FlammableComponent> ent, ref TileFireEvent args)
|
||||
{
|
||||
var tempDelta = args.Temperature - ent.Comp.MinIgnitionTemperature;
|
||||
var tempDelta = args.Temperature - MinIgnitionTemperature;
|
||||
|
||||
_fireEvents.TryGetValue(ent, out var maxTemp);
|
||||
|
||||
@@ -272,30 +291,17 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
_appearance.SetData(uid, ToggleableLightVisuals.Enabled, flammable.OnFire, appearance);
|
||||
}
|
||||
|
||||
public void AdjustFireStacks(EntityUid uid, float relativeFireStacks, FlammableComponent? flammable = null, bool ignite = false)
|
||||
public void AdjustFireStacks(EntityUid uid, float relativeFireStacks, FlammableComponent? flammable = null)
|
||||
{
|
||||
if (!Resolve(uid, ref flammable))
|
||||
return;
|
||||
|
||||
SetFireStacks(uid, flammable.FireStacks + relativeFireStacks, flammable, ignite);
|
||||
}
|
||||
flammable.FireStacks = MathF.Min(MathF.Max(MinimumFireStacks, flammable.FireStacks + relativeFireStacks), MaximumFireStacks);
|
||||
|
||||
public void SetFireStacks(EntityUid uid, float stacks, FlammableComponent? flammable = null, bool ignite = false)
|
||||
{
|
||||
if (!Resolve(uid, ref flammable))
|
||||
return;
|
||||
|
||||
flammable.FireStacks = MathF.Min(MathF.Max(flammable.MinimumFireStacks, stacks), flammable.MaximumFireStacks);
|
||||
|
||||
if (flammable.FireStacks <= 0)
|
||||
{
|
||||
if (flammable.OnFire && flammable.FireStacks <= 0)
|
||||
Extinguish(uid, flammable);
|
||||
}
|
||||
else
|
||||
{
|
||||
flammable.OnFire = ignite;
|
||||
UpdateAppearance(uid, flammable);
|
||||
}
|
||||
}
|
||||
|
||||
public void Extinguish(EntityUid uid, FlammableComponent? flammable = null)
|
||||
@@ -444,11 +450,13 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
EnsureComp<IgnitionSourceComponent>(uid);
|
||||
_ignitionSourceSystem.SetIgnited(uid);
|
||||
|
||||
var damageScale = MathF.Min( flammable.FireStacks, 5);
|
||||
|
||||
if (TryComp(uid, out TemperatureComponent? temp))
|
||||
_temperatureSystem.ChangeHeat(uid, 12500 * flammable.FireStacks, false, temp);
|
||||
_temperatureSystem.ChangeHeat(uid, 12500 * damageScale, false, temp);
|
||||
|
||||
if (!_spellBlade.IsHoldingItemWithComponent<FireAspectComponent>(uid)) // WD EDIT
|
||||
_damageableSystem.TryChangeDamage(uid, flammable.Damage * flammable.FireStacks, interruptsDoAfters: false);
|
||||
_damageableSystem.TryChangeDamage(uid, flammable.Damage * damageScale, interruptsDoAfters: false);
|
||||
|
||||
AdjustFireStacks(uid, flammable.FirestackFade * (flammable.Resisting ? 10f : 1f), flammable);
|
||||
}
|
||||
|
||||
@@ -108,13 +108,18 @@ public partial class SeedData
|
||||
|
||||
/// <summary>
|
||||
/// If true, the properties of this seed cannot be modified.
|
||||
/// to spare others like me: this DOES NOT prevent mutations
|
||||
/// </summary>
|
||||
[DataField("immutable")] public bool Immutable;
|
||||
|
||||
/// <summary>
|
||||
/// If true, you cannot clip this plant for more seeds, used for special plants such as the gnome plant
|
||||
/// </summary>
|
||||
[DataField("unclippable")] public bool Unclippable;
|
||||
|
||||
/// <summary>
|
||||
/// If true, there is only a single reference to this seed and it's properties can be directly modified without
|
||||
/// needing to clone the seed.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public bool Unique = false; // seed-prototypes or yaml-defined seeds for entity prototypes will not generally be unique.
|
||||
#endregion
|
||||
@@ -255,6 +260,7 @@ public partial class SeedData
|
||||
{
|
||||
DebugTools.Assert(!Immutable, "There should be no need to clone an immutable seed.");
|
||||
|
||||
|
||||
var newSeed = new SeedData
|
||||
{
|
||||
Name = Name,
|
||||
@@ -290,6 +296,7 @@ public partial class SeedData
|
||||
HarvestRepeat = HarvestRepeat,
|
||||
Potency = Potency,
|
||||
|
||||
Unclippable = Unclippable,
|
||||
Seedless = Seedless,
|
||||
Viable = Viable,
|
||||
Slip = Slip,
|
||||
|
||||
@@ -245,6 +245,13 @@ public sealed class PlantHolderSystem : EntitySystem
|
||||
_popup.PopupCursor(Loc.GetString("plant-holder-component-nothing-to-sample-message"), args.User);
|
||||
return;
|
||||
}
|
||||
//rejects clipping of unclippable plants
|
||||
if (component.Seed.Unclippable)
|
||||
{
|
||||
_popup.PopupCursor(Loc.GetString("plant-holder-component-nothing-to-sample-message"), args.User);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (component.Sampled)
|
||||
{
|
||||
|
||||
@@ -164,8 +164,7 @@ public sealed class MagicSystem : EntitySystem
|
||||
if (!_wizardSpells.CanCast(args)) // WD EDIT
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
Speak(args);
|
||||
_wizardSpells.Cast(args); // WD EDIT
|
||||
|
||||
var transform = Transform(args.Performer);
|
||||
var coords = transform.Coordinates;
|
||||
@@ -190,9 +189,7 @@ public sealed class MagicSystem : EntitySystem
|
||||
if (!_wizardSpells.CanCast(ev)) // WD EDIT
|
||||
return;
|
||||
|
||||
ev.Handled = true;
|
||||
|
||||
Speak(ev);
|
||||
_wizardSpells.Cast(ev); // WD EDIT
|
||||
|
||||
var direction = _transformSystem.GetMapCoordinates(ev.Target).Position - _transformSystem.GetMapCoordinates(ev.Performer).Position;
|
||||
var impulseVector = direction * 10000;
|
||||
|
||||
@@ -6,15 +6,37 @@ using Content.Shared.Popups;
|
||||
using Content.Shared.Repairable;
|
||||
using Content.Shared.Tools;
|
||||
using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem;
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Server.EUI;
|
||||
using Content.Server.Ghost;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Components;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Timing;
|
||||
using Content.Shared.Tools.Components;
|
||||
using Content.Server.Construction.Conditions;
|
||||
//many of these arent reqired but some seem neessesary so ill leave them for now
|
||||
|
||||
namespace Content.Server.Repairable
|
||||
{
|
||||
public sealed class RepairableSystem : SharedRepairableSystem
|
||||
{
|
||||
[Dependency] private readonly EuiManager _euiManager = default!;
|
||||
[Dependency] private readonly SharedToolSystem _toolSystem = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger= default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -24,6 +46,8 @@ namespace Content.Server.Repairable
|
||||
|
||||
private void OnRepairFinished(EntityUid uid, RepairableComponent component, RepairFinishedEvent args)
|
||||
{
|
||||
ICommonSession? session = null;
|
||||
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
@@ -34,15 +58,36 @@ namespace Content.Server.Repairable
|
||||
{
|
||||
var damageChanged = _damageableSystem.TryChangeDamage(uid, component.Damage, true, false, origin: args.User);
|
||||
_adminLogger.Add(LogType.Healed, $"{ToPrettyString(args.User):user} repaired {ToPrettyString(uid):target} by {damageChanged?.GetTotal()}");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Repair all damage
|
||||
_damageableSystem.SetAllDamage(uid, damageable, 0);
|
||||
_adminLogger.Add(LogType.Healed, $"{ToPrettyString(args.User):user} repaired {ToPrettyString(uid):target} back to full health");
|
||||
}
|
||||
|
||||
// this is to revive gnomes and call their ghost back
|
||||
//check for target for threshholds, i hardly understand WHY this works but it does so i wont touch it
|
||||
if (TryComp(uid, out MobThresholdsComponent? mobthresholds))
|
||||
{
|
||||
if (_mobThreshold.TryGetThresholdForState(uid, MobState.Dead, out var threshold) &&
|
||||
TryComp<DamageableComponent>(uid, out var damageableComponent) &&
|
||||
damageableComponent.TotalDamage < threshold)
|
||||
{
|
||||
_mobState.ChangeMobState(uid, MobState.Alive, null, uid);
|
||||
}
|
||||
if (_mind.TryGetMind(uid, out _, out var mind) &&
|
||||
mind.Session is { } playerSession)
|
||||
{
|
||||
session = playerSession;
|
||||
// notify them they're being revived.
|
||||
if (mind.CurrentEntity != uid)
|
||||
{
|
||||
_euiManager.OpenEui(new ReturnToBodyEui(mind, _mind), session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
var str = Loc.GetString("comp-repairable-repair",
|
||||
("target", uid),
|
||||
("tool", args.Used!));
|
||||
|
||||
8
Content.Server/Speech/Components/GnomeAccentComponent.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace Content.Server.Speech.Components;
|
||||
|
||||
/// <summary>
|
||||
/// garden time
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class GnomeAccentComponent : Component
|
||||
{}
|
||||
52
Content.Server/Speech/EntitySystems/GnomeAccentSystem.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Content.Server.Speech.Components;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Content.Server.Speech.EntitySystems;
|
||||
|
||||
/// <summary>
|
||||
/// System that Gnomes the Gnomes talking
|
||||
/// </summary>
|
||||
public sealed class GnomeAccentSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ReplacementAccentSystem _replacement = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<GnomeAccentComponent, AccentGetEvent>(OnAccentGet);
|
||||
}
|
||||
public string Accentuate(string message, GnomeAccentComponent component)
|
||||
{
|
||||
var msg = message;
|
||||
|
||||
msg = _replacement.ApplyReplacements(msg, "gnome");
|
||||
|
||||
// Пиздец, а не код
|
||||
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bне", "ГНЕМ", RegexOptions.IgnoreCase);
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bнет", "ГНЕМТ", RegexOptions.IgnoreCase);
|
||||
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bнахуй", "ГНАМХУЙ", RegexOptions.IgnoreCase);
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bпидоры", "ГНОМЕРЫ", RegexOptions.IgnoreCase);
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bхуесос", "ГНОХУСОМ", RegexOptions.IgnoreCase);
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bебал", "ГНОМИЛ", RegexOptions.IgnoreCase);
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bзаебал", "ЗАГНОМИЛ", RegexOptions.IgnoreCase);
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bубил", "УГНОМИЛ", RegexOptions.IgnoreCase);
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bубит", "УГНОМЛЕН", RegexOptions.IgnoreCase);
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bебнул", "УГНОМЛЕН", RegexOptions.IgnoreCase);
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bстрелял", "СТРЕГНОМИЛ", RegexOptions.IgnoreCase);
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bзаколол", "СГНОМИЛ", RegexOptions.IgnoreCase);
|
||||
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bмой", "муй", RegexOptions.None);
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bдруг", "бро", RegexOptions.None);
|
||||
msg = Regex.Replace(msg, @"(?<!\w)\bдрузья", "друганы", RegexOptions.None);
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
private void OnAccentGet(EntityUid uid, GnomeAccentComponent component, AccentGetEvent args)
|
||||
{
|
||||
args.Message = Accentuate(args.Message, component);
|
||||
}
|
||||
}
|
||||
@@ -48,11 +48,11 @@ public sealed partial class MeteorSwarmComponent : Component
|
||||
public Dictionary<EntProtoId, float> Meteors = new();
|
||||
|
||||
[DataField]
|
||||
public MinMax Waves = new(3, 3);
|
||||
public MinMax Waves = new(2, 4);
|
||||
|
||||
[DataField]
|
||||
public MinMax MeteorsPerWave = new(3, 4);
|
||||
|
||||
[DataField]
|
||||
public MinMax WaveCooldown = new (10, 60);
|
||||
public MinMax WaveCooldown = new (30, 60);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
using System.Globalization;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Radio.EntitySystems;
|
||||
using Content.Shared._White.Announcement;
|
||||
using Content.Shared.Radio;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._White.Announcement;
|
||||
|
||||
public sealed class ArrivalNotificationSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly RadioSystem _radioSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeAllEvent<PlayerSpawnCompleteEvent>(OnPlayerSpawn);
|
||||
}
|
||||
|
||||
private void OnPlayerSpawn(PlayerSpawnCompleteEvent args)
|
||||
{
|
||||
if (args.JobId == null)
|
||||
return;
|
||||
|
||||
if (!_prototypeManager.TryIndex<JobPrototype>(args.JobId, out var jobPrototype))
|
||||
return;
|
||||
|
||||
if (jobPrototype.AnnouncementPrototype == null)
|
||||
return;
|
||||
|
||||
if (!_prototypeManager.TryIndex<ArrivalNotificationPrototype>(jobPrototype.AnnouncementPrototype, out var notification))
|
||||
return;
|
||||
|
||||
var message = GetMessage(args.Mob,
|
||||
jobPrototype,
|
||||
notification.UseGlobalAnnouncement ? notification.GlobalMessage : notification.Message);
|
||||
|
||||
var senderName = Loc.GetString("head-arrived-sender");
|
||||
var source = args.Station;
|
||||
|
||||
if (notification.UseGlobalAnnouncement)
|
||||
_chatSystem.DispatchGlobalAnnouncement(message, senderName, colorOverride: Color.Gold);
|
||||
|
||||
message = GetMessage(args.Mob, jobPrototype, notification.Message); // Changing message type for radio notification
|
||||
|
||||
foreach (var channel in notification.RadioChannelsPrototypes)
|
||||
{
|
||||
if (!_prototypeManager.TryIndex<RadioChannelPrototype>(channel, out _))
|
||||
continue;
|
||||
|
||||
_radioSystem.SendRadioMessage(source, message, channel, args.Mob);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private string GetMessage(EntityUid mob, JobPrototype jobPrototype, string type)
|
||||
{
|
||||
var message = Loc.GetString(type,
|
||||
("character", MetaData(mob).EntityName),
|
||||
("job", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(Loc.GetString(jobPrototype.Name))));
|
||||
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,16 @@
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server._White.Other.DeathGasps;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class DeathGaspsComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public SoundSpecifier DeathSounds = new SoundCollectionSpecifier("deathSounds");
|
||||
|
||||
[DataField]
|
||||
public SoundSpecifier HeartSounds = new SoundCollectionSpecifier("heartSounds");
|
||||
|
||||
[DataField]
|
||||
public bool CanOtherHearDeathSound;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@ public sealed class OnDeath : EntitySystem
|
||||
}
|
||||
|
||||
private readonly Dictionary<EntityUid, EntityUid> _playingStreams = new();
|
||||
private static readonly SoundSpecifier DeathSounds = new SoundCollectionSpecifier("deathSounds");
|
||||
private static readonly SoundSpecifier HeartSounds = new SoundCollectionSpecifier("heartSounds");
|
||||
|
||||
|
||||
private void HandleDeathEvent(EntityUid uid, DeathGaspsComponent component, MobStateChangedEvent args)
|
||||
{
|
||||
@@ -31,23 +30,23 @@ public sealed class OnDeath : EntitySystem
|
||||
StopPlayingStream(uid);
|
||||
break;
|
||||
case MobState.Critical:
|
||||
PlayPlayingStream(uid);
|
||||
PlayPlayingStream(uid, component);
|
||||
break;
|
||||
case MobState.Dead:
|
||||
StopPlayingStream(uid);
|
||||
PlayDeathSound(uid);
|
||||
PlayDeathSound(uid, component);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void PlayPlayingStream(EntityUid uid)
|
||||
private void PlayPlayingStream(EntityUid uid, DeathGaspsComponent component)
|
||||
{
|
||||
if (_playingStreams.TryGetValue(uid, out var currentStream))
|
||||
{
|
||||
_audio.Stop(currentStream);
|
||||
}
|
||||
|
||||
var newStream = _audio.PlayEntity(HeartSounds, uid, uid, AudioParams.Default.WithLoop(true));
|
||||
var newStream = _audio.PlayEntity(component.HeartSounds, uid, uid, AudioParams.Default.WithLoop(true));
|
||||
|
||||
if (newStream.HasValue)
|
||||
{
|
||||
@@ -64,9 +63,12 @@ public sealed class OnDeath : EntitySystem
|
||||
_playingStreams.Remove(uid);
|
||||
}
|
||||
|
||||
private void PlayDeathSound(EntityUid uid)
|
||||
private void PlayDeathSound(EntityUid uid, DeathGaspsComponent component)
|
||||
{
|
||||
_audio.PlayEntity(DeathSounds, uid, uid, AudioParams.Default);
|
||||
if (component.CanOtherHearDeathSound)
|
||||
_audio.PlayPvs(component.DeathSounds, uid, AudioParams.Default);
|
||||
else
|
||||
_audio.PlayEntity(component.DeathSounds, uid, uid, AudioParams.Default);
|
||||
}
|
||||
|
||||
private void OnDetach(EntityUid uid, DeathGaspsComponent component, PlayerDetachedEvent args)
|
||||
|
||||
@@ -63,7 +63,9 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
|
||||
Filter filter;
|
||||
if (ev.Global)
|
||||
{
|
||||
filter = Filter.Broadcast();
|
||||
}
|
||||
else
|
||||
{
|
||||
var station = _stationSystem.GetOwningStation(ev.Source);
|
||||
@@ -132,11 +134,7 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
|
||||
private async void OnEntitySpoke(EntityUid uid, SharedTTSComponent component, EntitySpokeEvent args)
|
||||
{
|
||||
if (!_isEnabled ||
|
||||
args.Message.Length > MaxMessageChars)
|
||||
return;
|
||||
|
||||
if (string.IsNullOrEmpty(_apiUrl))
|
||||
if (!_isEnabled || string.IsNullOrEmpty(_apiUrl) || args.Message.Length > MaxMessageChars)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -154,6 +152,7 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
var soundData = await GenerateTTS(uid, message, protoVoice.Speaker);
|
||||
if (soundData is null)
|
||||
return;
|
||||
|
||||
var ttsEvent = new PlayTTSEvent(GetNetEntity(uid), soundData, false);
|
||||
|
||||
// Say
|
||||
@@ -182,7 +181,6 @@ public sealed partial class TTSSystem : EntitySystem
|
||||
var sourcePos = _xforms.GetWorldPosition(xformQuery.GetComponent(uid), xformQuery);
|
||||
var receptions = Filter.Pvs(uid).Recipients;
|
||||
|
||||
|
||||
foreach (var session in receptions)
|
||||
{
|
||||
if (!session.AttachedEntity.HasValue)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Shared._White.Wizard;
|
||||
using Content.Shared._White.Wizard.Charging;
|
||||
using Content.Shared.Follower;
|
||||
using Content.Shared.Mobs;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Player;
|
||||
@@ -25,10 +26,13 @@ public sealed class ChargingSystem : SharedChargingSystem
|
||||
SubscribeNetworkEvent<RequestSpellChargingAudio>(OnCharging);
|
||||
SubscribeNetworkEvent<RequestSpellChargedAudio>(OnCharged);
|
||||
SubscribeNetworkEvent<RequestAudioSpellStop>(OnStop);
|
||||
|
||||
SubscribeLocalEvent<PlayerDetachedEvent>(OnDetach);
|
||||
SubscribeLocalEvent<MobStateChangedEvent>(OnStateChanged);
|
||||
|
||||
SubscribeNetworkEvent<AddWizardChargeEvent>(Add);
|
||||
SubscribeNetworkEvent<RemoveWizardChargeEvent>(Remove);
|
||||
|
||||
}
|
||||
|
||||
#region Audio
|
||||
@@ -103,40 +107,29 @@ public sealed class ChargingSystem : SharedChargingSystem
|
||||
if (user == null)
|
||||
return;
|
||||
|
||||
if (_chargingLoops.TryGetValue(user.Value, out var currentStream))
|
||||
{
|
||||
_audio.Stop(currentStream);
|
||||
_chargingLoops.Remove(user.Value);
|
||||
}
|
||||
|
||||
if (_chargedLoop.TryGetValue(user.Value, out var chargedLoop))
|
||||
{
|
||||
_audio.Stop(chargedLoop);
|
||||
_chargedLoop.Remove(user.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDetach(PlayerDetachedEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
var user = msg.Entity;
|
||||
|
||||
if (_chargingLoops.TryGetValue(user, out var currentStream))
|
||||
{
|
||||
_audio.Stop(currentStream);
|
||||
_chargingLoops.Remove(user);
|
||||
}
|
||||
|
||||
if (_chargedLoop.TryGetValue(user, out var chargedLoop))
|
||||
{
|
||||
_audio.Stop(chargedLoop);
|
||||
_chargedLoop.Remove(user);
|
||||
}
|
||||
StopAllSounds(user.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Charges
|
||||
|
||||
private void OnDetach(PlayerDetachedEvent msg)
|
||||
{
|
||||
var user = msg.Entity;
|
||||
|
||||
RemoveAllCharges(user);
|
||||
StopAllSounds(user);
|
||||
}
|
||||
|
||||
private void OnStateChanged(MobStateChangedEvent ev)
|
||||
{
|
||||
var user = ev.Target;
|
||||
|
||||
RemoveAllCharges(user);
|
||||
StopAllSounds(user);
|
||||
}
|
||||
|
||||
private void Add(AddWizardChargeEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (args.SenderSession.AttachedEntity != null)
|
||||
@@ -153,6 +146,21 @@ public sealed class ChargingSystem : SharedChargingSystem
|
||||
|
||||
#region Helpers
|
||||
|
||||
public void StopAllSounds(EntityUid uid)
|
||||
{
|
||||
if (_chargingLoops.TryGetValue(uid, out var currentStream))
|
||||
{
|
||||
_audio.Stop(currentStream);
|
||||
_chargingLoops.Remove(uid);
|
||||
}
|
||||
|
||||
if (_chargedLoop.TryGetValue(uid, out var chargedLoop))
|
||||
{
|
||||
_audio.Stop(chargedLoop);
|
||||
_chargedLoop.Remove(uid);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddCharge(EntityUid uid, string msgChargeProto)
|
||||
{
|
||||
var itemEnt = Spawn(msgChargeProto, Transform(uid).Coordinates);
|
||||
|
||||
@@ -2,6 +2,7 @@ using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Server._White.Cult;
|
||||
using Content.Server._White.IncorporealSystem;
|
||||
using Content.Server._White.Wizard.Charging;
|
||||
using Content.Server._White.Wizard.Magic.Amaterasu;
|
||||
using Content.Server._White.Wizard.Magic.Other;
|
||||
using Content.Server._White.Wizard.Magic.TeslaProjectile;
|
||||
@@ -80,6 +81,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
[Dependency] private readonly EuiManager _euiManager = default!;
|
||||
[Dependency] private readonly MindSystem _mindSystem = default!;
|
||||
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
|
||||
[Dependency] private readonly ChargingSystem _charging = default!;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -125,7 +127,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
msg.Handled = true;
|
||||
Cast(msg);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -143,8 +145,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
var comp = EnsureComp<PreventCollideComponent>(ent);
|
||||
comp.Uid = msg.Performer;
|
||||
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -187,8 +188,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
_standing.TryLieDown(uid);
|
||||
_standing.TryLieDown(target);
|
||||
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg);
|
||||
|
||||
SwapComponent<WizardComponent>(uid, target);
|
||||
SwapComponent<RevolutionaryComponent>(uid, target);
|
||||
@@ -213,8 +213,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
_euiManager.OpenEui(eui, actor.PlayerSession);
|
||||
eui.StateDirty();
|
||||
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg, false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -264,8 +263,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
_handsSystem.TryForcePickupAnyHand(msg.Performer, recallComponent.Item.Value);
|
||||
_audio.PlayPvs(recallComponent.RecallSound, msg.Performer);
|
||||
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -293,8 +291,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
|
||||
Spawn("AdminInstantEffectSmoke3", Transform(msg.Target).Coordinates);
|
||||
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -317,8 +314,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
|
||||
Spawn("AdminInstantEffectSmoke3", Transform(msg.Target).Coordinates);
|
||||
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -340,8 +336,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
|
||||
Spawn("AdminInstantEffectSmoke3", Transform(msg.Target).Coordinates);
|
||||
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -357,8 +352,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
|
||||
_empSystem.EmpPulse(coords, 15, 1000000, 60f);
|
||||
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -381,8 +375,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
_statusEffectsSystem.TryAddStatusEffect<IncorporealComponent>(msg.Performer, "Incorporeal",
|
||||
TimeSpan.FromSeconds(10), false);
|
||||
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -434,8 +427,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
Spawn("AdminInstantEffectSmoke3", oldCoords);
|
||||
Spawn("AdminInstantEffectSmoke3", coords);
|
||||
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -460,9 +452,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
break;
|
||||
}
|
||||
|
||||
SetCooldown(msg.Action, msg.ActionUseType);
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg);
|
||||
}
|
||||
|
||||
private void ForcewallSpellDefault(ForceWallSpellEvent msg)
|
||||
@@ -533,9 +523,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
SetCooldown(msg.Action, msg.ActionUseType);
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg);
|
||||
}
|
||||
|
||||
private void CardsSpellDefault(CardsSpellEvent msg)
|
||||
@@ -638,9 +626,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
SetCooldown(msg.Action, msg.ActionUseType);
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg);
|
||||
}
|
||||
|
||||
private void FireballSpellDefault(FireballSpellEvent msg)
|
||||
@@ -725,9 +711,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
SetCooldown(msg.Action, msg.ActionUseType);
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg);
|
||||
}
|
||||
|
||||
private bool ForceSpellAlt(ForceSpellEvent msg)
|
||||
@@ -782,9 +766,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
SetCooldown(msg.Action, msg.ActionUseType);
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
Cast(msg);
|
||||
}
|
||||
|
||||
private bool ArcSpellDefault(ArcSpellEvent msg)
|
||||
@@ -844,6 +826,17 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
RaiseLocalEvent(uid, new EnergyDomeClothesTurnOffEvent());
|
||||
}
|
||||
|
||||
public void Cast(BaseActionEvent msg, bool removeAllCharges = true)
|
||||
{
|
||||
SetCooldown(msg.Action, msg.ActionUseType);
|
||||
msg.Handled = true;
|
||||
Speak(msg);
|
||||
if (!removeAllCharges)
|
||||
return;
|
||||
_charging.RemoveAllCharges(msg.Performer);
|
||||
_charging.StopAllSounds(msg.Performer);
|
||||
}
|
||||
|
||||
public bool CanCast(BaseActionEvent msg)
|
||||
{
|
||||
return !msg.Handled && CheckRequirements(msg.Action, msg.Performer) &&
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.EUI;
|
||||
using Content.Server._White.Wizard.Charging;
|
||||
using Content.Server.EUI;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared._White.Wizard.Teleport;
|
||||
using Content.Shared.Eui;
|
||||
@@ -15,6 +16,7 @@ public sealed class WizardTeleportSpellEui : BaseEui
|
||||
private readonly TeleportLocationSystem _teleportLocation;
|
||||
private readonly PullingSystem _pulling;
|
||||
private readonly PopupSystem _popupSystem;
|
||||
private readonly ChargingSystem _charging;
|
||||
|
||||
private readonly EntityUid _performer;
|
||||
|
||||
@@ -28,6 +30,7 @@ public sealed class WizardTeleportSpellEui : BaseEui
|
||||
_pulling = _entityManager.System<PullingSystem>();
|
||||
_teleportLocation = _entityManager.System<TeleportLocationSystem>();
|
||||
_popupSystem = _entityManager.System<PopupSystem>();
|
||||
_charging = _entityManager.System<ChargingSystem>();
|
||||
|
||||
_performer = performer;
|
||||
|
||||
@@ -107,6 +110,9 @@ public sealed class WizardTeleportSpellEui : BaseEui
|
||||
_entityManager.SpawnEntity("AdminInstantEffectSmoke10", oldCoords);
|
||||
_entityManager.SpawnEntity("AdminInstantEffectSmoke10", coords);
|
||||
|
||||
_charging.RemoveAllCharges(_performer);
|
||||
_charging.StopAllSounds(_performer);
|
||||
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,13 +125,13 @@ namespace Content.Shared.CCVar
|
||||
/// Minimum time between meteor swarms in minutes.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float>
|
||||
MeteorSwarmMinTime = CVarDef.Create("events.meteor_swarm_min_time", 12.5f, CVar.ARCHIVE | CVar.SERVERONLY);
|
||||
MeteorSwarmMinTime = CVarDef.Create("events.meteor_swarm_min_time", 20f, CVar.ARCHIVE | CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// Maximum time between meteor swarms in minutes.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float>
|
||||
MeteorSwarmMaxTime = CVarDef.Create("events.meteor_swarm_max_time", 17.5f, CVar.ARCHIVE | CVar.SERVERONLY);
|
||||
MeteorSwarmMaxTime = CVarDef.Create("events.meteor_swarm_max_time", 30f, CVar.ARCHIVE | CVar.SERVERONLY);
|
||||
|
||||
/*
|
||||
* Game
|
||||
|
||||
@@ -19,16 +19,16 @@ namespace Content.Shared.Roles
|
||||
[IdDataField]
|
||||
public string ID { get; private set; } = default!;
|
||||
|
||||
[DataField("playTimeTracker", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<PlayTimeTrackerPrototype>))]
|
||||
[DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<PlayTimeTrackerPrototype>))]
|
||||
public string PlayTimeTracker { get; private set; } = string.Empty;
|
||||
|
||||
[DataField("supervisors")]
|
||||
[DataField]
|
||||
public string Supervisors { get; private set; } = "nobody";
|
||||
|
||||
/// <summary>
|
||||
/// The name of this job as displayed to players.
|
||||
/// </summary>
|
||||
[DataField("name")]
|
||||
[DataField]
|
||||
public string Name { get; private set; } = string.Empty;
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
@@ -37,22 +37,25 @@ namespace Content.Shared.Roles
|
||||
/// <summary>
|
||||
/// The name of this job as displayed to players.
|
||||
/// </summary>
|
||||
[DataField("description")]
|
||||
[DataField]
|
||||
public string? Description { get; private set; }
|
||||
|
||||
[ViewVariables(VVAccess.ReadOnly)]
|
||||
public string? LocalizedDescription => Description is null ? null : Loc.GetString(Description);
|
||||
|
||||
[DataField("requirements")]
|
||||
[DataField]
|
||||
public HashSet<JobRequirement>? Requirements;
|
||||
|
||||
[DataField("joinNotifyCrew")]
|
||||
[DataField]
|
||||
public bool JoinNotifyCrew { get; private set; } = false;
|
||||
|
||||
[DataField("requireAdminNotify")]
|
||||
[DataField]
|
||||
public string? AnnouncementPrototype;
|
||||
|
||||
[DataField]
|
||||
public bool RequireAdminNotify { get; private set; } = false;
|
||||
|
||||
[DataField("setPreference")]
|
||||
[DataField]
|
||||
public bool SetPreference { get; private set; } = true;
|
||||
|
||||
/// <summary>
|
||||
@@ -62,14 +65,14 @@ namespace Content.Shared.Roles
|
||||
[DataField]
|
||||
public bool? OverrideConsoleVisibility { get; private set; } = null;
|
||||
|
||||
[DataField("canBeAntag")]
|
||||
[DataField]
|
||||
public bool CanBeAntag { get; private set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this job is a head.
|
||||
/// The job system will try to pick heads before other jobs on the same priority level.
|
||||
/// </summary>
|
||||
[DataField("weight")]
|
||||
[DataField]
|
||||
public int Weight { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -86,10 +89,10 @@ namespace Content.Shared.Roles
|
||||
/// A numerical score for how much easier this job is for antagonists.
|
||||
/// For traitors, reduces starting TC by this amount. Other gamemodes can use it for whatever they find fitting.
|
||||
/// </summary>
|
||||
[DataField("antagAdvantage")]
|
||||
[DataField]
|
||||
public int AntagAdvantage = 0;
|
||||
|
||||
[DataField("startingGear", customTypeSerializer: typeof(PrototypeIdSerializer<StartingGearPrototype>))]
|
||||
[DataField(customTypeSerializer: typeof(PrototypeIdSerializer<StartingGearPrototype>))]
|
||||
public string? StartingGear { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
@@ -97,28 +100,28 @@ namespace Content.Shared.Roles
|
||||
/// Starting gear will be ignored.
|
||||
/// If you want to just add special attributes to a humanoid, use AddComponentSpecial instead.
|
||||
/// </summary>
|
||||
[DataField("jobEntity", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
[DataField(customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string? JobEntity = null;
|
||||
|
||||
[DataField("icon", customTypeSerializer: typeof(PrototypeIdSerializer<StatusIconPrototype>))]
|
||||
[DataField(customTypeSerializer: typeof(PrototypeIdSerializer<StatusIconPrototype>))]
|
||||
public string Icon { get; private set; } = "JobIconUnknown";
|
||||
|
||||
[DataField("special", serverOnly: true)]
|
||||
[DataField(serverOnly: true)]
|
||||
public JobSpecial[] Special { get; private set; } = Array.Empty<JobSpecial>();
|
||||
|
||||
[DataField("access")]
|
||||
[DataField]
|
||||
public IReadOnlyCollection<ProtoId<AccessLevelPrototype>> Access { get; private set; } = Array.Empty<ProtoId<AccessLevelPrototype>>();
|
||||
|
||||
[DataField("accessGroups")]
|
||||
[DataField]
|
||||
public IReadOnlyCollection<ProtoId<AccessGroupPrototype>> AccessGroups { get; private set; } = Array.Empty<ProtoId<AccessGroupPrototype>>();
|
||||
|
||||
[DataField("extendedAccess")]
|
||||
[DataField]
|
||||
public IReadOnlyCollection<ProtoId<AccessLevelPrototype>> ExtendedAccess { get; private set; } = Array.Empty<ProtoId<AccessLevelPrototype>>();
|
||||
|
||||
[DataField("extendedAccessGroups")]
|
||||
[DataField]
|
||||
public IReadOnlyCollection<ProtoId<AccessGroupPrototype>> ExtendedAccessGroups { get; private set; } = Array.Empty<ProtoId<AccessGroupPrototype>>();
|
||||
|
||||
[DataField("whitelistedSpecies")]
|
||||
[DataField]
|
||||
public IReadOnlyCollection<ProtoId<SpeciesPrototype>> WhitelistedSpecies { get; private set; } = Array.Empty<ProtoId<SpeciesPrototype>>();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._White.Announcement;
|
||||
|
||||
[Prototype("arrivalNotification")]
|
||||
public sealed partial class ArrivalNotificationPrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The message that the department will receive upon the player arrival
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public string Message = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The message that the station will receive upon the player arrival
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string GlobalMessage = default!;
|
||||
|
||||
/// <summary>
|
||||
/// ID of the channel where the player arrival will be announced.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public HashSet<string> RadioChannelsPrototypes = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the notification will be made to the entire station. If false, the notification will be on the department radio channel
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool UseGlobalAnnouncement;
|
||||
}
|
||||
BIN
Resources/Audio/Voice/Gnome/Gnome_Clumsy_Sound_Effect.ogg
Normal file
BIN
Resources/Audio/Voice/Gnome/Gnome_Woo_Sound_Effect.ogg
Normal file
BIN
Resources/Audio/White/Voice/Gnomes/Death1.ogg
Normal file
BIN
Resources/Audio/White/Voice/Gnomes/Death2.ogg
Normal file
BIN
Resources/Audio/White/Voice/Gnomes/Death3.ogg
Normal file
BIN
Resources/Audio/White/Voice/Gnomes/Death4.ogg
Normal file
BIN
Resources/Audio/White/Voice/Gnomes/Gnome1V1.ogg
Normal file
BIN
Resources/Audio/White/Voice/Gnomes/Gnome2V1.ogg
Normal file
BIN
Resources/Audio/White/Voice/Gnomes/Gnome3V1.ogg
Normal file
BIN
Resources/Audio/White/Voice/Gnomes/Gnome4V1.ogg
Normal file
BIN
Resources/Audio/White/Voice/Gnomes/Gnome5V1.ogg
Normal file
BIN
Resources/Audio/White/Voice/Gnomes/Gnome6V1.ogg
Normal file
BIN
Resources/Audio/White/Voice/Gnomes/Gnome7V1.ogg
Normal file
BIN
Resources/Audio/White/Voice/Gnomes/Gnome8V1.ogg
Normal file
@@ -5264,3 +5264,140 @@
|
||||
id: 339
|
||||
time: '2024-06-30T07:04:16.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/400
|
||||
- author: Warete
|
||||
changes:
|
||||
- message: "\u0423\u043F\u0440\u043E\u0449\u0435\u043D \u043A\u0440\u0430\u0444\u0442\
|
||||
\ \u043F\u0430\u0440\u044B \u0440\u0435\u0446\u0435\u043F\u0442\u043E\u0432"
|
||||
type: Fix
|
||||
id: 340
|
||||
time: '2024-07-01T04:33:47.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/401
|
||||
- author: ThereDrD
|
||||
changes:
|
||||
- message: "\u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u043E \u043E\u043F\u043E\
|
||||
\u0432\u0435\u0449\u0435\u043D\u0438\u0435 \u043E \u043F\u0440\u0438\u0431\u044B\
|
||||
\u0442\u0438\u0438 \u0433\u043B\u0430\u0432 \u043E\u0442\u0434\u0435\u043B\u043E\
|
||||
\u0432 \u0432 \u043A\u0430\u043D\u0430\u043B\u044B \u043E\u0442\u0434\u0435\u043B\
|
||||
\u0430 \u0438 \u0433\u043B\u043E\u0431\u0430\u043B\u044C\u043D\u043E\u0435 \u043E\
|
||||
\u043F\u043E\u0432\u0435\u0449\u0435\u043D\u0438\u0435"
|
||||
type: Add
|
||||
id: 341
|
||||
time: '2024-07-01T10:10:32.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/402
|
||||
- author: Aviu
|
||||
changes:
|
||||
- message: "\u0423 \u0441\u0432\u0435\u0442\u043E\u0432\u043E\u0433\u043E \u043A\
|
||||
\u043E\u043F\u044C\u044F \u0446\u0435\u043D\u0430 \u0441\u043D\u043E\u0432\u0430\
|
||||
\ 10, \u0443\u0440\u043E\u043D \u043E\u0442 \u0431\u0440\u043E\u0441\u043A\u0430\
|
||||
\ \u0441\u043D\u043E\u0432\u0430 60, \u043D\u043E \u043A\u0434 \u0442\u0435\u043F\
|
||||
\u0435\u0440\u044C 2.5 \u0441\u0435\u043A\u0443\u043D\u0434."
|
||||
type: Add
|
||||
id: 342
|
||||
time: '2024-07-01T11:36:15.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/405
|
||||
- author: ThereDrD
|
||||
changes:
|
||||
- message: "\u0423\u0431\u0440\u0430\u043D\u043E \u043B\u0438\u0448\u043D\u0435\u0435\
|
||||
\ \u043E\u043F\u043E\u0432\u0435\u0449\u0435\u043D\u0438\u0435 \u0441\u0442\u0430\
|
||||
\u043D\u0446\u0438\u0438 \u043E \u043F\u0440\u0438\u0431\u044B\u0442\u0438\u0438\
|
||||
\ \u0433\u043B\u0430\u0432\u044B"
|
||||
type: Fix
|
||||
id: 343
|
||||
time: '2024-07-01T13:02:51.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/407
|
||||
- author: Aviu
|
||||
changes:
|
||||
- message: "\u041E\u0442\u043A\u0430\u0442 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\
|
||||
\u0438\u0439, \u0441\u0432\u044F\u0437\u0430\u043D\u043D\u044B\u0445 \u0441\
|
||||
\ \u043E\u0433\u043D\u0435\u043C, \u043D\u043E \u043E\u0433\u043E\u043D\u044C\
|
||||
\ \u0432\u0441\u0435 \u0435\u0449\u0435 \u043C\u0435\u043D\u0435\u0435 \u043E\
|
||||
\u043F\u0430\u0441\u0435\u043D."
|
||||
type: Fix
|
||||
id: 344
|
||||
time: '2024-07-01T13:27:22.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/408
|
||||
- author: ThereDrD
|
||||
changes:
|
||||
- message: "\u041E\u043F\u043E\u0432\u0435\u0449\u0435\u043D\u0438\u0435 \u043E\
|
||||
\ \u0433\u043B\u0430\u0432\u0435 \u043E\u0442\u0434\u0435\u043B\u0430 \u0442\
|
||||
\u0435\u043F\u0435\u0440\u044C \u043E\u043F\u043E\u0432\u0435\u0449\u0430\u0435\
|
||||
\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0432 \u043E\u0434\u0438\
|
||||
\u043D \u043A\u0430\u043D\u0430\u043B"
|
||||
type: Tweak
|
||||
id: 345
|
||||
time: '2024-07-01T13:46:56.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/409
|
||||
- author: ThereDrD
|
||||
changes:
|
||||
- message: "\u041C\u0435\u0442\u0435\u043E\u0440\u043E\u0432 \u0434\u043E\u043B\u0436\
|
||||
\u043D\u043E \u0441\u0442\u0430\u0442\u044C \u043D\u0435\u043C\u043D\u043E\u0433\
|
||||
\u043E \u043C\u0435\u043D\u044C\u0448\u0435"
|
||||
type: Add
|
||||
id: 346
|
||||
time: '2024-07-02T09:55:38.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/410
|
||||
- author: ThereDrD
|
||||
changes:
|
||||
- message: "\u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u044B \u0413\u041D\u041E\
|
||||
\u041C\u042B. \u041E\u043D\u0438 \u043C\u043E\u0433\u0443\u0442 \u043F\u043E\
|
||||
\u043C\u043E\u0433\u0430\u0442\u044C \u0432 \u0441\u0430\u0434\u0443, \u0441\
|
||||
\u043C\u0435\u0448\u043D\u043E \u0433\u043E\u0432\u043E\u0440\u0438\u0442\u044C\
|
||||
, \u0441\u043C\u0435\u0448\u043D\u043E \u043A\u0440\u0438\u0447\u0430\u0442\u044C\
|
||||
, \u0441\u0438\u0434\u0435\u0442\u044C \u043D\u0430 \u0433\u043E\u043B\u043E\
|
||||
\u0432\u0435, \u0432\u043E\u0440\u043E\u0432\u0430\u0442\u044C, \u0438\u0441\
|
||||
\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C\u0441\u044F \u043A\
|
||||
\u0430\u043A \u043E\u0442\u0432\u0435\u0440\u0442\u043A\u0430 \u0438 \u0440\u0430\
|
||||
\u0437\u0431\u0438\u0432\u0430\u0442\u044C\u0441\u044F \u043E\u0431 \u0441\u0442\
|
||||
\u0435\u043D\u043A\u0443. \u0418\u0445 \u043C\u043E\u0436\u043D\u043E \u0432\
|
||||
\u044B\u0440\u0430\u0441\u0442\u0438\u0442\u044C, \u0438\u0441\u043F\u043E\u043B\
|
||||
\u044C\u0437\u0443\u044F \u0441\u043F\u0435\u0446\u0438\u0430\u043B\u044C\u043D\
|
||||
\u044B\u0435 \u0441\u0435\u043C\u0435\u043D\u0430. \u041D\u0435\u0441\u043A\u043E\
|
||||
\u043B\u044C\u043A\u043E \u0441\u0435\u043C\u044F\u043D \u043C\u043E\u0436\u043D\
|
||||
\u043E \u043D\u0430\u0439\u0442\u0438 \u0432 \u0432\u0435\u043D\u0434\u043E\u043C\
|
||||
\u0430\u0442\u0435 \u0431\u043E\u0442\u0430\u043D\u0438\u043A\u0430"
|
||||
type: Add
|
||||
id: 347
|
||||
time: '2024-07-02T09:55:25.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/411
|
||||
- author: ThereDrD
|
||||
changes:
|
||||
- message: "\u0423\u043C\u0435\u043D\u044C\u0448\u0435\u043D\u043E \u043A\u043E\u043B\
|
||||
\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0441\u0435\u043C\u044F\u043D \u0433\
|
||||
\u043D\u043E\u043C\u043E\u0432 \u0432 \u0430\u0432\u0442\u043E\u043C\u0430\u0442\
|
||||
\u0435 \u0431\u043E\u0442\u0430\u043D\u0438\u043A\u0430 \u0434\u043E 1"
|
||||
type: Tweak
|
||||
- message: "\u0422\u0435\u043F\u0435\u0440\u044C \u0434\u043B\u044F \u043F\u043E\
|
||||
\u043B\u0443\u0447\u0435\u043D\u0438\u044F \u0441\u0435\u043C\u044F\u043D \u0433\
|
||||
\u043D\u043E\u043C\u043E\u0432 \u0430\u0432\u0442\u043E\u043C\u0430\u0442 \u0431\
|
||||
\u043E\u0442\u0430\u043D\u0438\u043A\u043E\u0432 \u0442\u0440\u0435\u0431\u0443\
|
||||
\u0435\u0442\u0441\u044F \u0432\u0437\u043B\u043E\u043C\u0430\u0442\u044C"
|
||||
type: Tweak
|
||||
- message: "\u0423\u0440\u043E\u043D \u0433\u043D\u043E\u043C\u043E\u0432 \u043E\
|
||||
\u0442 \u0434\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u0443\u043C\u0435\u043D\
|
||||
\u044C\u0448\u0435\u043D"
|
||||
type: Tweak
|
||||
- message: "\u0420\u0430\u043D\u0434\u043E\u043C \u0438\u0433\u0440\u043E\u043A\u043E\
|
||||
\u0432 \u0434\u043B\u044F \u0433\u043E\u0441\u0442\u0440\u043E\u043B\u0438 \u0433\
|
||||
\u043D\u043E\u043C\u0430"
|
||||
type: Tweak
|
||||
- message: "\u0421\u0435\u043C\u0435\u043D\u0430 \u0433\u043D\u043E\u043C\u043E\u0432\
|
||||
\ \u0432 \u044F\u0449\u0438\u043A \u0441 \u044D\u043A\u0437\u043E\u0442\u0438\
|
||||
\u0447\u0435\u0441\u043A\u0438\u043C\u0438 \u0440\u0430\u0441\u0442\u0435\u043D\
|
||||
\u0438\u044F\u043C\u0438, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0437\u0430\
|
||||
\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442\u0441\u044F \u0432 \u043A\u0430\
|
||||
\u0440\u0433\u043E"
|
||||
type: Tweak
|
||||
id: 348
|
||||
time: '2024-07-02T15:12:29.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/412
|
||||
- author: Remuchi
|
||||
changes:
|
||||
- message: "\u0422\u0422\u0421 \u0441\u043E \u0432\u0441\u0435\u0439 \u0441\u0442\
|
||||
\u0430\u043D\u0446\u0438\u0438 \u0431\u043E\u043B\u044C\u0448\u0435 \u043D\u0435\
|
||||
\ \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u0441\u043B\
|
||||
\u044B\u0448\u0435\u043D \u0432 \u0441\u043B\u0443\u0447\u0430\u0439\u043D\u044B\
|
||||
\u0445 \u043C\u0435\u0441\u0442\u0430\u0445 \u043A\u0430\u0440\u0442\u044B."
|
||||
type: Fix
|
||||
id: 349
|
||||
time: '2024-07-02T15:56:53.0000000+00:00'
|
||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/413
|
||||
|
||||
@@ -232,3 +232,7 @@ ghost-role-information-artifact-name = Sentient Artifact
|
||||
ghost-role-information-artifact-description =
|
||||
Enact your eldritch whims.
|
||||
Forcibly activate your nodes for good or for evil.
|
||||
|
||||
|
||||
ghost-role-information-gnome-name = Garden Gnome
|
||||
ghost-role-information-gnome-description = You are the trusted keeper of the station garden, keep your domain safe.
|
||||
|
||||
@@ -111,3 +111,5 @@ seeds-pumpkin-name = pumpkin
|
||||
seeds-pumpkin-display-name = pumpkins
|
||||
seeds-cotton-name = cotton
|
||||
seeds-cotton-display-name = cotton plant
|
||||
seeds-gome-name = gnome
|
||||
seeds-gnome-display-name = gnome plant
|
||||
|
||||
3
Resources/Locale/ru-RU/_white/announce/announce.ftl
Normal file
@@ -0,0 +1,3 @@
|
||||
head-arrived-message = { $character }, { $job }, Глава отдела
|
||||
head-arrived-message-global = { $job } { $character } на станции
|
||||
head-arrived-sender = Автоматическая Система Оповещений
|
||||
6
Resources/Locale/ru-RU/_white/mobs/gnomes.ftl
Normal file
@@ -0,0 +1,6 @@
|
||||
ent-MobGnome = гном
|
||||
.desc = Добросовестный помощник по саду
|
||||
ent-GnomeSeeds = пакет семян гнома
|
||||
.desc = { ent-SeedBase.desc }
|
||||
ent-ClothingHeadHatGnome = шляпа гнома
|
||||
.desc = Шляпа настоящего садового помощника
|
||||
@@ -1,4 +1,4 @@
|
||||
- type: body
|
||||
- type: body
|
||||
id: Bot
|
||||
name: "bot"
|
||||
root: hand 1
|
||||
|
||||
19
Resources/Prototypes/Body/Prototypes/gnome.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
- type: body
|
||||
id: gnome
|
||||
name: "gnome"
|
||||
root: torso
|
||||
slots:
|
||||
torso:
|
||||
part: TorsoAnimal
|
||||
connections:
|
||||
- hands
|
||||
- legs
|
||||
organs:
|
||||
hands:
|
||||
part: HandsAnimal
|
||||
legs:
|
||||
part: LegsAnimal
|
||||
connections:
|
||||
- feet
|
||||
feet:
|
||||
part: FeetAnimal
|
||||
@@ -20,6 +20,8 @@
|
||||
amount: 2
|
||||
- id: BungoSeeds
|
||||
amount: 2
|
||||
- id: GnomeSeeds
|
||||
amount: 1
|
||||
|
||||
- type: entity
|
||||
id: CrateHydroponicsSeedsMedicinal
|
||||
|
||||
@@ -125,7 +125,19 @@
|
||||
- id: Soap
|
||||
prob: 0.10
|
||||
- id: PlushieCarp
|
||||
prob: 0.1
|
||||
prob: 0.2
|
||||
orGroup: carp
|
||||
- id: ClothingHeadHatGnome
|
||||
prob: 0.2
|
||||
- id: PlushieHolocarp
|
||||
prob: 0.05
|
||||
orGroup: carp
|
||||
- id: PlushieMagicarp
|
||||
prob: 0.05
|
||||
orGroup: carp
|
||||
- id: PlushieRainbowCarp
|
||||
prob: 0.03
|
||||
orGroup: carp
|
||||
- id: PlushieSlime
|
||||
prob: 0.1
|
||||
- id: PlushieSnake
|
||||
|
||||
@@ -37,5 +37,7 @@
|
||||
BerrySeeds: 5
|
||||
PeaSeeds: 5
|
||||
CottonSeeds: 5
|
||||
contrabandInventory:
|
||||
GnomeSeeds: 1
|
||||
emaggedInventory:
|
||||
FlyAmanitaSeeds: 1
|
||||
|
||||
@@ -1108,3 +1108,19 @@
|
||||
sprite: Clothing/Head/Hats/beret_medic.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Head/Hats/beret_medic.rsi
|
||||
|
||||
- type: entity
|
||||
parent: ClothingHeadBase
|
||||
id: ClothingHeadHatGnome
|
||||
name: gnome hat
|
||||
description: The cap of a true garden helper
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Head/Hats/hat_gnome.rsi
|
||||
- type: Clothing
|
||||
sprite: Clothing/Head/Hats/hat_gnome.rsi
|
||||
- type: Seed
|
||||
seedId: gnome
|
||||
- type: AddAccentClothing
|
||||
accent: GnomeAccent
|
||||
|
||||
|
||||
@@ -819,3 +819,182 @@
|
||||
# - type: AlwaysRevolutionaryConvertible
|
||||
- type: StealTarget
|
||||
stealGroup: AnimalTropico
|
||||
|
||||
|
||||
- type: entity #WHY MUST YOU THROW ERRORS HOW DARE YOU
|
||||
name: Gnome #this thing is covered in comments, its for my sanity, ignore them please.
|
||||
parent: [BaseSimpleMob, MobCombat, MobAtmosExposed]
|
||||
id: MobGnome
|
||||
description: "A garden's trusty helper"
|
||||
components:
|
||||
- type: Inventory
|
||||
templateId: gnome
|
||||
speciesId: gnome
|
||||
- type: InventorySlots
|
||||
- type: RotationVisuals
|
||||
defaultRotation: 90
|
||||
horizontalRotation: 90
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeCircle #displays error, works anyways so i wont touch it, whatever it does
|
||||
radius: 0.2
|
||||
density: 80
|
||||
mask:
|
||||
- SmallMobMask #lets em go under doors for escapes from sec/greytide/hunting mice
|
||||
layer:
|
||||
- SmallMobLayer
|
||||
- type: Stripping
|
||||
- type: Strippable
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
- key: enum.StrippingUiKey.Key
|
||||
type: StrippableBoundUserInterface
|
||||
- type: GhostRole
|
||||
prob: 1
|
||||
makeSentient: true
|
||||
allowSpeech: true
|
||||
allowMovement: true
|
||||
name: ghost-role-information-gnome-name
|
||||
description: ghost-role-information-gnome-description
|
||||
raffle:
|
||||
settings: short
|
||||
- type: GhostTakeoverAvailable
|
||||
- type: Flashable
|
||||
- type: Tag
|
||||
tags:
|
||||
- CannotSuicide
|
||||
- VimPilot
|
||||
- type: MobThresholds
|
||||
thresholds: #VERY easy to kill, if it was harder to kill them the sneaky fuckers would rule the world
|
||||
0: Alive
|
||||
10: Dead
|
||||
- type: DamageStateVisuals
|
||||
states:
|
||||
Alive:
|
||||
Base: Gnome-0
|
||||
Dead:
|
||||
Base: dead-1
|
||||
- type: GnomeAccent
|
||||
- type: NameIdentifier
|
||||
group: Gnome
|
||||
- type: Sprite
|
||||
drawdepth: SmallMobs
|
||||
sprite: Mobs/Animals/gnome.rsi
|
||||
layers:
|
||||
- map: ["enum.DamageStateVisualLayers.Base"]
|
||||
state: Gnome-0
|
||||
- type: Item
|
||||
size: Small
|
||||
- type: Clothing #TO VALLHALLA
|
||||
quickEquip: false
|
||||
sprite: Mobs/Animals/gnome.rsi
|
||||
equippedPrefix: 1
|
||||
slots:
|
||||
- HEAD
|
||||
- type: IdExaminable
|
||||
- type: InteractionPopup
|
||||
interactSuccessString: hugging-success-generic
|
||||
interactSuccessSound: /Audio/Effects/thudswoosh.ogg
|
||||
messagePerceivedByOthers: hugging-success-generic-others
|
||||
- type: MeleeWeapon
|
||||
soundHit:
|
||||
collection: ToySqueak
|
||||
angle: 30
|
||||
animation: WeaponArcPunch
|
||||
damage:
|
||||
types:
|
||||
Piercing: 3
|
||||
- type: Puller #dont need hands because they are at a disadvantage anyway, this way they can hold a light and drag a box for a backpack
|
||||
needsHands: false
|
||||
- type: CanHostGuardian #touch this stuff to make the fuckers hold still when not possesed (NOT THE GAURDIAN)
|
||||
- type: FactionException
|
||||
- type: NpcFactionMember
|
||||
factions:
|
||||
- Passive
|
||||
- type: Hands #gives em hands, the item sprites for holding things look all strange but its FINE, I DONT WANNA FIX IT ITS FINE ILL DO IT LATER
|
||||
- type: Body #gives em a body, is needed for organs and hands
|
||||
prototype: gnome
|
||||
requiredLegs: 0
|
||||
- type: Clumsy #no guns for youuuu if they shoot a gun they die >:3
|
||||
clumsyDamage:
|
||||
types:
|
||||
Blunt: 2
|
||||
Piercing: 7
|
||||
groups:
|
||||
Burn: 2
|
||||
clumsySound:
|
||||
path: /Audio/Voice/Gnome/Gnome_Clumsy_Sound_Effect.ogg
|
||||
- type: Barotrauma #gnomes instantly explode in space, gnomes shouldnt go in space
|
||||
damage:
|
||||
types:
|
||||
Blunt: 20 #per second, scales with pressure and other constants.
|
||||
- type: Repairable
|
||||
fuelCost: 5
|
||||
qualityNeeded: Gluing
|
||||
doAfterDelay: 8
|
||||
- type: ZombieImmune
|
||||
- type: Damageable
|
||||
damageContainer: StructuralInorganic
|
||||
- type: CanEscapeInventory
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTypeTrigger #gnomes gib once they are in enough bits that they cant be glued back together
|
||||
damageType: Blunt
|
||||
damage: 60
|
||||
behaviors:
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
collection: GlassBreak
|
||||
- !type:SpawnEntitiesBehavior
|
||||
spawn:
|
||||
ClothingHeadHatGnome:
|
||||
min: 1
|
||||
max: 1
|
||||
ShardGlass:
|
||||
min: 1
|
||||
max: 3
|
||||
- !type:DoActsBehavior
|
||||
acts: [ "Destruction" ]
|
||||
- type: DamageOnHighSpeedImpact #gnomes break when thrown, another anti gnometide device
|
||||
minimumSpeed: 10
|
||||
damage:
|
||||
types:
|
||||
Blunt: 20
|
||||
soundHit:
|
||||
collection: GlassBreak
|
||||
- type: Vocal
|
||||
sounds:
|
||||
Male: Gnome
|
||||
Female: Gnome
|
||||
Unsexed: Gnome
|
||||
wilhelmProbability: 0.0001
|
||||
- type: Unrevivable
|
||||
- type: Tool
|
||||
qualities:
|
||||
- Screwing
|
||||
useSound:
|
||||
collection: Screwdriver
|
||||
- type: FelinidFood
|
||||
- type: Speech
|
||||
speechSounds: GnomesSpeech
|
||||
speechVerb: SmallMob
|
||||
- type: Extractable
|
||||
grindableSolutionName: food
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
food:
|
||||
reagents:
|
||||
- ReagentId: UnstableMutagen
|
||||
Quantity: 5
|
||||
- type: BadFood
|
||||
- type: DeathGasps
|
||||
deathSounds:
|
||||
collection: GnomesDeathCollection
|
||||
canOtherHearDeathSound: True
|
||||
- type: Thieving
|
||||
stripTimeReduction: 4
|
||||
- type: Pacified
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
map: [ "enum.SolutionContainerLayers.Overlay" ]
|
||||
- type: Appearance
|
||||
- type: Glue
|
||||
- type: RefillableSolution
|
||||
solution: drink
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
drink:
|
||||
@@ -26,6 +28,11 @@
|
||||
reagents:
|
||||
- ReagentId: SpaceGlue
|
||||
Quantity: 30
|
||||
Welder:
|
||||
reagents:
|
||||
- ReagentId: SpaceGlue
|
||||
Quantity: 30
|
||||
maxVol: 30
|
||||
- type: SolutionContainerVisuals
|
||||
maxFillLevels: 6
|
||||
fillBaseName: fill
|
||||
@@ -38,8 +45,15 @@
|
||||
- type: Tag
|
||||
tags:
|
||||
- DrinkSpaceGlue
|
||||
- GlueTool
|
||||
- type: TrashOnSolutionEmpty
|
||||
solution: drink
|
||||
- type: Tool
|
||||
qualities: Gluing
|
||||
- type: Welder #this here uses welding code to take fuel out of the bottle (fuel being glue)
|
||||
fuelSolutionName: drink
|
||||
fuelReagent: SpaceGlue
|
||||
hiddenInfo: true
|
||||
|
||||
- type: entity
|
||||
parent: DrinkBase
|
||||
|
||||
@@ -1514,6 +1514,8 @@
|
||||
- type: Tag
|
||||
tags:
|
||||
- DrinkSpaceGlue
|
||||
- type: Tool
|
||||
qualities: Gluing
|
||||
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
|
||||
@@ -571,3 +571,13 @@
|
||||
seedId: cotton
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Hydroponics/cotton.rsi
|
||||
|
||||
- type: entity #you should never see this, this is for testing, if someone has these then I FUCKED UP and you should ping BITTERLYNX
|
||||
parent: SeedBase
|
||||
name: packet of Gnome seeds
|
||||
id: GnomeSeeds
|
||||
components:
|
||||
- type: Seed
|
||||
seedId: gnome
|
||||
- type: Sprite
|
||||
sprite: Objects/Specific/Hydroponics/cotton.rsi
|
||||
|
||||
@@ -1501,3 +1501,22 @@
|
||||
Max: 10
|
||||
PotencyDivisor: 20
|
||||
|
||||
- type: seed #once again, replacing learning with comments because ive been in this file for 10 hours
|
||||
id: gnome
|
||||
name: seeds-gome-name #the name of the seeds
|
||||
noun: seeds-noun-seeds
|
||||
displayName: seeds-gnome-display-name #name of the plant when looking at the tray
|
||||
plantRsi: Objects/Specific/Hydroponics/gnome.rsi
|
||||
packetPrototype: GnomeSeeds #seeds you get when clipping? BUT YOU CANT CLIP THIS PLANT TAKE THAT BOTANISTS!
|
||||
productPrototypes:
|
||||
- MobGnome #THE THING THAT SPAWNS!
|
||||
lifespan: 25
|
||||
maturation: 10
|
||||
production: 1
|
||||
yield: 1
|
||||
potency: 1
|
||||
idealLight: 8
|
||||
growthStages: 2
|
||||
waterConsumption: 0
|
||||
seedless: true #fuckin does nothing but im keeping it just in case someone wants botany to riot
|
||||
unclippable: true
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
- type: inventoryTemplate
|
||||
id: gnome
|
||||
#slots: i was on the fence to give them an id slot so ill comment this out for now
|
||||
# - name: id
|
||||
# slotTexture: id
|
||||
# slotFlags: IDCARD
|
||||
# slotGroup: SecondHotbar
|
||||
# stripTime: 6
|
||||
# uiWindowPos: 2,1
|
||||
# strippingWindowPos: 2,4
|
||||
# dependsOn: jumpsuit
|
||||
# displayName: ID
|
||||
|
||||
@@ -32,12 +32,5 @@
|
||||
icon:
|
||||
sprite: Objects/Misc/stock_parts.rsi
|
||||
state: capacitor
|
||||
doAfter: 5
|
||||
- tag: CapacitorStockPart
|
||||
name: capacitor
|
||||
icon:
|
||||
sprite: Objects/Misc/stock_parts.rsi
|
||||
state: capacitor
|
||||
doAfter: 5
|
||||
- node: medsecHud
|
||||
entity: ClothingEyesHudMedSec
|
||||
|
||||
@@ -65,10 +65,5 @@
|
||||
icon:
|
||||
sprite: Objects/Misc/stock_parts.rsi
|
||||
state: capacitor
|
||||
- tag: CapacitorStockPart
|
||||
name: capacitor
|
||||
icon:
|
||||
sprite: Objects/Misc/stock_parts.rsi
|
||||
state: capacitor
|
||||
- node: potatoaichip
|
||||
entity: PotatoAIChip
|
||||
entity: PotatoAIChip
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
weight: 10
|
||||
startingGear: QuartermasterGear
|
||||
icon: "JobIconQuarterMaster"
|
||||
announcementPrototype: QuartermasterArrivalNotification
|
||||
supervisors: job-supervisors-captain
|
||||
whitelistedSpecies:
|
||||
- Human
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
icon: "JobIconCaptain"
|
||||
requireAdminNotify: true
|
||||
joinNotifyCrew: true
|
||||
announcementPrototype: CaptainArrivalNotification
|
||||
supervisors: job-supervisors-centcom
|
||||
whitelistedSpecies:
|
||||
- Human
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
startingGear: HoPGear
|
||||
icon: "JobIconHeadOfPersonnel"
|
||||
requireAdminNotify: true
|
||||
announcementPrototype: HeadOfPersonnelArrivalNotification
|
||||
supervisors: job-supervisors-captain
|
||||
whitelistedSpecies:
|
||||
- Human
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
startingGear: ChiefEngineerGear
|
||||
icon: "JobIconChiefEngineer"
|
||||
requireAdminNotify: true
|
||||
announcementPrototype: ChiefEngineerArrivalNotification
|
||||
supervisors: job-supervisors-captain
|
||||
whitelistedSpecies:
|
||||
- Human
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
time: 36000 #10 hrs
|
||||
startingGear: InspectorGear
|
||||
icon: "JobIconInspector"
|
||||
announcementPrototype: InspectorArrivalNotification
|
||||
supervisors: job-supervisors-captain
|
||||
access:
|
||||
- Service
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
weight: 10
|
||||
startingGear: CMOGear
|
||||
icon: "JobIconChiefMedicalOfficer"
|
||||
announcementPrototype: ChiefMedicalOfficerArrivalNotification
|
||||
requireAdminNotify: true
|
||||
supervisors: job-supervisors-captain
|
||||
whitelistedSpecies:
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
startingGear: ResearchDirectorGear
|
||||
icon: "JobIconResearchDirector"
|
||||
requireAdminNotify: true
|
||||
announcementPrototype: ResearchDirectorArrivalNotification
|
||||
supervisors: job-supervisors-captain
|
||||
whitelistedSpecies:
|
||||
- Human
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
startingGear: HoSGear
|
||||
icon: "JobIconHeadOfSecurity"
|
||||
requireAdminNotify: true
|
||||
announcementPrototype: HeadOfSecurityArrivalNotification
|
||||
supervisors: job-supervisors-captain
|
||||
whitelistedSpecies:
|
||||
- Human
|
||||
|
||||
@@ -620,3 +620,13 @@
|
||||
path: /Audio/Animals/parrot_raught.ogg
|
||||
params:
|
||||
variation: 0.125
|
||||
|
||||
- type: emoteSounds
|
||||
id: Gnome
|
||||
params:
|
||||
variation: 0.125
|
||||
sounds:
|
||||
Scream:
|
||||
path: /Audio/Voice/Gnome/Gnome_Woo_Sound_Effect.ogg
|
||||
Weh:
|
||||
collection: Weh
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
noSpawn: true
|
||||
components:
|
||||
- type: InstantAction
|
||||
useDelay: 1.5
|
||||
useDelay: 2.5
|
||||
itemIconStyle: BigAction
|
||||
priority: -20
|
||||
icon:
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
- type: arrivalNotification
|
||||
id: CaptainArrivalNotification
|
||||
message: head-arrived-message
|
||||
globalMessage: head-arrived-message-global
|
||||
radioChannelsPrototypes:
|
||||
- Command
|
||||
useGlobalAnnouncement: True
|
||||
|
||||
- type: arrivalNotification
|
||||
id: HeadOfPersonnelArrivalNotification
|
||||
message: head-arrived-message
|
||||
radioChannelsPrototypes:
|
||||
- Service
|
||||
|
||||
- type: arrivalNotification
|
||||
id: HeadOfSecurityArrivalNotification
|
||||
message: head-arrived-message
|
||||
radioChannelsPrototypes:
|
||||
- Security
|
||||
|
||||
- type: arrivalNotification
|
||||
id: ChiefMedicalOfficerArrivalNotification
|
||||
message: head-arrived-message
|
||||
radioChannelsPrototypes:
|
||||
- Medical
|
||||
|
||||
- type: arrivalNotification
|
||||
id: ChiefEngineerArrivalNotification
|
||||
message: head-arrived-message
|
||||
radioChannelsPrototypes:
|
||||
- Engineering
|
||||
|
||||
- type: arrivalNotification
|
||||
id: ResearchDirectorArrivalNotification
|
||||
message: head-arrived-message
|
||||
radioChannelsPrototypes:
|
||||
- Science
|
||||
|
||||
- type: arrivalNotification
|
||||
id: QuartermasterArrivalNotification
|
||||
message: head-arrived-message
|
||||
radioChannelsPrototypes:
|
||||
- Cargo
|
||||
|
||||
- type: arrivalNotification
|
||||
id: InspectorArrivalNotification
|
||||
message: head-arrived-message
|
||||
radioChannelsPrototypes:
|
||||
- Security
|
||||
@@ -93,7 +93,7 @@
|
||||
icon: { sprite: /Textures/White/Objects/Weapons/hardlight_spear.rsi, state: spear }
|
||||
productEntity: HardlightSpearImplanter
|
||||
cost:
|
||||
Telecrystal: 12
|
||||
Telecrystal: 10
|
||||
categories:
|
||||
- UplinkImplants
|
||||
conditions:
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
- type: DamageOtherOnHit
|
||||
damage:
|
||||
types:
|
||||
Piercing: 20
|
||||
Heat: 20
|
||||
Piercing: 30
|
||||
Heat: 30
|
||||
- type: Wieldable
|
||||
- type: IncreaseDamageOnWield
|
||||
damage:
|
||||
|
||||
@@ -61,8 +61,8 @@
|
||||
ckey: reider207
|
||||
sprite: White/Ghosts/reider207-ghost.rsi
|
||||
alpha: 0.8
|
||||
ghostName: Соня
|
||||
ghostDescription: Видишь спит соня? Так не буди
|
||||
ghostName: Tighnari
|
||||
ghostDescription: But what are they going to do, lock me up?
|
||||
size: 0.8, 0.8
|
||||
|
||||
#mikvisan
|
||||
|
||||
8
Resources/Prototypes/_White/Sound/Speech/gnomes.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
- type: speechSounds
|
||||
id: GnomesSpeech
|
||||
saySound:
|
||||
collection: GnomesSpeechCollection
|
||||
askSound:
|
||||
collection: GnomesSpeechCollection
|
||||
exclaimSound:
|
||||
collection: GnomesSpeechCollection
|
||||
19
Resources/Prototypes/_White/SoundCollections/gnomes.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
- type: soundCollection
|
||||
id: GnomesSpeechCollection
|
||||
files:
|
||||
- /Audio/White/Voice/Gnomes/Gnome1V1.ogg
|
||||
- /Audio/White/Voice/Gnomes/Gnome2V1.ogg
|
||||
- /Audio/White/Voice/Gnomes/Gnome3V1.ogg
|
||||
- /Audio/White/Voice/Gnomes/Gnome4V1.ogg
|
||||
- /Audio/White/Voice/Gnomes/Gnome5V1.ogg
|
||||
- /Audio/White/Voice/Gnomes/Gnome6V1.ogg
|
||||
- /Audio/White/Voice/Gnomes/Gnome7V1.ogg
|
||||
- /Audio/White/Voice/Gnomes/Gnome8V1.ogg
|
||||
|
||||
- type: soundCollection
|
||||
id: GnomesDeathCollection
|
||||
files:
|
||||
- /Audio/White/Voice/Gnomes/Death1.ogg
|
||||
- /Audio/White/Voice/Gnomes/Death2.ogg
|
||||
- /Audio/White/Voice/Gnomes/Death3.ogg
|
||||
- /Audio/White/Voice/Gnomes/Death4.ogg
|
||||
12
Resources/Prototypes/_White/Spawners/spawners.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
- type: entity
|
||||
name: Gnome spawner
|
||||
id: SpawnMobGnome
|
||||
parent: MarkerBase
|
||||
components:
|
||||
- type: Sprite
|
||||
layers:
|
||||
- state: green
|
||||
- state: ai
|
||||
- type: ConditionalSpawner
|
||||
prototypes:
|
||||
- MobGnome
|
||||
@@ -15,12 +15,15 @@
|
||||
- type: Clothing
|
||||
sprite: White/Objects/Weapons/Chaplain/hfrequency.rsi
|
||||
slots:
|
||||
- back
|
||||
- suitStorage
|
||||
- none
|
||||
- type: Reflect
|
||||
reflectProb: 0.4
|
||||
- type: Item
|
||||
sprite: White/Objects/Weapons/Chaplain/hfrequency.rsi
|
||||
size: Large
|
||||
storedRotation: 44
|
||||
shape:
|
||||
- 0, 0, 3, 0
|
||||
|
||||
- type: entity
|
||||
name: клинок заклинаний
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
rules:
|
||||
- RampingStationEventScheduler
|
||||
- BasicRoundstartVariation
|
||||
- GameRuleMeteorScheduler
|
||||
|
||||
- type: gamePreset
|
||||
id: AllAtOnce
|
||||
@@ -24,6 +25,7 @@
|
||||
- Cult
|
||||
- Wizard
|
||||
- BasicRoundstartVariation
|
||||
- GameRuleMeteorScheduler
|
||||
|
||||
- type: gamePreset
|
||||
id: Extended
|
||||
@@ -175,6 +177,7 @@
|
||||
- Pirates
|
||||
- BasicStationEventScheduler
|
||||
- BasicRoundstartVariation
|
||||
- GameRuleMeteorScheduler
|
||||
|
||||
#WD EDIT START
|
||||
- type: gamePreset
|
||||
@@ -190,6 +193,7 @@
|
||||
- SubGamemodesRule
|
||||
- BasicStationEventScheduler
|
||||
- BasicRoundstartVariation
|
||||
- GameRuleMeteorScheduler
|
||||
|
||||
- type: gamePreset
|
||||
id: Changeling
|
||||
@@ -204,6 +208,7 @@
|
||||
- SubGamemodesRule
|
||||
- BasicStationEventScheduler
|
||||
- BasicRoundstartVariation
|
||||
- GameRuleMeteorScheduler
|
||||
|
||||
- type: gamePreset
|
||||
id: Wizard
|
||||
@@ -219,4 +224,5 @@
|
||||
- SubGamemodesRule
|
||||
- BasicStationEventScheduler
|
||||
- BasicRoundstartVariation
|
||||
- GameRuleMeteorScheduler
|
||||
#WD EDIT END
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
# Non-fungible apes, anyone?
|
||||
# Non-fungible apes, anyone?
|
||||
- type: nameIdentifierGroup
|
||||
id: Monkey
|
||||
prefix: MK
|
||||
|
||||
- type: nameIdentifierGroup
|
||||
id: Gnome
|
||||
prefix: GN
|
||||
|
||||
- type: nameIdentifierGroup
|
||||
id: Kobold
|
||||
prefix: KB
|
||||
|
||||
@@ -644,6 +644,9 @@
|
||||
- type: Tag
|
||||
id: Grenade
|
||||
|
||||
- type: Tag # tag to make a glue tool use glue on repair
|
||||
id: GlueTool
|
||||
|
||||
- type: Tag
|
||||
id: HudMedical
|
||||
|
||||
@@ -1325,5 +1328,3 @@
|
||||
|
||||
- type: Tag
|
||||
id: WriteIgnoreStamps
|
||||
|
||||
# ALPHABETICAL
|
||||
|
||||
@@ -74,3 +74,10 @@
|
||||
toolName: tool-quality-rolling-tool-name
|
||||
spawn: RollingPin
|
||||
icon: { sprite: Objects/Tools/rolling_pin.rsi, state: icon }
|
||||
|
||||
- type: tool
|
||||
id: Gluing
|
||||
name: tool-quality-gluing-name
|
||||
toolName: tool-quality-rolling-tool-name
|
||||
spawn: DrinkSpaceGlue
|
||||
icon: { sprite: Objects/Tools/rolling_pin.rsi, state: icon }
|
||||
|
||||
|
After Width: | Height: | Size: 368 B |
BIN
Resources/Textures/Clothing/Head/Hats/hat_gnome.rsi/icon.png
Normal file
|
After Width: | Height: | Size: 631 B |
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Sprited by DanoftheE (Discord)",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
|
||||
{
|
||||
"name": "equipped-HELMET",
|
||||
"directions": 4
|
||||
},
|
||||
|
||||
{
|
||||
"name": "icon"
|
||||
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
Resources/Textures/Mobs/Animals/gnome.rsi/0-equipped-HELMET.png
Normal file
|
After Width: | Height: | Size: 827 B |
BIN
Resources/Textures/Mobs/Animals/gnome.rsi/1-equipped-HELMET.png
Normal file
|
After Width: | Height: | Size: 827 B |
BIN
Resources/Textures/Mobs/Animals/gnome.rsi/Gnome-0.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Resources/Textures/Mobs/Animals/gnome.rsi/Gnome-1.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Resources/Textures/Mobs/Animals/gnome.rsi/dead-1.png
Normal file
|
After Width: | Height: | Size: 430 B |
63
Resources/Textures/Mobs/Animals/gnome.rsi/meta.json
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Sprited by DanoftheE (Discord)",
|
||||
"states": [
|
||||
{
|
||||
"name": "dead-1",
|
||||
"delays": [
|
||||
[
|
||||
1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Gnome-0",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
1
|
||||
],
|
||||
[
|
||||
1
|
||||
],
|
||||
[
|
||||
1
|
||||
],
|
||||
[
|
||||
1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Gnome-1",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
1
|
||||
],
|
||||
[
|
||||
1
|
||||
],
|
||||
[
|
||||
1
|
||||
],
|
||||
[
|
||||
1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "0-equipped-HELMET",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "1-equipped-HELMET",
|
||||
"directions": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 444 B |
|
After Width: | Height: | Size: 443 B |
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Sprited by DanoftheE (Discord)",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "dead"
|
||||
},
|
||||
{
|
||||
"name": "harvest"
|
||||
},
|
||||
{
|
||||
"name": "stage-1"
|
||||
},
|
||||
{
|
||||
"name": "stage-2"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 173 B |
|
After Width: | Height: | Size: 246 B |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 18 KiB |
@@ -3,8 +3,8 @@
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "reider207",
|
||||
"size": {
|
||||
"x": 64,
|
||||
"y": 64
|
||||
"x": 128,
|
||||
"y": 128
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
|
||||