Cherrypicks 5 (#399)

* Give moldy food the "Trash" tag (#29380)

Make moldy food items have the "Trash" tag, so they can be collected.

* Add "Structure" tag to switches, buttons, and levers (#29378)
shit
Co-authored-by: Eoin Mcloughlin <helloworld@eoinrul.es>

* Revamped Meteor Swarm (#28974)

* meteor code and balanced values

* Meteor Swarms

* Update meteors.yml

* Update meteors.yml

* HOO! (fix overkill bug and buff space dust)

* undo BloodstreamComponent.cs changes

* DamageDistribution -> DamageTypes

* part 2.

* meteor fixes

* improve meteor spawning (#29057)

* Decrease meteor frequency (#29194)

* Make Projectiles Only Hit a Variety of Station Objects Unless Clicked on (#28571)

* Revert "Make Projectiles Only Hit a Variety of Station Objects Unless Clicked on (#28571)"

This reverts commit 4f934f02f17ce55cabc03b965eb1df7738d63148.

* Makes machine parts stackable, removes unused field in stack prototypes (#28434)

* Makes machine parts stacks, removes unused field in stack prototypes

* forgor

* Fix tests

* Fixes lathe construction. Yes. This sucks but there's no better way that doesnt involve refactoring machine parts completely

* detail

* a

* Add pressure and temperature warning text to firelocks (#28341)

* fix firelocks

* missing nukies can be filled in by ghost roles (#28316)

* Revert "missing nukies can be filled in by ghost roles (#28316)"

This reverts commit 99f13e1e45bc778a4941316fde5d89d7b91337ce.

* welding gas mask (#27108)

* welding gas mask

* eek

* Canes + Cane Blade for Syndicate Librarians (#25873)

* Cane + Cane Blade

* Add - type: ContainerContainer

* Add another - type: ContainerContainer

* Fix and add proper ContainerContainer component

* Add UserInterface component

* Remove Space

* Stat Changes

* review

---------

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>

* Fix stupid NPC. (#26868)

* init commit

* Review

---------

Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>

* fixes

---------

Co-authored-by: VeritableCalamity <34698192+Veritable-Calamity@users.noreply.github.com>
Co-authored-by: eoineoineoin <github@eoinrul.es>
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
Co-authored-by: Cojoke <83733158+Cojoke-dot@users.noreply.github.com>
Co-authored-by: AJCM-git <60196617+AJCM-git@users.noreply.github.com>
Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: Ps3Moira <113228053+ps3moira@users.noreply.github.com>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
Co-authored-by: Vigers Ray <60344369+VigersRay@users.noreply.github.com>
This commit is contained in:
ThereDrD0
2024-06-30 10:04:27 +03:00
committed by GitHub
parent e2d41d6802
commit 164251ffa7
108 changed files with 1857 additions and 494 deletions

View File

@@ -102,7 +102,7 @@ public sealed class MaterialArbitrageTest
continue;
var stackProto = protoManager.Index<StackPrototype>(materialStep.MaterialPrototypeId);
var spawnProto = protoManager.Index<EntityPrototype>(stackProto.Spawn);
var spawnProto = protoManager.Index(stackProto.Spawn);
if (!spawnProto.Components.ContainsKey(materialName) ||
!spawnProto.Components.TryGetValue(compositionName, out var compositionReg))

View File

@@ -59,23 +59,27 @@ public sealed class MachineFrameSystem : EntitySystem
return;
}
// Machine parts cannot currently satisfy stack/component/tag restrictions. Similarly stacks cannot satisfy
// component/tag restrictions. However, there is no reason this cannot be supported in the future. If this
// changes, then RegenerateProgress() also needs to be updated.
//
// If this changes in the future, then RegenerateProgress() also needs to be updated.
// Note that one entity is ALLOWED to satisfy more than one kind of component or tag requirements. This is
// necessary in order to avoid weird entity-ordering shenanigans in RegenerateProgress().
var stack = CompOrNull<StackComponent>(args.Used);
var machinePart = CompOrNull<MachinePartComponent>(args.Used);
if (stack != null && machinePart != null)
{
if (TryInsertPartStack(uid, args.Used, component, machinePart, stack))
args.Handled = true;
return;
}
// Handle parts
if (TryComp<MachinePartComponent>(args.Used, out var machinePart))
if (machinePart != null)
{
if (TryInsertPart(uid, args.Used, component, machinePart))
args.Handled = true;
return;
}
// Handle stacks
if (TryComp<StackComponent>(args.Used, out var stack))
if (stack != null)
{
if (TryInsertStack(uid, args.Used, component, stack))
args.Handled = true;
@@ -191,6 +195,44 @@ public sealed class MachineFrameSystem : EntitySystem
return true;
}
/// <returns>Whether or not the function had any effect. Does not indicate success.</returns>
private bool TryInsertPartStack(EntityUid uid, EntityUid used, MachineFrameComponent component, MachinePartComponent machinePart, StackComponent stack)
{
if (!component.Requirements.ContainsKey(machinePart.PartType))
return false;
var progress = component.Progress[machinePart.PartType];
var requirement = component.Requirements[machinePart.PartType];
var needed = requirement - progress;
if (needed <= 0)
return false;
var count = stack.Count;
if (count < needed)
{
if (!_container.Insert(used, component.PartContainer))
return true;
component.Progress[machinePart.PartType] += count;
return true;
}
var splitStack = _stack.Split(used, needed, Transform(uid).Coordinates, stack);
if (splitStack == null)
return false;
if (!_container.Insert(splitStack.Value, component.PartContainer))
return true;
component.Progress[machinePart.PartType] += needed;
if (IsComplete(component))
_popupSystem.PopupEntity(Loc.GetString("machine-frame-component-on-complete"), uid);
return true;
}
/// <returns>Whether or not the function had any effect. Does not indicate success.</returns>
private bool TryInsertStack(EntityUid uid, EntityUid used, MachineFrameComponent component, StackComponent stack)
{
@@ -328,8 +370,6 @@ public sealed class MachineFrameSystem : EntitySystem
{
if (TryComp<MachinePartComponent>(part, out var machinePart))
{
DebugTools.Assert(!HasComp<StackComponent>(part));
// Check this is part of the requirements...
if (!component.Requirements.ContainsKey(machinePart.PartType))
continue;
@@ -338,7 +378,6 @@ public sealed class MachineFrameSystem : EntitySystem
component.Progress[machinePart.PartType] = 1;
else
component.Progress[machinePart.PartType]++;
continue;
}

View File

@@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using Content.Server.Administration.Logs;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Body.Systems;
@@ -90,6 +91,16 @@ namespace Content.Server.Destructible
}
}
public bool TryGetDestroyedAt(Entity<DestructibleComponent?> ent, [NotNullWhen(true)] out FixedPoint2? destroyedAt)
{
destroyedAt = null;
if (!Resolve(ent, ref ent.Comp, false))
return false;
destroyedAt = DestroyedAt(ent, ent.Comp);
return true;
}
// FFS this shouldn't be this hard. Maybe this should just be a field of the destructible component. Its not
// like there is currently any entity that is NOT just destroyed upon reaching a total-damage value.
/// <summary>

View File

@@ -1,13 +1,25 @@
namespace Content.Server.Destructible.Thresholds
using Robust.Shared.Random;
namespace Content.Server.Destructible.Thresholds
{
[Serializable]
[DataDefinition]
[DataDefinition, Serializable]
public partial struct MinMax
{
[DataField("min")]
[DataField]
public int Min;
[DataField("max")]
[DataField]
public int Max;
public MinMax(int min, int max)
{
Min = min;
Max = max;
}
public int Next(IRobustRandom random)
{
return random.Next(Min, Max + 1);
}
}
}

View File

@@ -1,71 +1,60 @@
using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Monitor.Systems;
using Content.Server.Popups;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Shuttles.Components;
using Content.Shared.Access.Systems;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Monitor;
using Content.Shared.Doors;
using Content.Shared.Doors.Components;
using Content.Shared.Doors.Systems;
using Content.Shared.Popups;
using Content.Shared.Prying.Components;
using Robust.Server.GameObjects;
using Robust.Shared.Map.Components;
namespace Content.Server.Doors.Systems
{
public sealed class FirelockSystem : EntitySystem
public sealed class FirelockSystem : SharedFirelockSystem
{
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedDoorSystem _doorSystem = default!;
[Dependency] private readonly AtmosAlarmableSystem _atmosAlarmable = default!;
[Dependency] private readonly AtmosphereSystem _atmosSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
[Dependency] private readonly SharedMapSystem _mapping = default!;
[Dependency] private readonly PointLightSystem _pointLight = default!;
private static float _visualUpdateInterval = 0.5f;
private float _accumulatedFrameTime;
private const int UpdateInterval = 30;
private int _accumulatedTicks;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FirelockComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
SubscribeLocalEvent<FirelockComponent, GetPryTimeModifierEvent>(OnDoorGetPryTimeModifier);
SubscribeLocalEvent<FirelockComponent, DoorStateChangedEvent>(OnUpdateState);
SubscribeLocalEvent<FirelockComponent, BeforeDoorAutoCloseEvent>(OnBeforeDoorAutoclose);
SubscribeLocalEvent<FirelockComponent, AtmosAlarmEvent>(OnAtmosAlarm);
// Visuals
SubscribeLocalEvent<FirelockComponent, MapInitEvent>(UpdateVisuals);
SubscribeLocalEvent<FirelockComponent, ComponentStartup>(UpdateVisuals);
SubscribeLocalEvent<FirelockComponent, PowerChangedEvent>(PowerChanged);
}
private void PowerChanged(EntityUid uid, FirelockComponent component, ref PowerChangedEvent args)
{
// TODO this should REALLLLY not be door specific appearance thing.
_appearance.SetData(uid, DoorVisuals.Powered, args.Powered);
component.Powered = args.Powered;
Dirty(uid, component);
}
#region Visuals
private void UpdateVisuals(EntityUid uid, FirelockComponent component, EntityEventArgs args) => UpdateVisuals(uid, component);
public override void Update(float frameTime)
{
_accumulatedFrameTime += frameTime;
if (_accumulatedFrameTime < _visualUpdateInterval)
_accumulatedTicks += 1;
if (_accumulatedTicks < UpdateInterval)
return;
_accumulatedFrameTime -= _visualUpdateInterval;
_accumulatedTicks = 0;
var airtightQuery = GetEntityQuery<AirtightComponent>();
var appearanceQuery = GetEntityQuery<AppearanceComponent>();
var xformQuery = GetEntityQuery<TransformComponent>();
var pointLightQuery = GetEntityQuery<PointLightComponent>();
var query = EntityQueryEnumerator<FirelockComponent, DoorComponent>();
while (query.MoveNext(out var uid, out var firelock, out var door))
@@ -82,109 +71,20 @@ namespace Content.Server.Doors.Systems
&& xformQuery.TryGetComponent(uid, out var xform)
&& appearanceQuery.TryGetComponent(uid, out var appearance))
{
var (fire, pressure) = CheckPressureAndFire(uid, firelock, xform, airtight, airtightQuery);
var (pressure, fire) = CheckPressureAndFire(uid, firelock, xform, airtight, airtightQuery);
_appearance.SetData(uid, DoorVisuals.ClosedLights, fire || pressure, appearance);
firelock.Temperature = fire;
firelock.Pressure = pressure;
Dirty(uid, firelock);
if (pointLightQuery.TryComp(uid, out var pointLight))
{
_pointLight.SetEnabled(uid, fire | pressure, pointLight);
}
}
}
}
private void UpdateVisuals(EntityUid uid,
FirelockComponent? firelock = null,
DoorComponent? door = null,
AirtightComponent? airtight = null,
AppearanceComponent? appearance = null,
TransformComponent? xform = null)
{
if (!Resolve(uid, ref door, ref appearance, false))
return;
// only bother to check pressure on doors that are some variation of closed.
if (door.State != DoorState.Closed
&& door.State != DoorState.Welded
&& door.State != DoorState.Denying)
{
_appearance.SetData(uid, DoorVisuals.ClosedLights, false, appearance);
return;
}
var query = GetEntityQuery<AirtightComponent>();
if (!Resolve(uid, ref firelock, ref airtight, ref appearance, ref xform, false) || !query.Resolve(uid, ref airtight, false))
return;
var (fire, pressure) = CheckPressureAndFire(uid, firelock, xform, airtight, query);
_appearance.SetData(uid, DoorVisuals.ClosedLights, fire || pressure, appearance);
}
#endregion
public bool EmergencyPressureStop(EntityUid uid, FirelockComponent? firelock = null, DoorComponent? door = null)
{
if (!Resolve(uid, ref firelock, ref door))
return false;
if (door.State == DoorState.Open)
{
if (_doorSystem.TryClose(uid, door))
{
return _doorSystem.OnPartialClose(uid, door);
}
}
return false;
}
private void OnBeforeDoorOpened(EntityUid uid, FirelockComponent component, BeforeDoorOpenedEvent args)
{
// Give the Door remote the ability to force a firelock open even if it is holding back dangerous gas
var overrideAccess = (args.User != null) && _accessReaderSystem.IsAllowed(args.User.Value, uid);
if (!this.IsPowered(uid, EntityManager) || (!overrideAccess && IsHoldingPressureOrFire(uid, component)))
args.Cancel();
}
private void OnDoorGetPryTimeModifier(EntityUid uid, FirelockComponent component, ref GetPryTimeModifierEvent args)
{
var state = CheckPressureAndFire(uid, component);
if (state.Fire)
{
_popupSystem.PopupEntity(Loc.GetString("firelock-component-is-holding-fire-message"),
uid, args.User, PopupType.MediumCaution);
}
else if (state.Pressure)
{
_popupSystem.PopupEntity(Loc.GetString("firelock-component-is-holding-pressure-message"),
uid, args.User, PopupType.MediumCaution);
}
if (state.Fire || state.Pressure)
args.PryTimeModifier *= component.LockedPryTimeModifier;
}
private void OnUpdateState(EntityUid uid, FirelockComponent component, DoorStateChangedEvent args)
{
var ev = new BeforeDoorAutoCloseEvent();
RaiseLocalEvent(uid, ev);
UpdateVisuals(uid, component, args);
if (ev.Cancelled)
{
return;
}
_doorSystem.SetNextStateChange(uid, component.AutocloseDelay);
}
private void OnBeforeDoorAutoclose(EntityUid uid, FirelockComponent component, BeforeDoorAutoCloseEvent args)
{
if (!this.IsPowered(uid, EntityManager))
args.Cancel();
// Make firelocks autoclose, but only if the last alarm type it
// remembers was a danger. This is to prevent people from
// flooding hallways with endless bad air/fire.
if (component.AlarmAutoClose &&
(_atmosAlarmable.TryGetHighestAlert(uid, out var alarm) && alarm != AtmosAlarmType.Danger || alarm == null))
args.Cancel();
}
private void OnAtmosAlarm(EntityUid uid, FirelockComponent component, AtmosAlarmEvent args)
{
if (!this.IsPowered(uid, EntityManager))
@@ -193,7 +93,7 @@ namespace Content.Server.Doors.Systems
if (!TryComp<DoorComponent>(uid, out var doorComponent))
return;
if (args.AlarmType == AtmosAlarmType.Normal || args.AlarmType == AtmosAlarmType.Warning)
if (args.AlarmType == AtmosAlarmType.Normal)
{
if (doorComponent.State == DoorState.Closed)
_doorSystem.TryOpen(uid);
@@ -204,12 +104,6 @@ namespace Content.Server.Doors.Systems
}
}
public bool IsHoldingPressureOrFire(EntityUid uid, FirelockComponent firelock)
{
var result = CheckPressureAndFire(uid, firelock);
return result.Pressure || result.Fire;
}
public (bool Pressure, bool Fire) CheckPressureAndFire(EntityUid uid, FirelockComponent firelock)
{
var query = GetEntityQuery<AirtightComponent>();
@@ -234,17 +128,17 @@ namespace Content.Server.Doors.Systems
return (false, false);
}
if (!TryComp(xform.ParentUid, out GridAtmosphereComponent? gridAtmosphere))
if (!HasComp<GridAtmosphereComponent>(xform.ParentUid))
return (false, false);
var grid = Comp<MapGridComponent>(xform.ParentUid);
var pos = grid.CoordinatesToTile(xform.Coordinates);
var pos = _mapping.CoordinatesToTile(xform.ParentUid, grid, xform.Coordinates);
var minPressure = float.MaxValue;
var maxPressure = float.MinValue;
var minTemperature = float.MaxValue;
var maxTemperature = float.MinValue;
bool holdingFire = false;
bool holdingPressure = false;
var holdingFire = false;
var holdingPressure = false;
// We cannot simply use `_atmosSystem.GetAdjacentTileMixtures` because of how the `includeBlocked` option
// works, we want to ignore the firelock's blocking, while including blockers on other tiles.
@@ -284,7 +178,7 @@ namespace Content.Server.Doors.Systems
{
// Is there some airtight entity blocking this direction? If yes, don't include this direction in the
// pressure differential
if (HasAirtightBlocker(grid.GetAnchoredEntities(adjacentPos), dir.GetOpposite(), airtightQuery))
if (HasAirtightBlocker(_mapping.GetAnchoredEntities(xform.ParentUid, grid, adjacentPos), dir.GetOpposite(), airtightQuery))
continue;
var p = gas.Pressure;

View File

@@ -141,4 +141,9 @@ public abstract partial class GameRuleSystem<T> where T: IComponent
return found;
}
protected void ForceEndSelf(EntityUid uid, GameRuleComponent? component = null)
{
GameTicker.EndGameRule(uid, component);
}
}

View File

@@ -0,0 +1,25 @@
using Content.Shared.Damage;
namespace Content.Server.Mining;
/// <summary>
/// This is used for meteors which hit objects, dealing damage to destroy/kill the object and dealing equal damage back to itself.
/// </summary>
[RegisterComponent, Access(typeof(MeteorSystem))]
public sealed partial class MeteorComponent : Component
{
/// <summary>
/// Damage specifier that is multiplied against the calculated damage amount to determine what damage is applied to the colliding entity.
/// </summary>
/// <remarks>
/// The values of this should add up to 1 or else the damage will be scaled.
/// </remarks>
[DataField]
public DamageSpecifier DamageTypes = new();
/// <summary>
/// A list of entities that this meteor has collided with. used to ensure no double collisions occur.
/// </summary>
[DataField]
public HashSet<EntityUid> HitList = new();
}

View File

@@ -0,0 +1,65 @@
using Content.Server.Administration.Logs;
using Content.Server.Destructible;
using Content.Shared.Damage;
using Content.Shared.Database;
using Content.Shared.FixedPoint;
using Content.Shared.Mobs.Systems;
using Robust.Shared.Physics.Events;
using Robust.Shared.Player;
namespace Content.Server.Mining;
public sealed class MeteorSystem : EntitySystem
{
[Dependency] private readonly IAdminLogManager _adminLog = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly DestructibleSystem _destructible = default!;
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<MeteorComponent, StartCollideEvent>(OnCollide);
}
private void OnCollide(EntityUid uid, MeteorComponent component, ref StartCollideEvent args)
{
if (TerminatingOrDeleted(args.OtherEntity) || TerminatingOrDeleted(uid))
return;
if (component.HitList.Contains(args.OtherEntity))
return;
FixedPoint2 threshold;
if (_mobThreshold.TryGetDeadThreshold(args.OtherEntity, out var mobThreshold))
{
threshold = mobThreshold.Value;
if (HasComp<ActorComponent>(args.OtherEntity))
_adminLog.Add(LogType.Action, LogImpact.Extreme, $"{ToPrettyString(args.OtherEntity):player} was struck by meteor {ToPrettyString(uid):ent} and killed instantly.");
}
else if (_destructible.TryGetDestroyedAt(args.OtherEntity, out var destroyThreshold))
{
threshold = destroyThreshold.Value;
}
else
{
threshold = FixedPoint2.MaxValue;
}
var otherEntDamage = CompOrNull<DamageableComponent>(args.OtherEntity)?.TotalDamage ?? FixedPoint2.Zero;
// account for the damage that the other entity has already taken: don't overkill
threshold -= otherEntDamage;
// The max amount of damage our meteor can take before breaking.
var maxMeteorDamage = _destructible.DestroyedAt(uid) - CompOrNull<DamageableComponent>(uid)?.TotalDamage ?? FixedPoint2.Zero;
// Cap damage so we don't overkill the meteor
var trueDamage = FixedPoint2.Min(maxMeteorDamage, threshold);
var damage = component.DamageTypes * trueDamage;
_damageable.TryChangeDamage(args.OtherEntity, damage, true, origin: uid);
_damageable.TryChangeDamage(uid, damage);
if (!TerminatingOrDeleted(args.OtherEntity))
component.HitList.Add(args.OtherEntity);
}
}

View File

@@ -0,0 +1,27 @@
using Robust.Server.Containers;
namespace Content.Server.NPC.HTN.Preconditions;
/// <summary>
/// Checks if the owner in container or not
/// </summary>
public sealed partial class InContainerPrecondition : HTNPrecondition
{
private ContainerSystem _container = default!;
[ViewVariables(VVAccess.ReadWrite)] [DataField("isInContainer")] public bool IsInContainer = true;
public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_container = sysManager.GetEntitySystem<ContainerSystem>();
}
public override bool IsMet(NPCBlackboard blackboard)
{
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
return IsInContainer && _container.IsEntityInContainer(owner) ||
!IsInContainer && !_container.IsEntityInContainer(owner);
}
}

View File

@@ -0,0 +1,40 @@
using Robust.Server.Containers;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat;
public sealed partial class ContainerOperator : HTNOperator
{
[Dependency] private readonly IEntityManager _entManager = default!;
private ContainerSystem _container = default!;
private EntityQuery<TransformComponent> _transformQuery;
[DataField("shutdownState")]
public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.TaskFinished;
[DataField("targetKey", required: true)]
public string TargetKey = default!;
public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_container = sysManager.GetEntitySystem<ContainerSystem>();
_transformQuery = _entManager.GetEntityQuery<TransformComponent>();
}
public override void Startup(NPCBlackboard blackboard)
{
base.Startup(blackboard);
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
if (!_container.TryGetOuterContainer(owner, _transformQuery.GetComponent(owner), out var outerContainer) && outerContainer == null)
return;
var target = outerContainer.Owner;
blackboard.SetValue(TargetKey, target);
}
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
{
return HTNOperatorStatus.Finished;
}
}

View File

@@ -0,0 +1,140 @@
using System.Threading;
using System.Threading.Tasks;
using Content.Server.NPC.Components;
using Content.Server.Storage.EntitySystems;
using Content.Shared.CombatMode;
using Robust.Server.Containers;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat.Melee;
public sealed partial class EscapeOperator : HTNOperator, IHtnConditionalShutdown
{
[Dependency] private readonly IEntityManager _entManager = default!;
private ContainerSystem _container = default!;
private EntityStorageSystem _entityStorage = default!;
[DataField("shutdownState")]
public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.TaskFinished;
[DataField("targetKey", required: true)]
public string TargetKey = default!;
public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_container = sysManager.GetEntitySystem<ContainerSystem>();
_entityStorage = sysManager.GetEntitySystem<EntityStorageSystem>();
}
public override void Startup(NPCBlackboard blackboard)
{
base.Startup(blackboard);
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
var target = blackboard.GetValue<EntityUid>(TargetKey);
if (_entityStorage.TryOpenStorage(owner, target))
{
TaskShutdown(blackboard, HTNOperatorStatus.Finished);
return;
}
var melee = _entManager.EnsureComponent<NPCMeleeCombatComponent>(owner);
melee.MissChance = blackboard.GetValueOrDefault<float>(NPCBlackboard.MeleeMissChance, _entManager);
melee.Target = target;
}
public override async Task<(bool Valid, Dictionary<string, object>? Effects)> Plan(NPCBlackboard blackboard,
CancellationToken cancelToken)
{
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
if (!blackboard.TryGetValue<EntityUid>(TargetKey, out var target, _entManager))
{
return (false, null);
}
if (!_container.IsEntityInContainer(owner))
{
return (false, null);
}
if (_entityStorage.TryOpenStorage(owner, target))
{
return (false, null);
}
return (true, null);
}
public void ConditionalShutdown(NPCBlackboard blackboard)
{
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
_entManager.System<SharedCombatModeSystem>().SetInCombatMode(owner, false);
_entManager.RemoveComponent<NPCMeleeCombatComponent>(owner);
blackboard.Remove<EntityUid>(TargetKey);
}
public override void TaskShutdown(NPCBlackboard blackboard, HTNOperatorStatus status)
{
base.TaskShutdown(blackboard, status);
ConditionalShutdown(blackboard);
}
public override void PlanShutdown(NPCBlackboard blackboard)
{
base.PlanShutdown(blackboard);
ConditionalShutdown(blackboard);
}
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
{
base.Update(blackboard, frameTime);
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
HTNOperatorStatus status;
if (_entManager.TryGetComponent<NPCMeleeCombatComponent>(owner, out var combat) &&
blackboard.TryGetValue<EntityUid>(TargetKey, out var target, _entManager))
{
combat.Target = target;
// Success
if (!_container.IsEntityInContainer(owner))
{
status = HTNOperatorStatus.Finished;
}
else
{
if (_entityStorage.TryOpenStorage(owner, target))
{
status = HTNOperatorStatus.Finished;
}
else
{
switch (combat.Status)
{
case CombatStatus.TargetOutOfRange:
case CombatStatus.Normal:
status = HTNOperatorStatus.Continuing;
break;
default:
status = HTNOperatorStatus.Failed;
break;
}
}
}
}
else
{
status = HTNOperatorStatus.Failed;
}
// Mark it as finished to continue the plan.
if (status == HTNOperatorStatus.Continuing && ShutdownState == HTNPlanState.PlanFinished)
{
status = HTNOperatorStatus.Finished;
}
return status;
}
}

View File

@@ -0,0 +1,35 @@
using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Movement.Pulling.Systems;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat;
public sealed partial class UnPullOperator : HTNOperator
{
[Dependency] private readonly IEntityManager _entManager = default!;
private PullingSystem _pulling = default!;
private EntityQuery<PullableComponent> _pullableQuery;
[DataField("shutdownState")]
public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.TaskFinished;
public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_pulling = sysManager.GetEntitySystem<PullingSystem>();
_pullableQuery = _entManager.GetEntityQuery<PullableComponent>();
}
public override void Startup(NPCBlackboard blackboard)
{
base.Startup(blackboard);
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
_pulling.TryStopPull(owner, _pullableQuery.GetComponent(owner), owner);
}
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
{
return HTNOperatorStatus.Finished;
}
}

View File

@@ -0,0 +1,34 @@
using Content.Server.Buckle.Systems;
using Content.Shared.Buckle.Components;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat;
public sealed partial class UnbuckleOperator : HTNOperator
{
[Dependency] private readonly IEntityManager _entManager = default!;
private BuckleSystem _buckle = default!;
[DataField("shutdownState")]
public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.TaskFinished;
public override void Initialize(IEntitySystemManager sysManager)
{
base.Initialize(sysManager);
_buckle = sysManager.GetEntitySystem<BuckleSystem>();
}
public override void Startup(NPCBlackboard blackboard)
{
base.Startup(blackboard);
var owner = blackboard.GetValue<EntityUid>(NPCBlackboard.Owner);
if (!_entManager.TryGetComponent<BuckleComponent>(owner, out var buckle) || !buckle.Buckled)
return;
_buckle.TryUnbuckle(owner, owner, true, buckle);
}
public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime)
{
return HTNOperatorStatus.Finished;
}
}

View File

@@ -51,7 +51,7 @@ namespace Content.Server.Stack
// Get a prototype ID to spawn the new entity. Null is also valid, although it should rarely be picked...
var prototype = _prototypeManager.TryIndex<StackPrototype>(stack.StackTypeId, out var stackType)
? stackType.Spawn
? stackType.Spawn.ToString()
: Prototype(uid)?.ID;
// Set the output parameter in the event instance to the newly split stack.

View File

@@ -0,0 +1,35 @@
using Content.Shared.Random;
using Robust.Shared.Prototypes;
namespace Content.Server.StationEvents.Components;
/// <summary>
/// This is used for running meteor swarm events at regular intervals.
/// </summary>
[RegisterComponent, Access(typeof(MeteorSchedulerSystem)), AutoGenerateComponentPause]
public sealed partial class MeteorSchedulerComponent : Component
{
/// <summary>
/// The weights for which swarms will be selected.
/// </summary>
[DataField]
public ProtoId<WeightedRandomEntityPrototype> Config = "DefaultConfig";
/// <summary>
/// The time at which the next swarm occurs.
/// </summary>
[DataField, AutoPausedField]
public TimeSpan NextSwarmTime = TimeSpan.Zero;
/// <summary>
/// The minimum time between swarms
/// </summary>
[DataField]
public TimeSpan MinSwarmDelay = TimeSpan.FromMinutes(7.5f);
/// <summary>
/// The maximum time between swarms
/// </summary>
[DataField]
public TimeSpan MaxSwarmDelay = TimeSpan.FromMinutes(12.5f);
}

View File

@@ -0,0 +1,58 @@
using Content.Server.Destructible.Thresholds;
using Content.Server.StationEvents.Events;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Server.StationEvents.Components;
[RegisterComponent, Access(typeof(MeteorSwarmSystem)), AutoGenerateComponentPause]
public sealed partial class MeteorSwarmComponent : Component
{
[DataField, AutoPausedField]
public TimeSpan NextWaveTime;
/// <summary>
/// We'll send a specific amount of waves of meteors towards the station per ending rather than using a timer.
/// </summary>
[DataField]
public int WaveCounter;
[DataField]
public float MeteorVelocity = 10f;
/// <summary>
/// If true, meteors will be thrown from all angles instead of from a singular source
/// </summary>
[DataField]
public bool NonDirectional;
/// <summary>
/// The announcement played when a meteor swarm begins.
/// </summary>
[DataField]
public LocId? Announcement = "station-event-meteor-swarm-start-announcement";
[DataField]
public SoundSpecifier? AnnouncementSound = new SoundPathSpecifier("/Audio/Announcements/meteors.ogg")
{
Params = new()
{
Volume = -4
}
};
/// <summary>
/// Each meteor entity prototype and their corresponding weight in being picked.
/// </summary>
[DataField]
public Dictionary<EntProtoId, float> Meteors = new();
[DataField]
public MinMax Waves = new(3, 3);
[DataField]
public MinMax MeteorsPerWave = new(3, 4);
[DataField]
public MinMax WaveCooldown = new (10, 60);
}

View File

@@ -1,40 +0,0 @@
using Content.Server.StationEvents.Events;
namespace Content.Server.StationEvents.Components;
[RegisterComponent, Access(typeof(MeteorSwarmRule))]
public sealed partial class MeteorSwarmRuleComponent : Component
{
[DataField("cooldown")]
public float Cooldown;
/// <summary>
/// We'll send a specific amount of waves of meteors towards the station per ending rather than using a timer.
/// </summary>
[DataField("waveCounter")]
public int WaveCounter;
[DataField("minimumWaves")]
public int MinimumWaves = 3;
[DataField("maximumWaves")]
public int MaximumWaves = 8;
[DataField("minimumCooldown")]
public float MinimumCooldown = 10f;
[DataField("maximumCooldown")]
public float MaximumCooldown = 60f;
[DataField("meteorsPerWave")]
public int MeteorsPerWave = 5;
[DataField("meteorVelocity")]
public float MeteorVelocity = 10f;
[DataField("maxAngularVelocity")]
public float MaxAngularVelocity = 0.25f;
[DataField("minAngularVelocity")]
public float MinAngularVelocity = -0.25f;
}

View File

@@ -1,84 +0,0 @@
using System.Numerics;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.StationEvents.Components;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Spawners;
namespace Content.Server.StationEvents.Events
{
public sealed class MeteorSwarmRule : StationEventSystem<MeteorSwarmRuleComponent>
{
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
protected override void Started(EntityUid uid, MeteorSwarmRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
component.WaveCounter = RobustRandom.Next(component.MinimumWaves, component.MaximumWaves);
}
protected override void ActiveTick(EntityUid uid, MeteorSwarmRuleComponent component, GameRuleComponent gameRule, float frameTime)
{
if (component.WaveCounter <= 0)
{
ForceEndSelf(uid, gameRule);
return;
}
component.Cooldown -= frameTime;
if (component.Cooldown > 0f)
return;
component.WaveCounter--;
component.Cooldown += (component.MaximumCooldown - component.MinimumCooldown) * RobustRandom.NextFloat() + component.MinimumCooldown;
Box2? playableArea = null;
var mapId = GameTicker.DefaultMap;
var query = AllEntityQuery<MapGridComponent, TransformComponent>();
while (query.MoveNext(out var gridId, out _, out var xform))
{
if (xform.MapID != mapId)
continue;
var aabb = _physics.GetWorldAABB(gridId);
playableArea = playableArea?.Union(aabb) ?? aabb;
}
if (playableArea == null)
{
ForceEndSelf(uid, gameRule);
return;
}
var minimumDistance = (playableArea.Value.TopRight - playableArea.Value.Center).Length() + 50f;
var maximumDistance = minimumDistance + 100f;
var center = playableArea.Value.Center;
for (var i = 0; i < component.MeteorsPerWave; i++)
{
var angle = new Angle(RobustRandom.NextFloat() * MathF.Tau);
var offset = angle.RotateVec(new Vector2((maximumDistance - minimumDistance) * RobustRandom.NextFloat() + minimumDistance, 0));
var spawnPosition = new MapCoordinates(center + offset, mapId);
var meteor = Spawn("MeteorLarge", spawnPosition);
var physics = EntityManager.GetComponent<PhysicsComponent>(meteor);
_physics.SetBodyStatus(meteor, physics, BodyStatus.InAir);
_physics.SetLinearDamping(meteor, physics, 0f);
_physics.SetAngularDamping(meteor, physics, 0f);
_physics.ApplyLinearImpulse(meteor, -offset.Normalized() * component.MeteorVelocity * physics.Mass, body: physics);
_physics.ApplyAngularImpulse(
meteor,
physics.Mass * ((component.MaxAngularVelocity - component.MinAngularVelocity) * RobustRandom.NextFloat() + component.MinAngularVelocity),
body: physics);
EnsureComp<TimedDespawnComponent>(meteor).Lifetime = 120f;
}
}
}
}

View File

@@ -0,0 +1,88 @@
using System.Numerics;
using Content.Server.Chat.Systems;
using Content.Server.GameTicking.Rules;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Server.StationEvents.Components;
using Robust.Server.Audio;
using Robust.Shared.Map;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Player;
using Robust.Shared.Random;
namespace Content.Server.StationEvents.Events;
public sealed class MeteorSwarmSystem : GameRuleSystem<MeteorSwarmComponent>
{
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly StationSystem _station = default!;
protected override void Added(EntityUid uid, MeteorSwarmComponent component, GameRuleComponent gameRule, GameRuleAddedEvent args)
{
base.Added(uid, component, gameRule, args);
component.WaveCounter = component.Waves.Next(RobustRandom);
if (component.Announcement is { } locId)
_chat.DispatchGlobalAnnouncement(Loc.GetString(locId), playSound: false, colorOverride: Color.Yellow);
_audio.PlayGlobal(component.AnnouncementSound, Filter.Broadcast(), true);
}
protected override void ActiveTick(EntityUid uid, MeteorSwarmComponent component, GameRuleComponent gameRule, float frameTime)
{
if (Timing.CurTime < component.NextWaveTime)
return;
component.NextWaveTime += TimeSpan.FromSeconds(component.WaveCooldown.Next(RobustRandom));
if (_station.GetStations().Count == 0)
return;
var station = RobustRandom.Pick(_station.GetStations());
if (_station.GetLargestGrid(Comp<StationDataComponent>(station)) is not { } grid)
return;
var mapId = Transform(grid).MapID;
var playableArea = _physics.GetWorldAABB(grid);
var minimumDistance = (playableArea.TopRight - playableArea.Center).Length() + 50f;
var maximumDistance = minimumDistance + 100f;
var center = playableArea.Center;
var meteorsToSpawn = component.MeteorsPerWave.Next(RobustRandom);
for (var i = 0; i < meteorsToSpawn; i++)
{
var spawnProto = RobustRandom.Pick(component.Meteors).Key;
var angle = component.NonDirectional
? RobustRandom.NextAngle()
: new Random(uid.Id).NextAngle();
var offset = angle.RotateVec(new Vector2((maximumDistance - minimumDistance) * RobustRandom.NextFloat() + minimumDistance, 0));
// the line at which spawns occur is perpendicular to the offset.
// This means the meteors are less likely to bunch up and hit the same thing.
var subOffsetAngle = RobustRandom.Prob(0.5f)
? angle + Math.PI / 2
: angle - Math.PI / 2;
var subOffset = subOffsetAngle.RotateVec(new Vector2( (playableArea.TopRight - playableArea.Center).Length() / 3 * RobustRandom.NextFloat(), 0));
var spawnPosition = new MapCoordinates(center + offset + subOffset, mapId);
var meteor = Spawn(spawnProto, spawnPosition);
var physics = Comp<PhysicsComponent>(meteor);
_physics.ApplyLinearImpulse(meteor, -offset.Normalized() * component.MeteorVelocity * physics.Mass, body: physics);
}
component.WaveCounter--;
if (component.WaveCounter <= 0)
{
ForceEndSelf(uid, gameRule);
}
}
}

View File

@@ -0,0 +1,39 @@
using Content.Server.GameTicking.Rules;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.StationEvents.Components;
using Content.Shared.Random.Helpers;
using Robust.Shared.Prototypes;
namespace Content.Server.StationEvents;
/// <summary>
/// This handles scheduling and launching meteors at a station at regular intervals.
/// TODO: there is 100% a world in which this is genericized and can be used for lots of basic event scheduling
/// </summary>
public sealed class MeteorSchedulerSystem : GameRuleSystem<MeteorSchedulerComponent>
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
protected override void Started(EntityUid uid, MeteorSchedulerComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
component.NextSwarmTime = Timing.CurTime + RobustRandom.Next(component.MinSwarmDelay, component.MaxSwarmDelay);
}
protected override void ActiveTick(EntityUid uid, MeteorSchedulerComponent component, GameRuleComponent gameRule, float frameTime)
{
base.ActiveTick(uid, component, gameRule, frameTime);
if (Timing.CurTime < component.NextSwarmTime)
return;
RunSwarm((uid, component));
component.NextSwarmTime += RobustRandom.Next(component.MinSwarmDelay, component.MaxSwarmDelay);
}
private void RunSwarm(Entity<MeteorSchedulerComponent> ent)
{
var swarmWeights = _prototypeManager.Index(ent.Comp.Config);
GameTicker.StartGameRule(swarmWeights.Pick(RobustRandom));
}
}

View File

@@ -121,6 +121,18 @@ namespace Content.Shared.CCVar
public static readonly CVarDef<float>
EventsRampingAverageChaos = CVarDef.Create("events.ramping_average_chaos", 6f, CVar.ARCHIVE | CVar.SERVERONLY);
/// <summary>
/// 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);
/// <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);
/*
* Game
*/

View File

@@ -87,9 +87,9 @@ namespace Content.Shared.Construction
foreach (var (stackId, amount) in comp.MaterialIdRequirements)
{
var stackProto = _prototype.Index<StackPrototype>(stackId);
var defaultProto = _prototype.Index(stackProto.Spawn);
if (_prototype.TryIndex(stackProto.Spawn, out var defaultProto) &&
defaultProto.TryGetComponent<PhysicalCompositionComponent>(out var physComp))
if (defaultProto.TryGetComponent<PhysicalCompositionComponent>(out var physComp))
{
foreach (var (mat, matAmount) in physComp.MaterialComposition)
{

View File

@@ -1,4 +1,4 @@
using Content.Shared.Doors.Components;
using Robust.Shared.GameStates;
namespace Content.Shared.Doors.Components
{
@@ -7,9 +7,11 @@ namespace Content.Shared.Doors.Components
/// auto-closing on depressurization, air/fire alarm interactions, and preventing normal door functions when
/// retaining pressure..
/// </summary>
[RegisterComponent]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class FirelockComponent : Component
{
#region Settings
/// <summary>
/// Pry time modifier to be used when the firelock is currently closed due to fire or pressure.
/// </summary>
@@ -17,8 +19,6 @@ namespace Content.Shared.Doors.Components
[DataField("lockedPryTimeModifier"), ViewVariables(VVAccess.ReadWrite)]
public float LockedPryTimeModifier = 1.5f;
[DataField("autocloseDelay")] public TimeSpan AutocloseDelay = TimeSpan.FromSeconds(3f);
/// <summary>
/// Maximum pressure difference before the firelock will refuse to open, in kPa.
/// </summary>
@@ -39,5 +39,47 @@ namespace Content.Shared.Doors.Components
/// </summary>
[DataField("alarmAutoClose"), ViewVariables(VVAccess.ReadWrite)]
public bool AlarmAutoClose = true;
/// <summary>
/// The cooldown duration before a firelock can automatically close due to a hazardous environment after it has
/// been pried open. Measured in seconds.
/// </summary>
[DataField]
public TimeSpan EmergencyCloseCooldownDuration = TimeSpan.FromSeconds(2);
#endregion
#region Set by system
/// <summary>
/// When the firelock will be allowed to automatically close again due to a hazardous environment.
/// </summary>
[DataField]
public TimeSpan? EmergencyCloseCooldown;
/// <summary>
/// Whether the firelock can open, or is locked due to its environment.
/// </summary>
public bool IsLocked => Pressure || Temperature;
/// <summary>
/// Whether the firelock is holding back a hazardous pressure.
/// </summary>
[DataField, AutoNetworkedField]
public bool Pressure;
/// <summary>
/// Whether the firelock is holding back extreme temperatures.
/// </summary>
[DataField, AutoNetworkedField]
public bool Temperature;
/// <summary>
/// Whether the airlock is powered.
/// </summary>
[DataField, AutoNetworkedField]
public bool Powered;
#endregion
}
}

View File

@@ -0,0 +1,124 @@
using Content.Shared.Access.Systems;
using Content.Shared.Doors.Components;
using Content.Shared.Examine;
using Content.Shared.Popups;
using Content.Shared.Prying.Components;
using Robust.Shared.Timing;
namespace Content.Shared.Doors.Systems;
public abstract class SharedFirelockSystem : EntitySystem
{
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedDoorSystem _doorSystem = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
public override void Initialize()
{
base.Initialize();
// Access/Prying
SubscribeLocalEvent<FirelockComponent, BeforeDoorOpenedEvent>(OnBeforeDoorOpened);
SubscribeLocalEvent<FirelockComponent, GetPryTimeModifierEvent>(OnDoorGetPryTimeModifier);
SubscribeLocalEvent<FirelockComponent, PriedEvent>(OnAfterPried);
// Visuals
SubscribeLocalEvent<FirelockComponent, MapInitEvent>(UpdateVisuals);
SubscribeLocalEvent<FirelockComponent, ComponentStartup>(UpdateVisuals);
SubscribeLocalEvent<FirelockComponent, ExaminedEvent>(OnExamined);
}
public bool EmergencyPressureStop(EntityUid uid, FirelockComponent? firelock = null, DoorComponent? door = null)
{
if (!Resolve(uid, ref firelock, ref door))
return false;
if (door.State != DoorState.Open
|| firelock.EmergencyCloseCooldown != null
&& _gameTiming.CurTime < firelock.EmergencyCloseCooldown)
return false;
if (!_doorSystem.TryClose(uid, door))
return false;
return _doorSystem.OnPartialClose(uid, door);
}
#region Access/Prying
private void OnBeforeDoorOpened(EntityUid uid, FirelockComponent component, BeforeDoorOpenedEvent args)
{
// Give the Door remote the ability to force a firelock open even if it is holding back dangerous gas
var overrideAccess = (args.User != null) && _accessReaderSystem.IsAllowed(args.User.Value, uid);
if (!component.Powered || (!overrideAccess && component.IsLocked))
args.Cancel();
}
private void OnDoorGetPryTimeModifier(EntityUid uid, FirelockComponent component, ref GetPryTimeModifierEvent args)
{
if (component.Temperature)
{
_popupSystem.PopupClient(Loc.GetString("firelock-component-is-holding-fire-message"),
uid, args.User, PopupType.MediumCaution);
}
else if (component.Pressure)
{
_popupSystem.PopupClient(Loc.GetString("firelock-component-is-holding-pressure-message"),
uid, args.User, PopupType.MediumCaution);
}
if (component.IsLocked)
args.PryTimeModifier *= component.LockedPryTimeModifier;
}
private void OnAfterPried(EntityUid uid, FirelockComponent component, ref PriedEvent args)
{
component.EmergencyCloseCooldown = _gameTiming.CurTime + component.EmergencyCloseCooldownDuration;
}
#endregion
#region Visuals
private void UpdateVisuals(EntityUid uid, FirelockComponent component, EntityEventArgs args) => UpdateVisuals(uid, component);
private void UpdateVisuals(EntityUid uid,
FirelockComponent? firelock = null,
DoorComponent? door = null,
AppearanceComponent? appearance = null)
{
if (!Resolve(uid, ref door, ref appearance, false))
return;
// only bother to check pressure on doors that are some variation of closed.
if (door.State != DoorState.Closed
&& door.State != DoorState.Welded
&& door.State != DoorState.Denying)
{
_appearance.SetData(uid, DoorVisuals.ClosedLights, false, appearance);
return;
}
if (!Resolve(uid, ref firelock, ref appearance, false))
return;
_appearance.SetData(uid, DoorVisuals.ClosedLights, firelock.IsLocked, appearance);
}
#endregion
private void OnExamined(Entity<FirelockComponent> ent, ref ExaminedEvent args)
{
using (args.PushGroup(nameof(FirelockComponent)))
{
if (ent.Comp.Pressure)
args.PushMarkup(Loc.GetString("firelock-component-examine-pressure-warning"));
if (ent.Comp.Temperature)
args.PushMarkup(Loc.GetString("firelock-component-examine-temperature-warning"));
}
}
}

View File

@@ -29,7 +29,7 @@ namespace Content.Shared.Materials
/// include which stack we should spawn by default.
/// </summary>
[DataField]
public ProtoId<EntityPrototype>? StackEntity;
public EntProtoId? StackEntity;
[DataField]
public string Name = string.Empty;

View File

@@ -212,7 +212,7 @@ public sealed class MobThresholdSystem : EntitySystem
MobThresholdsComponent? thresholdComponent = null)
{
threshold = null;
if (!Resolve(target, ref thresholdComponent))
if (!Resolve(target, ref thresholdComponent, false))
return false;
return TryGetThresholdForState(target, MobState.Dead, out threshold, thresholdComponent);

View File

@@ -4,7 +4,7 @@ using Robust.Shared.Utility;
namespace Content.Shared.Stacks;
[Prototype("stack")]
[Prototype]
public sealed partial class StackPrototype : IPrototype
{
[ViewVariables]
@@ -15,33 +15,26 @@ public sealed partial class StackPrototype : IPrototype
/// Human-readable name for this stack type e.g. "Steel"
/// </summary>
/// <remarks>This is a localization string ID.</remarks>
[DataField("name")]
[DataField]
public string Name { get; private set; } = string.Empty;
/// <summary>
/// An icon that will be used to represent this stack type.
/// </summary>
[DataField("icon")]
[DataField]
public SpriteSpecifier? Icon { get; private set; }
/// <summary>
/// The entity id that will be spawned by default from this stack.
/// </summary>
[DataField("spawn", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string Spawn { get; private set; } = string.Empty;
[DataField(required: true)]
public EntProtoId Spawn { get; private set; } = string.Empty;
/// <summary>
/// The maximum amount of things that can be in a stack.
/// Can be overriden on <see cref="StackComponent"/>
/// if null, simply has unlimited max count.
/// </summary>
[DataField("maxCount")]
[DataField]
public int? MaxCount { get; private set; }
/// <summary>
/// The size of an individual unit of this stack.
/// </summary>
[DataField("itemSize")]
public int? ItemSize;
}

View File

@@ -117,3 +117,10 @@
license: "CC0-1.0"
copyright: "Original sound by stomachache on freesound.org, processed by vanilla"
source: "https://freesound.org/s/262213/"
- files:
- "sheath.ogg"
- "unsheath.ogg"
license: "CC-BY-SA-3.0"
copyright: "Taken from tgstation."
source: "https://github.com/tgstation/tgstation/blob/a7f525bce9a359ab5282fc754078cd4b5678a006/sound/items"

Binary file not shown.

Binary file not shown.

View File

@@ -1,2 +1,4 @@
firelock-component-is-holding-pressure-message = A gush of air blows in your face... Maybe you should reconsider.
firelock-component-is-holding-fire-message = A gush of warm air blows in your face... Maybe you should reconsider.
firelock-component-is-holding-fire-message = A gush of warm air blows in your face... Maybe you should reconsider.
firelock-component-examine-pressure-warning = The [color=red]extreme pressure[/color] differential warning is active.
firelock-component-examine-temperature-warning = The [color=red]extreme temperature[/color] warning is active.

View File

@@ -1,2 +1,5 @@
station-event-meteor-swarm-start-announcement = Meteors are on a collision course with the station. Brace for impact.
station-event-meteor-swarm-start-announcement = Meteors have been detected on collision course with the station.
station-event-meteor-swarm-end-announcement = The meteor swarm has passed. Please return to your stations.
station-event-space-dust-start-announcement = The station is passing through a debris cloud, expect minor damage to external fittings and fixtures.
station-event-meteor-urist-start-announcement = The station is colliding with an unidentified swarm of debris. Please stay calm and do not listen to them.

View File

@@ -293,6 +293,9 @@ uplink-disposable-turret-desc = Looks and functions like a normal electrical too
uplink-cluster-banana-peel-name = Cluster Banana
uplink-cluster-banana-peel-desc = Splits into 6 explosive banana peels after being thrown, the peels detonate automatically after 20 seconds if nobody slips on them.
uplink-cane-blade-name = Cane Blade
uplink-cane-blade-desc = A cane that has a hidden blade that can be unsheathed.
# Armor
uplink-chameleon-name = Chameleon Kit
uplink-chameleon-desc = A backpack full of items that contain chameleon technology allowing you to disguise as pretty much anything on the station, and more!

View File

@@ -4,6 +4,7 @@
BooksBag: 2
BriefcaseBrown: 2
HandLabeler: 2
Cane: 3
ClothingEyesGlasses: 2
ClothingEyesGlassesJamjar: 2
ClothingNeckScarfStripedGreen: 2

View File

@@ -1715,3 +1715,22 @@
- ResearchDirector
- Chef
- ResearchAssistant
- type: listing
id: UplinkCaneBlade
name: uplink-cane-blade-name
description: uplink-cane-blade-desc
icon: { sprite: Objects/Weapons/Melee/cane.rsi, state: cane}
productEntity: CaneSheathFilled
cost:
Telecrystal: 5
categories:
- UplinkJob
conditions:
- !type:BuyerJobCondition
whitelist:
- Librarian
- !type:BuyerWhitelistCondition
blacklist:
components:
- SurplusBundle

View File

@@ -7,7 +7,7 @@
components:
- type: Tag
tags: # ignore "WhitelistChameleon" tag
- HidesNose
- HidesNose
- type: Sprite
sprite: Clothing/Mask/gas.rsi
- type: Clothing
@@ -19,8 +19,8 @@
- type: IdentityBlocker # need that for default ClothingMaskGas
- type: UserInterface
interfaces:
- key: enum.ChameleonUiKey.Key
type: ChameleonBoundUserInterface
- key: enum.ChameleonUiKey.Key
type: ChameleonBoundUserInterface
- type: entity
parent: ClothingMaskGasChameleon
@@ -28,3 +28,29 @@
suffix: Voice Mask, Chameleon
components:
- type: VoiceMasker
- type: entity
parent: ClothingMaskBase
id: ClothingMaskWeldingGas
name: welding gas mask
description: A gas mask with built in welding goggles and face shield. Looks like a skull, clearly designed by a nerd.
components:
- type: Sprite
sprite: Clothing/Mask/welding-gas.rsi
state: icon
- type: Clothing
sprite: Clothing/Mask/welding-gas.rsi
- type: BreathMask
- type: IngestionBlocker
- type: IdentityBlocker
- type: FlashImmunity
- type: EyeProtection
- type: PhysicalComposition
materialComposition:
Steel: 200
Glass: 100
- type: StaticPrice
price: 100
- type: Tag
tags:
- WhitelistChameleon

View File

@@ -742,6 +742,9 @@
- type: Sprite
layers:
- state: moldy-slice
- type: Tag
tags:
- Trash
- type: SolutionContainerManager
solutions:
food:

View File

@@ -521,6 +521,9 @@
- type: Sprite
layers:
- state: moldy-slice
- type: Tag
tags:
- Trash
- type: SolutionContainerManager
solutions:
food:

View File

@@ -9,6 +9,8 @@
sprite: Objects/Misc/stock_parts.rsi
- type: Item
size: Tiny
- type: Stack
count: 1
- type: entity
id: CapacitorStockPart
@@ -25,6 +27,8 @@
- type: Tag
tags:
- CapacitorStockPart
- type: Stack
stackType: Capacitor
- type: entity
id: MicroManipulatorStockPart
@@ -38,6 +42,8 @@
- type: MachinePart
part: Manipulator
rating: 1
- type: Stack
stackType: MicroManipulator
- type: entity
id: MatterBinStockPart
@@ -51,3 +57,5 @@
- type: MachinePart
part: MatterBin
rating: 1
- type: Stack
stackType: MatterBin

View File

@@ -7,7 +7,6 @@
state: extraction_pack
spawn: Fulton1
maxCount: 10
itemSize: 2
# Entities
- type: entity

View File

@@ -420,7 +420,7 @@
whitelist:
tags:
- CartridgeRocket
proto: MeteorLarge
proto: MeteorMedium
- type: GiftIgnore
- type: entity

View File

@@ -1,40 +1,206 @@
- type: entity
id: MeteorLarge
id: BaseMeteor
name: meteor
noSpawn: true
description: You prefer them when they're burning up in the atmosphere.
abstract: true
components:
- type: Sprite
noRot: false
sprite: Objects/Weapons/Guns/Projectiles/meteor.rsi
scale: 4,4
layers:
- state: large
shader: unshaded
- type: ExplodeOnTrigger
- type: DeleteOnTrigger
- type: TriggerOnCollide
fixtureID: projectile
sprite: Objects/Misc/meteor.rsi
- type: Projectile
damage: {}
deleteOnCollide: false
- type: Explosive
explosionType: Default
totalIntensity: 600.0
intensitySlope: 30
maxIntensity: 45
- type: Meteor
damageTypes:
types:
Blunt: 1
- type: TimedDespawn
lifetime: 120
- type: Clickable
- type: Physics
bodyType: Dynamic
bodyStatus: InAir
angularDamping: 0
linearDamping: 0
- type: Fixtures
fixtures:
projectile:
shape:
!type:PhysShapeCircle
radius: 0.8
radius: 0.4
density: 100
hard: true
# Didn't use MapGridComponent for now as the bounds are stuffed.
hard: false
layer:
- LargeMobLayer
mask:
- Impassable
- BulletImpassable
- type: Damageable
damageContainer: Inorganic
- type: Explosive
explosionType: Default
intensitySlope: 4
maxIntensity: 100
- type: entity
parent: BaseMeteor
id: MeteorSpaceDust
name: space dust
description: Makes a station sneeze.
components:
- type: Sprite
state: space_dust
- type: Fixtures
fixtures:
projectile:
shape:
!type:PhysShapeCircle
radius: 0.45
density: 100
hard: false
layer:
- LargeMobLayer
mask:
- Impassable
- BulletImpassable
- type: Explosive
totalIntensity: 25
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 100
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- !type:PlaySoundBehavior
sound:
collection: MetalBreak
- !type:ExplodeBehavior
- type: entity
parent: BaseMeteor
id: MeteorSmall
suffix: Small
components:
- type: Sprite
state: small
- type: Fixtures
fixtures:
projectile:
shape:
!type:PhysShapeCircle
radius: 0.25
density: 100
hard: false
layer:
- LargeMobLayer
mask:
- Impassable
- BulletImpassable
- type: Explosive
totalIntensity: 100
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 1250
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- !type:PlaySoundBehavior
sound:
collection: MetalBreak
- !type:ExplodeBehavior
- type: entity
parent: BaseMeteor
id: MeteorMedium
suffix: Medium
components:
- type: Sprite
state: medium
- type: Fixtures
fixtures:
projectile:
shape:
!type:PhysShapeCircle
radius: 0.3
density: 100
hard: false
layer:
- LargeMobLayer
mask:
- Impassable
- BulletImpassable
- type: Explosive
totalIntensity: 200
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 1750
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- !type:PlaySoundBehavior
sound:
collection: MetalBreak
- !type:ExplodeBehavior
- type: entity
parent: BaseMeteor
id: MeteorLarge
suffix: Large
components:
- type: Sprite
state: big
- type: Explosive
totalIntensity: 300
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 2500
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- !type:PlaySoundBehavior
sound:
collection: MetalBreak
- !type:ExplodeBehavior
- type: entity
parent: BaseMeteor
id: MeteorUrist
name: Urist McMeteor
description: As a successful member of society with a stable unflinching psyche and limitless drive, natural affinity for finance and domination, you have been selected, no, you have been effortlessly guided by divine (biological) trauma towards this moment. The gates of destiny fling open, and once again you're left standing on pulsating nothingness. A strobing headache of the soul.
suffix: Meteor
components:
- type: Sprite
state: human_pixel
- type: SolutionContainerManager
solutions:
blood:
maxVol: 1000
reagents:
- ReagentId: Blood
Quantity: 1000
- type: Explosive
totalIntensity: 25
- type: Destructible
thresholds:
- trigger:
!type:DamageTrigger
damage: 3000
behaviors:
- !type:DoActsBehavior
acts: [ "Destruction" ]
- !type:PlaySoundBehavior
sound:
collection: MaleScreams
params:
volume: 10
- !type:SpillBehavior
solution: blood
- !type:ExplodeBehavior

View File

@@ -0,0 +1,97 @@
- type: entity
parent: BaseItem
id: Cane
name: cane
description: A wooden cane.
components:
- type: Sprite
sprite: Objects/Weapons/Melee/cane.rsi
state: cane
- type: Item
size: Normal
sprite: Objects/Weapons/Melee/cane.rsi
- type: Appearance
- type: MeleeWeapon
wideAnimationRotation: 45
damage:
types:
Blunt: 5
- type: StaminaDamageOnHit
damage: 5
- type: Wieldable
- type: IncreaseDamageOnWield
damage:
types:
Blunt: 3
- type: UseDelay
delay: 1
- type: entity
name: cane blade
parent: BaseItem
id: CaneBlade
description: A sharp blade with a cane shaped hilt.
components:
- type: Sharp
- type: Sprite
sprite: Objects/Weapons/Melee/cane_blade.rsi
state: icon
- type: MeleeWeapon
wideAnimationRotation: 65
attackRate: 1.5
damage:
types:
Slash: 14
soundHit:
path: /Audio/Weapons/bladeslice.ogg
- type: Item
size: Normal
sprite: Objects/Weapons/Melee/cane_blade.rsi
- type: Tag
tags:
- CaneBlade
- type: DisarmMalus
- type: entity
parent: Cane
id: CaneSheath
suffix: Empty
components:
- type: Sprite
sprite: Objects/Weapons/Melee/cane.rsi
state: cane-empty
- type: ContainerContainer
containers:
storagebase: !type:Container
ents: []
- type: UserInterface
interfaces:
- key: enum.StorageUiKey.Key
type: StorageBoundUserInterface
- type: ItemSlots
slots:
item:
name: CaneBlade
insertVerbText: sheath-insert-verb
ejectVerbText: sheath-eject-verb
whitelist:
tags:
- CaneBlade
insertSound: /Audio/Items/sheath.ogg
ejectSound: /Audio/Items/unsheath.ogg
- type: ItemMapper
mapLayers:
cane:
whitelist:
tags:
- CaneBlade
- type: entity
id: CaneSheathFilled
parent: CaneSheath
suffix: Filled
components:
- type: ContainerFill
containers:
item:
- CaneBlade

View File

@@ -317,6 +317,7 @@
- PowerCellMicroreactor
- PowerCellHigh
- WeaponPistolCHIMP
- ClothingMaskWeldingGas
- WeaponGauntletGorilla
- SynthesizerInstrument
- ClothingShoesBootsMagSci

View File

@@ -32,7 +32,9 @@
collection: MetalBreak
- type: UseDelay
delay: 0.2 # prevent light-toggling auto-clickers.
# WD edit start
- type: Tag
tags:
- Structure
- type: entity
id: SignalSwitch

View File

@@ -158,25 +158,6 @@
duration: 240
- type: KudzuGrowthRule
- type: entity
id: MeteorSwarm
parent: BaseGameRule
noSpawn: true
components:
- type: StationEvent
earliestStart: 30
weight: 7.5
minimumPlayers: 10 #Enough to hopefully have at least one engineering guy
startAnnouncement: station-event-meteor-swarm-start-announcement
endAnnouncement: station-event-meteor-swarm-end-announcement
startAudio:
path: /Audio/Announcements/meteors.ogg
params:
volume: -4
duration: null #ending is handled by MeteorSwarmRule
startDelay: 30
- type: MeteorSwarmRule
- type: entity
id: MouseMigration
parent: BaseGameRule

View File

@@ -0,0 +1,111 @@
- type: entity
parent: BaseGameRule
id: GameRuleMeteorScheduler
noSpawn: true
components:
- type: GameRule
minPlayers: 25
- type: MeteorScheduler
- type: weightedRandomEntity
id: DefaultConfig
weights:
GameRuleSpaceDustMinor: 44
GameRuleSpaceDustMajor: 22
GameRuleMeteorSwarmSmall: 18
GameRuleMeteorSwarmMedium: 10
GameRuleMeteorSwarmLarge: 5
GameRuleUristSwarm: 0.05
- type: entity
parent: BaseGameRule
id: GameRuleMeteorSwarm
noSpawn: true
components:
- type: GameRule
- type: MeteorSwarm
- type: entity
parent: GameRuleMeteorSwarm
id: GameRuleSpaceDustMinor
noSpawn: true
components:
- type: MeteorSwarm
announcement: null
announcementSound: null
nonDirectional: true
meteors:
MeteorSpaceDust: 1
waves:
min: 2
max: 3
meteorsPerWave:
min: 3
max: 5
- type: entity
parent: GameRuleMeteorSwarm
id: GameRuleSpaceDustMajor
noSpawn: true
components:
- type: MeteorSwarm
announcement: station-event-space-dust-start-announcement
announcementSound: /Audio/Announcements/attention.ogg
nonDirectional: true
meteors:
MeteorSpaceDust: 1
waves:
min: 2
max: 3
meteorsPerWave:
min: 8
max: 12
- type: entity
parent: GameRuleMeteorSwarm
id: GameRuleMeteorSwarmSmall
noSpawn: true
components:
- type: MeteorSwarm
meteors:
MeteorSmall: 7
MeteorMedium: 3
- type: entity
parent: GameRuleMeteorSwarm
id: GameRuleMeteorSwarmMedium
noSpawn: true
components:
- type: MeteorSwarm
meteors:
MeteorSmall: 3
MeteorMedium: 6
MeteorLarge: 1
- type: entity
parent: GameRuleMeteorSwarm
id: GameRuleMeteorSwarmLarge
noSpawn: true
components:
- type: MeteorSwarm
meteors:
MeteorSmall: 2
MeteorMedium: 4
MeteorLarge: 4
- type: entity
parent: GameRuleMeteorSwarm
id: GameRuleUristSwarm
noSpawn: true
components:
- type: MeteorSwarm
announcement: station-event-meteor-urist-start-announcement
announcementSound: /Audio/Announcements/attention.ogg
meteors:
MeteorUrist: 1
waves:
min: 3
max: 3
meteorsPerWave:
min: 10
max: 10

View File

@@ -17,6 +17,29 @@
- !type:HTNCompoundTask
task: PickupMeleeCompound
- preconditions:
- !type:BuckledPrecondition
isBuckled: true
tasks:
- !type:HTNPrimitiveTask
shutdownState: TaskFinished
operator: !type:UnbuckleOperator
- preconditions:
- !type:InContainerPrecondition
isInContainer: true
tasks:
- !type:HTNCompoundTask
task: EscapeCompound
- preconditions:
- !type:PulledPrecondition
isPulled: true
tasks:
- !type:HTNPrimitiveTask
shutdownState: TaskFinished
operator: !type:UnPullOperator
# Melee combat (unarmed or otherwise)
- tasks:
- !type:HTNPrimitiveTask
@@ -101,6 +124,21 @@
proto: NearbyMeleeTargets
key: Target
- type: htnCompound
id: EscapeCompound
branches:
- tasks:
- !type:HTNPrimitiveTask
shutdownState: TaskFinished
operator: !type:ContainerOperator
targetKey: Target
- !type:HTNPrimitiveTask
operator: !type:EscapeOperator
targetKey: Target
preconditions:
- !type:InContainerPrecondition
isInContainer: true
- type: htnCompound
id: MeleeAttackOrderedTargetCompound
branches:

View File

@@ -76,7 +76,7 @@
Steel: 100
Plastic: 200
Glass: 100
- type: latheRecipe
id: SignallerAdvanced
result: RemoteSignallerAdvanced
@@ -175,6 +175,14 @@
Plasma: 1500
Uranium: 150
- type: latheRecipe
id: ClothingMaskWeldingGas
result: ClothingMaskWeldingGas
completetime: 3
materials:
Steel: 600
Glass: 200
- type: latheRecipe
id: WeaponForceGun
result: WeaponForceGun

View File

@@ -14,6 +14,7 @@
- BorgModuleMining
- OreProcessorIndustrialMachineCircuitboard
- OreBagOfHolding
- ClothingMaskWeldingGas
- type: technology
id: AdvancedPowercells

View File

@@ -4,7 +4,6 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/glass.rsi, state: glass }
spawn: SheetGlass1
maxCount: 30
itemSize: 1
- type: stack
id: ReinforcedGlass
@@ -12,7 +11,6 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/glass.rsi, state: rglass }
spawn: SheetRGlass1
maxCount: 30
itemSize: 1
- type: stack
id: PlasmaGlass
@@ -20,7 +18,6 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/glass.rsi, state: pglass }
spawn: SheetPGlass1
maxCount: 30
itemSize: 1
- type: stack
id: ReinforcedPlasmaGlass
@@ -28,7 +25,6 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/glass.rsi, state: rpglass }
spawn: SheetRPGlass1
maxCount: 30
itemSize: 1
- type: stack
id: UraniumGlass
@@ -36,7 +32,6 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/glass.rsi, state: uglass }
spawn: SheetUGlass1
maxCount: 30
itemSize: 1
- type: stack
id: ReinforcedUraniumGlass
@@ -44,7 +39,6 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/glass.rsi, state: ruglass }
spawn: SheetRUGlass1
maxCount: 30
itemSize: 1
- type: stack
id: ClockworkGlass
@@ -52,4 +46,3 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/glass.rsi, state: cglass }
spawn: SheetClockworkGlass1
maxCount: 30
itemSize: 1

View File

@@ -4,7 +4,6 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/metal.rsi, state: steel }
spawn: SheetSteel1
maxCount: 30
itemSize: 1
- type: stack
id: Plasteel
@@ -12,7 +11,6 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/metal.rsi, state: plasteel }
spawn: SheetPlasteel1
maxCount: 30
itemSize: 1
- type: stack
id: Brass
@@ -20,4 +18,3 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/metal.rsi, state: brass }
spawn: SheetBrass1
maxCount: 30
itemSize: 1

