Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Jabak
2024-07-02 21:26:29 +03:00
94 changed files with 1225 additions and 372 deletions

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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>

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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!));

View File

@@ -0,0 +1,8 @@
namespace Content.Server.Speech.Components;
/// <summary>
/// garden time
/// </summary>
[RegisterComponent]
public sealed partial class GnomeAccentComponent : Component
{}

View 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);
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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);

View File

@@ -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) &&

View File

@@ -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();
}
}

View File

@@ -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

View File

@@ -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>>();
}

View File

@@ -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;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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

View File

@@ -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.

View File

@@ -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

View File

@@ -0,0 +1,3 @@
head-arrived-message = { $character }, { $job }, Глава отдела
head-arrived-message-global = { $job } { $character } на станции
head-arrived-sender = Автоматическая Система Оповещений

View File

@@ -0,0 +1,6 @@
ent-MobGnome = гном
.desc = Добросовестный помощник по саду
ent-GnomeSeeds = пакет семян гнома
.desc = { ent-SeedBase.desc }
ent-ClothingHeadHatGnome = шляпа гнома
.desc = Шляпа настоящего садового помощника

View File

@@ -1,4 +1,4 @@
- type: body
- type: body
id: Bot
name: "bot"
root: hand 1

View 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

View File

@@ -20,6 +20,8 @@
amount: 2
- id: BungoSeeds
amount: 2
- id: GnomeSeeds
amount: 1
- type: entity
id: CrateHydroponicsSeedsMedicinal

View File

@@ -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

View File

@@ -37,5 +37,7 @@
BerrySeeds: 5
PeaSeeds: 5
CottonSeeds: 5
contrabandInventory:
GnomeSeeds: 1
emaggedInventory:
FlyAmanitaSeeds: 1

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -1514,6 +1514,8 @@
- type: Tag
tags:
- DrinkSpaceGlue
- type: Tool
qualities: Gluing
- type: entity
parent: BaseItem

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -15,6 +15,7 @@
weight: 10
startingGear: QuartermasterGear
icon: "JobIconQuarterMaster"
announcementPrototype: QuartermasterArrivalNotification
supervisors: job-supervisors-captain
whitelistedSpecies:
- Human

View File

@@ -20,6 +20,7 @@
icon: "JobIconCaptain"
requireAdminNotify: true
joinNotifyCrew: true
announcementPrototype: CaptainArrivalNotification
supervisors: job-supervisors-centcom
whitelistedSpecies:
- Human

View File

@@ -19,6 +19,7 @@
startingGear: HoPGear
icon: "JobIconHeadOfPersonnel"
requireAdminNotify: true
announcementPrototype: HeadOfPersonnelArrivalNotification
supervisors: job-supervisors-captain
whitelistedSpecies:
- Human

View File

@@ -16,6 +16,7 @@
startingGear: ChiefEngineerGear
icon: "JobIconChiefEngineer"
requireAdminNotify: true
announcementPrototype: ChiefEngineerArrivalNotification
supervisors: job-supervisors-captain
whitelistedSpecies:
- Human

View File

@@ -14,6 +14,7 @@
time: 36000 #10 hrs
startingGear: InspectorGear
icon: "JobIconInspector"
announcementPrototype: InspectorArrivalNotification
supervisors: job-supervisors-captain
access:
- Service

View File

@@ -14,6 +14,7 @@
weight: 10
startingGear: CMOGear
icon: "JobIconChiefMedicalOfficer"
announcementPrototype: ChiefMedicalOfficerArrivalNotification
requireAdminNotify: true
supervisors: job-supervisors-captain
whitelistedSpecies:

View File

@@ -13,6 +13,7 @@
startingGear: ResearchDirectorGear
icon: "JobIconResearchDirector"
requireAdminNotify: true
announcementPrototype: ResearchDirectorArrivalNotification
supervisors: job-supervisors-captain
whitelistedSpecies:
- Human

View File

@@ -16,6 +16,7 @@
startingGear: HoSGear
icon: "JobIconHeadOfSecurity"
requireAdminNotify: true
announcementPrototype: HeadOfSecurityArrivalNotification
supervisors: job-supervisors-captain
whitelistedSpecies:
- Human

View File

@@ -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

View File

@@ -20,7 +20,7 @@
noSpawn: true
components:
- type: InstantAction
useDelay: 1.5
useDelay: 2.5
itemIconStyle: BigAction
priority: -20
icon:

View File

@@ -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

View File

@@ -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:

View File

@@ -18,8 +18,8 @@
- type: DamageOtherOnHit
damage:
types:
Piercing: 20
Heat: 20
Piercing: 30
Heat: 30
- type: Wieldable
- type: IncreaseDamageOnWield
damage:

View File

@@ -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

View File

@@ -0,0 +1,8 @@
- type: speechSounds
id: GnomesSpeech
saySound:
collection: GnomesSpeechCollection
askSound:
collection: GnomesSpeechCollection
exclaimSound:
collection: GnomesSpeechCollection

View 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

View 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

View File

@@ -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: клинок заклинаний

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 }

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B

View File

@@ -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"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

View 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
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

View File

@@ -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"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -3,8 +3,8 @@
"license": "CC-BY-SA-3.0",
"copyright": "reider207",
"size": {
"x": 64,
"y": 64
"x": 128,
"y": 128
},
"states": [
{