View File

@@ -4,7 +4,6 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/other.rsi, state: paper }
spawn: SheetPaper1
maxCount: 30
itemSize: 1
- type: stack
id: Plasma
@@ -12,7 +11,6 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/other.rsi, state: plasma }
spawn: SheetPlasma1
maxCount: 30
itemSize: 1
- type: stack
id: Plastic
@@ -20,7 +18,6 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/other.rsi, state: plastic }
spawn: SheetPlastic1
maxCount: 30
itemSize: 1
- type: stack
id: Uranium
@@ -28,4 +25,3 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/other.rsi, state: uranium }
spawn: SheetUranium1
maxCount: 30
itemSize: 1

View File

@@ -3,4 +3,3 @@
name: telecrystal
icon: Objects/Specific/Syndicate/telecrystal.rsi
spawn: Telecrystal1
itemSize: 1

View File

@@ -4,7 +4,6 @@
icon: { sprite: "/Textures/Objects/Materials/ingots.rsi", state: gold }
spawn: IngotGold1
maxCount: 30
itemSize: 1
- type: stack
id: Silver
@@ -12,4 +11,3 @@
icon: { sprite: "/Textures/Objects/Materials/ingots.rsi", state: silver }
spawn: IngotSilver1
maxCount: 30
itemSize: 1

View File

@@ -1,66 +1,65 @@
- type: stack
id: Biomass
name: биомасса
name: biomass
icon: { sprite: /Textures/Objects/Misc/monkeycube.rsi, state: cube }
spawn: MaterialBiomass1
maxCount: 100
itemSize: 1
- type: stack
id: WoodPlank
name: древесина
name: wood plank
icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: wood }
spawn: MaterialWoodPlank1
maxCount: 30
itemSize: 1
- type: stack
id: Cardboard
name: картонная коробка
name: cardboard
icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: cardboard }
spawn: MaterialCardboard1
maxCount: 30
itemSize: 1
- type: stack
id: Cloth
name: ткань
name: cloth
icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: cloth }
spawn: MaterialCloth1
maxCount: 30
itemSize: 1
- type: stack
id: Durathread
name: дюраткань
name: durathread
icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: durathread }
spawn: MaterialDurathread1
maxCount: 30
itemSize: 1
- type: stack
id: Diamond
name: алмаз
name: diamond
icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: diamond }
spawn: MaterialDiamond1
maxCount: 30
itemSize: 2
- type: stack
id: Cotton
name: хлопок
name: cotton
icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: cotton }
spawn: MaterialCotton1
maxCount: 30
itemSize: 1
- type: stack
id: Pyrotton
name: pyrotton
icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: pyrotton }
spawn: MaterialPyrotton1
maxCount: 30
- type: stack
id: Bananium
name: бананиум
name: bananium
icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: bananium }
spawn: MaterialBananium1
maxCount: 10
itemSize: 2
- type: stack
id: MeatSheets
@@ -68,7 +67,6 @@
icon: { sprite: /Textures/Objects/Materials/Sheets/meaterial.rsi, state: meat }
spawn: MaterialSheetMeat1
maxCount: 30
itemSize: 1
- type: stack
id: WebSilk
@@ -76,7 +74,6 @@
icon: { sprite: /Textures/Objects/Materials/silk.rsi, state: icon }
spawn: MaterialWebSilk1
maxCount: 50
itemSize: 1
- type: stack
id: Bones
@@ -84,7 +81,6 @@
icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: bones}
spawn: MaterialBones1
maxCount: 30
itemSize: 1
- type: stack
id: RunicMetalSheets
@@ -92,12 +88,10 @@
icon: { sprite: /Textures/White/Cult/Entities/runic_metal.rsi, state: runic}
spawn: CultRunicMetal1
maxCount: 30
itemSize: 1
- type: stack
id: Gunpowder
name: порох
name: gunpowder
icon: { sprite: /Textures/Objects/Misc/reagent_fillings.rsi, state: powderpile }
spawn: MaterialGunpowder
maxCount: 60
itemSize: 1

View File

@@ -4,7 +4,6 @@
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: gold }
spawn: GoldOre1
maxCount: 30
itemSize: 2
- type: stack
id: SteelOre
@@ -12,7 +11,6 @@
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: iron }
spawn: SteelOre1
maxCount: 30
itemSize: 2
- type: stack
id: PlasmaOre
@@ -20,7 +18,6 @@
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: plasma }
spawn: PlasmaOre1
maxCount: 30
itemSize: 2
- type: stack
id: SilverOre
@@ -28,7 +25,6 @@
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: silver }
spawn: SilverOre1
maxCount: 30
itemSize: 2
- type: stack
id: SpaceQuartz
@@ -36,7 +32,6 @@
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: spacequartz }
spawn: SpaceQuartz1
maxCount: 30
itemSize: 2
- type: stack
id: UraniumOre
@@ -44,7 +39,6 @@
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: uranium }
spawn: UraniumOre1
maxCount: 30
itemSize: 2
- type: stack
@@ -53,7 +47,6 @@
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: bananium }
spawn: BananiumOre1
maxCount: 30
itemSize: 2
- type: stack
id: Coal
@@ -61,7 +54,6 @@
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: coal }
spawn: Coal1
maxCount: 30
itemSize: 2
- type: stack
id: SaltOre
@@ -69,4 +61,3 @@
icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: salt }
spawn: Salt1
maxCount: 30
itemSize: 2

View File

@@ -4,4 +4,3 @@
icon: { sprite: /Textures/Objects/Materials/parts.rsi, state: rods }
spawn: PartRodMetal1
maxCount: 30
itemSize: 1

View File

@@ -5,7 +5,6 @@
name: pancake
spawn: FoodBakedPancake
maxCount: 3
itemSize: 1
# Food Containers
@@ -15,54 +14,60 @@
icon: { sprite: Objects/Consumable/Food/Baked/pizza.rsi, state: box }
spawn: FoodBoxPizza
maxCount: 30
itemSize: 10
# Smokeables
- type: stack
id: PaperRolling
name: самокрутка
name: rolling paper
icon: { sprite: /Textures/Objects/Consumable/Smokeables/Cigarettes/paper.rsi, state: cigpaper }
spawn: PaperRolling
maxCount: 5
itemSize: 1
- type: stack
id: CigaretteFilter
name: фильтр
name: cigarette filter
icon: { sprite: /Textures/Objects/Consumable/Smokeables/Cigarettes/paper.rsi, state: cigfilter }
spawn: CigaretteFilter
maxCount: 5
itemSize: 2
- type: stack
id: GroundTobacco
name: измельчённый табак
name: ground tobacco
icon: { sprite: /Textures/Objects/Misc/reagent_fillings.rsi, state: powderpile }
spawn: GroundTobacco
maxCount: 5
itemSize: 1
- type: stack
id: GroundCannabis
name: измельчённый каннабис
name: ground cannabis
icon: { sprite: /Textures/Objects/Misc/reagent_fillings.rsi, state: powderpile }
spawn: GroundCannabis
maxCount:
itemSize: 1
- type: stack
id: GroundCannabisRainbow
name: ground rainbow cannabis
icon: { sprite: /Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi, state: powderpile_rainbow }
spawn: GroundCannabisRainbow
maxCount:
- type: stack
id: LeavesTobaccoDried
name: высушеные листья табака
name: dried tobacco leaves
icon: { sprite: /Textures/Objects/Specific/Hydroponics/tobacco.rsi, state: dried }
spawn: LeavesTobaccoDried
maxCount: 5
itemSize: 5
- type: stack
id: LeavesCannabisDried
name: высушеные листья каннабиса
name: dried cannabis leaves
icon: { sprite: /Textures/Objects/Specific/Hydroponics/tobacco.rsi, state: dried }
spawn: LeavesCannabisDried
maxCount: 5
itemSize: 5
- type: stack
id: LeavesCannabisRainbowDried
name: dried rainbow cannabis leaves
icon: { sprite: /Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi, state: dried }
spawn: LeavesCannabisRainbowDried

View File

@@ -4,11 +4,9 @@
name: inflatable wall
spawn: InflatableWallStack1
maxCount: 10
itemSize: 1
- type: stack
id: InflatableDoor
name: inflatable door
spawn: InflatableDoorStack1
maxCount: 4
itemSize: 1

View File

@@ -3,469 +3,402 @@
name: steel tile
spawn: FloorTileItemSteel
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileMetalDiamond
name: steel tile
spawn: FloorTileItemMetalDiamond
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileWood
name: wood floor
spawn: FloorTileItemWood
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileWhite
name: white tile
spawn: FloorTileItemWhite
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileDark
name: dark tile
spawn: FloorTileItemDark
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileTechmaint
name: techmaint floor
spawn: FloorTileItemTechmaint
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileFreezer
name: freezer tile
spawn: FloorTileItemFreezer
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileShowroom
name: showroom tile
spawn: FloorTileItemShowroom
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileGCircuit
name: green-circuit floor
spawn: FloorTileItemGCircuit
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileGold
name: gold floor
spawn: FloorTileItemGold
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileReinforced
name: reinforced tile
spawn: FloorTileItemReinforced
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileMono
name: mono tile
spawn: FloorTileItemMono
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileBrassFilled
name: filled brass plate
spawn: FloorTileItemBrassFilled
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileBrassReebe
name: smooth brass plate
spawn: FloorTileItemBrassReebe
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileLino
name: linoleum floor
spawn: FloorTileItemLino
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileHydro
name: hydro tile
spawn: FloorTileItemHydro
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileLime
name: lime tile
spawn: FloorTileItemLime
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileDirty
name: dirty tile
spawn: FloorTileItemDirty
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackShuttleWhite
name: white shuttle tile
spawn: FloorTileItemShuttleWhite
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackShuttleBlue
name: blue shuttle tile
spawn: FloorTileItemShuttleBlue
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackShuttleOrange
name: orange shuttle tile
spawn: FloorTileItemShuttleOrange
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackShuttlePurple
name: purple shuttle tile
spawn: FloorTileItemShuttlePurple
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackShuttleRed
name: red shuttle tile
spawn: FloorTileItemShuttleRed
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackShuttleGrey
name: grey shuttle tile
spawn: FloorTileItemShuttleGrey
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackShuttleBlack
name: black shuttle tile
spawn: FloorTileItemShuttleBlack
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackEighties
name: eighties floor tile
spawn: FloorTileItemEighties
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackArcadeBlue
name: blue arcade tile
spawn: FloorTileItemArcadeBlue
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackArcadeBlue2
name: blue arcade tile
spawn: FloorTileItemArcadeBlue2
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackArcadeRed
name: red arcade tile
spawn: FloorTileItemArcadeRed
maxCount: 30
itemSize: 5
- type: stack
id: FloorCarpetRed
name: red carpet tile
spawn: FloorCarpetItemRed
maxCount: 30
itemSize: 5
- type: stack
id: FloorCarpetBlack
name: block carpet tile
spawn: FloorCarpetItemBlack
maxCount: 30
itemSize: 5
- type: stack
id: FloorCarpetBlue
name: blue carpet tile
spawn: FloorCarpetItemBlue
maxCount: 30
itemSize: 5
- type: stack
id: FloorCarpetGreen
name: green carpet tile
spawn: FloorCarpetItemGreen
maxCount: 30
itemSize: 5
- type: stack
id: FloorCarpetOrange
name: orange carpet tile
spawn: FloorCarpetItemOrange
maxCount: 30
itemSize: 5
- type: stack
id: FloorCarpetSkyBlue
name: skyblue carpet tile
spawn: FloorCarpetItemSkyBlue
maxCount: 30
itemSize: 5
- type: stack
id: FloorCarpetPurple
name: purple carpet tile
spawn: FloorCarpetItemPurple
maxCount: 30
itemSize: 5
- type: stack
id: FloorCarpetPink
name: pink carpet tile
spawn: FloorCarpetItemPink
maxCount: 30
itemSize: 5
- type: stack
id: FloorCarpetCyan
name: cyan carpet tile
spawn: FloorCarpetItemCyan
maxCount: 30
itemSize: 5
- type: stack
id: FloorCarpetWhite
name: white carpet tile
spawn: FloorCarpetItemWhite
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackCarpetClown
name: clown carpet tile
spawn: FloorTileItemCarpetClown
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackCarpetOffice
name: office carpet tile
spawn: FloorTileItemCarpetOffice
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackBoxing
name: boxing ring tile
spawn: FloorTileItemBoxing
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileStackGym
name: gym floor tile
spawn: FloorTileItemGym
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileElevatorShaft
name: elevator shaft tile
spawn: FloorTileItemElevatorShaft
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileRockVault
name: rock vault tile
spawn: FloorTileItemRockVault
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileBlue
name: blue floor tile
spawn: FloorTileItemBlue
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileMining
name: mining floor tile
spawn: FloorTileItemMining
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileMiningDark
name: dark mining floor tile
spawn: FloorTileItemMiningDark
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileMiningLight
name: light mining floor tile
spawn: FloorTileItemMiningLight
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileBar
name: item bar floor tile
spawn: FloorTileItemBar
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileClown
name: clown floor tile
spawn: FloorTileItemClown
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileMime
name: mime floor tile
spawn: FloorTileItemMime
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileKitchen
name: kitchen floor tile
spawn: FloorTileItemKitchen
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileLaundry
name: laundry floor tile
spawn: FloorTileItemLaundry
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileConcrete
name: concrete tile
spawn: FloorTileItemGrayConcrete
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileGrayConcrete
name: gray concrete tile
spawn: FloorTileItemLaundry
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileOldConcrete
name: old concrete tile
spawn: FloorTileItemOldConcrete
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileSilver
name: silver floor tile
spawn: FloorTileItemSilver
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileBCircuit
name: bcircuit floor tile
spawn: FloorTileItemBCircuit
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileGrass
name: grass floor tile
spawn: FloorTileItemGrass
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileGrassJungle
name: grass jungle floor tile
spawn: FloorTileItemGrassJungle
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileSnow
name: snow floor tile
spawn: FloorTileItemSnow
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileWoodPattern
name: wood pattern floor
spawn: FloorTileItemWoodPattern
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileFlesh
name: flesh floor
spawn: FloorTileItemFlesh
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileSteelMaint
name: steel maint floor
spawn: FloorTileItemSteelMaint
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileGratingMaint
name: grating maint floor
spawn: FloorTileItemGratingMaint
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileWeb
name: web tile
spawn: FloorTileItemWeb
maxCount: 30
itemSize: 5
# Faux science tiles
- type: stack
@@ -473,38 +406,33 @@
name: astro-grass floor
spawn: FloorTileItemAstroGrass
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileMowedAstroGrass
name: mowed astro-grass floor
spawn: FloorTileItemMowedAstroGrass
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileJungleAstroGrass
name: jungle astro-grass floor
spawn: FloorTileItemJungleAstroGrass
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileAstroIce
name: astro-ice floor
spawn: FloorTileItemAstroIce
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileAstroSnow
name: astro-snow floor
spawn: FloorTileItemAstroSnow
maxCount: 30
itemSize: 5
- type: stack
id: FloorTileWoodLarge
name: large wood floor
spawn: FloorTileItemWoodLarge
maxCount: 30
maxCount: 30

View File

@@ -4,7 +4,6 @@
icon: { sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: ointment }
spawn: Ointment
maxCount: 10
itemSize: 1
- type: stack
id: AloeCream
@@ -12,7 +11,6 @@
icon: { sprite: "/Textures/Objects/Specific/Hydroponics/aloe.rsi", state: cream }
spawn: AloeCream
maxCount: 10
itemSize: 1
- type: stack
id: Gauze
@@ -20,7 +18,6 @@
icon: { sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: gauze }
spawn: Gauze
maxCount: 10
itemSize: 1
- type: stack
id: Brutepack
@@ -28,7 +25,6 @@
icon: { sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: gauze }
spawn: Brutepack
maxCount: 10
itemSize: 1
- type: stack
id: Bloodpack
@@ -36,7 +32,6 @@
icon: { sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: bloodpack }
spawn: Bloodpack
maxCount: 10
itemSize: 1
- type: stack
id: MedicatedSuture
@@ -44,7 +39,6 @@
icon: {sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: medicated-suture }
spawn: MedicatedSuture
maxCount: 10
itemSize: 1
- type: stack
id: RegenerativeMesh
@@ -52,6 +46,4 @@
icon: {sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: regenerative-mesh}
spawn: RegenerativeMesh
maxCount: 10
itemSize: 1

View File

@@ -4,7 +4,6 @@
icon: { sprite: "/Textures/Objects/Tools/cable-coils.rsi", state: coil-30 }
spawn: CableApcStack1
maxCount: 30
itemSize: 1
- type: stack
id: CableMV
@@ -12,7 +11,6 @@
icon: { sprite: "/Textures/Objects/Tools/cable-coils.rsi", state: coilmv-30 }
spawn: CableMVStack1
maxCount: 30
itemSize: 1
- type: stack
id: CableHV
@@ -20,4 +18,3 @@
icon: { sprite: "/Textures/Objects/Tools/cable-coils.rsi", state: coilhv-30 }
spawn: CableHVStack1
maxCount: 30
itemSize: 1

View File

@@ -3,4 +3,21 @@
name: artifact fragment
spawn: ArtifactFragment1
maxCount: 30
itemSize: 5
- type: stack
id: Capacitor
name: capacitor
spawn: CapacitorStockPart
maxCount: 10
- type: stack
id: MicroManipulator
name: micro manipulator
spawn: MicroManipulatorStockPart
maxCount: 10
- type: stack
id: MatterBin
name: matter bin
spawn: MatterBinStockPart
maxCount: 10

View File

@@ -35,6 +35,7 @@
description: extended-description
rules:
- BasicStationEventScheduler
- GameRuleMeteorScheduler
- BasicRoundstartVariation
- type: gamePreset
@@ -68,6 +69,7 @@
description: secret-description
rules:
- BasicStationEventScheduler
- GameRuleMeteorScheduler
- type: gamePreset
id: SecretGreenshift #For Admin Use: Runs Greenshift but shows "Secret" in lobby.
@@ -99,6 +101,7 @@
- Traitor
- SubGamemodesRule
- BasicStationEventScheduler
- GameRuleMeteorScheduler
- BasicRoundstartVariation
- type: gamePreset
@@ -125,6 +128,7 @@
- Nukeops
- SubGamemodesRule
- BasicStationEventScheduler
- GameRuleMeteorScheduler
- BasicRoundstartVariation
- type: gamePreset
@@ -140,6 +144,7 @@
- Revolutionary
- SubGamemodesRule
- BasicStationEventScheduler
- GameRuleMeteorScheduler
- BasicRoundstartVariation
- type: gamePreset
@@ -156,6 +161,7 @@
rules:
- Zombie
- BasicStationEventScheduler
- GameRuleMeteorScheduler
- BasicRoundstartVariation
- type: gamePreset

View File

@@ -258,6 +258,9 @@
- type: Tag
id: CableCoil
- type: Tag
id: CaneBlade
- type: Tag
id: CannonBall
@@ -1319,3 +1322,5 @@
- type: Tag
id: WriteIgnoreStamps
# ALPHABETICAL

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 550 B

View File

@@ -0,0 +1,49 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/6f5ca45e3ac06b30fb1957042214a888d8c01722. Inhands, worn sprites, and vox sprites created by EmoGarbage404 (github)",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "icon"
},
{
"name": "icon-up"
},
{
"name": "equipped-MASK",
"directions": 4
},
{
"name": "up-equipped-MASK",
"directions": 4
},
{
"name": "equipped-MASK-vox",
"directions": 4
},
{
"name": "up-equipped-MASK-vox",
"directions": 4
},
{
"name": "inhand-left",
"directions": 4
},
{
"name": "inhand-right",
"directions": 4
},
{
"name": "up-inhand-left",
"directions": 4
},
{
"name": "up-inhand-right",
"directions": 4
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 624 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 461 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,271 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from vgstation13 at https://github.com/vgstation-coders/vgstation13/blob/31dd6749bfe32810c46e7913efc99a187479cd51/icons/obj/meteor.dmi",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "small",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "small_pixel",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "small_flash",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "small_flash_pixel",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "space_dust"
},
{
"name": "medium",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "medium_pixel",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "medium_piercing",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "medium_piercing_pixel",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "medium_radioactive",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "medium_radioactive_pixel",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "big",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "big_pixel",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "big_cluster",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "big_cluster_pixel",
"delays": [
[
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "human",
"directions": 4,
"delays": [
[
0.1,
0.1,
0.1,
0.1
],
[
0.1,
0.1,
0.1,
0.1
],
[
0.1,
0.1,
0.1,
0.1
],
[
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "human_pixel",
"delays": [
[
0.1,
0.1,
0.1,
0.1
]
]
},
{
"name": "firework_pixel"
},
{
"name": "firework"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

Some files were not shown because too many files have changed in this diff Show More