Merge branch 'master' into ed-17-07-2024-dungenagain

This commit is contained in:
Ed
2024-08-05 23:08:01 +03:00
committed by GitHub
1423 changed files with 219353 additions and 54715 deletions

View File

@@ -47,7 +47,7 @@ public sealed class JobWhitelistAddCommand : LocalizedCommands
var isWhitelisted = await _db.IsJobWhitelisted(guid, job);
if (isWhitelisted)
{
shell.WriteLine(Loc.GetString("cmd-jobwhitelist-already-whitelisted",
shell.WriteLine(Loc.GetString("cmd-jobwhitelistadd-already-whitelisted",
("player", player),
("jobId", job.Id),
("jobName", jobPrototype.LocalizedName)));

View File

@@ -1,5 +1,5 @@
using System.Text.Json;
using Content.Server.Station.Components;
using Content.Shared.Station.Components;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;

View File

@@ -285,18 +285,18 @@ public sealed partial class AdminVerbSystem
{
Text = "admin-smite-remove-hands-name",
Category = VerbCategory.Smite,
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Fluids/vomit_toxin.rsi"), "vomit_toxin-1"),
Icon = new SpriteSpecifier.Rsi(new("/Textures/Fluids/vomit_toxin.rsi"), "vomit_toxin-1"),
Act = () =>
{
_vomitSystem.Vomit(args.Target, -1000, -1000); // You feel hollow!
var organs = _bodySystem.GetBodyOrganComponents<TransformComponent>(args.Target, body);
var organs = _bodySystem.GetBodyOrganEntityComps<TransformComponent>((args.Target, body));
var baseXform = Transform(args.Target);
foreach (var (xform, organ) in organs)
foreach (var organ in organs)
{
if (HasComp<BrainComponent>(xform.Owner) || HasComp<EyeComponent>(xform.Owner))
if (HasComp<BrainComponent>(organ.Owner) || HasComp<EyeComponent>(organ.Owner))
continue;
_transformSystem.AttachToGridOrMap(organ.Owner);
_transformSystem.PlaceNextTo((organ.Owner, organ.Comp1), (args.Target, baseXform));
}
_popupSystem.PopupEntity(Loc.GetString("admin-smite-vomit-organs-self"), args.Target,
@@ -361,9 +361,9 @@ public sealed partial class AdminVerbSystem
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Species/Human/organs.rsi"), "stomach"),
Act = () =>
{
foreach (var (component, _) in _bodySystem.GetBodyOrganComponents<StomachComponent>(args.Target, body))
foreach (var entity in _bodySystem.GetBodyOrganEntityComps<StomachComponent>((args.Target, body)))
{
QueueDel(component.Owner);
QueueDel(entity.Owner);
}
_popupSystem.PopupEntity(Loc.GetString("admin-smite-stomach-removal-self"), args.Target,
@@ -381,9 +381,9 @@ public sealed partial class AdminVerbSystem
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Species/Human/organs.rsi"), "lung-r"),
Act = () =>
{
foreach (var (component, _) in _bodySystem.GetBodyOrganComponents<LungComponent>(args.Target, body))
foreach (var entity in _bodySystem.GetBodyOrganEntityComps<LungComponent>((args.Target, body)))
{
QueueDel(component.Owner);
QueueDel(entity.Owner);
}
_popupSystem.PopupEntity(Loc.GetString("admin-smite-lung-removal-self"), args.Target,

View File

@@ -122,7 +122,7 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
_audio.PlayPvs(ent.Comp.ConnectedSound, ent);
}
//TO DO: disconnection from the anomaly should also be triggered if the anomaly is far away from the synchronizer.
//TODO: disconnection from the anomaly should also be triggered if the anomaly is far away from the synchronizer.
//Currently only bluespace anomaly can do this, but for some reason it is the only one that cannot be connected to the synchronizer.
private void DisconneсtFromAnomaly(Entity<AnomalySynchronizerComponent> ent, AnomalyComponent anomaly)
{

View File

@@ -76,7 +76,7 @@ public sealed class ReagentProducerAnomalySystem : EntitySystem
if (anomaly.Severity >= 0.97) reagentProducingAmount *= component.SupercriticalReagentProducingModifier;
newSol.AddReagent(component.ProducingReagent, reagentProducingAmount);
_solutionContainer.TryAddSolution(component.Solution.Value, newSol); //TO DO - the container is not fully filled.
_solutionContainer.TryAddSolution(component.Solution.Value, newSol); // TODO - the container is not fully filled.
component.AccumulatedFrametime = 0;

View File

@@ -336,7 +336,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
}
_mind.TransferTo(curMind.Value, antagEnt, ghostCheckOverride: true);
_role.MindAddRoles(curMind.Value, def.MindComponents);
_role.MindAddRoles(curMind.Value, def.MindComponents, null, true);
ent.Comp.SelectedMinds.Add((curMind.Value, Name(player)));
SendBriefing(session, def.Briefing);
}

View File

@@ -157,7 +157,7 @@ public sealed partial class BlockGame
/// <param name="message">The message to broadcase to all players/spectators.</param>
private void SendMessage(BoundUserInterfaceMessage message)
{
_uiSystem.ServerSendUiMessage(_entityManager.GetEntity(message.Entity), BlockGameUiKey.Key, message);
_uiSystem.ServerSendUiMessage(_owner, BlockGameUiKey.Key, message);
}
/// <summary>
@@ -167,7 +167,7 @@ public sealed partial class BlockGame
/// <param name="actor">The target recipient.</param>
private void SendMessage(BoundUserInterfaceMessage message, EntityUid actor)
{
_uiSystem.ServerSendUiMessage(_entityManager.GetEntity(message.Entity), BlockGameUiKey.Key, message, actor);
_uiSystem.ServerSendUiMessage(_owner, BlockGameUiKey.Key, message, actor);
}
/// <summary>

View File

@@ -1,11 +1,11 @@
using Content.Server.Bible.Components;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Ghost.Roles.Events;
using Content.Server.Popups;
using Content.Shared.ActionBlocker;
using Content.Shared.Actions;
using Content.Shared.Bible;
using Content.Shared.Damage;
using Content.Shared.Ghost.Roles.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Inventory;

View File

@@ -31,7 +31,7 @@ public sealed class CharacterInfoSystem : EntitySystem
var entity = args.SenderSession.AttachedEntity.Value;
var objectives = new Dictionary<string, List<ObjectiveInfo>>();
var jobTitle = "No Profession";
var jobTitle = Loc.GetString("character-info-no-profession");
string? briefing = null;
if (_minds.TryGetMind(entity, out var mindId, out var mind))
{

View File

@@ -121,21 +121,25 @@ public sealed class InjectorSystem : SharedInjectorSystem
if (!SolutionContainers.TryGetSolution(injector.Owner, injector.Comp.SolutionName, out _, out var solution))
return;
var actualDelay = MathHelper.Max(injector.Comp.Delay, TimeSpan.FromSeconds(1));
float amountToInject;
var actualDelay = injector.Comp.Delay;
FixedPoint2 amountToInject;
if (injector.Comp.ToggleState == InjectorToggleMode.Draw)
{
// additional delay is based on actual volume left to draw in syringe when smaller than transfer amount
amountToInject = Math.Min(injector.Comp.TransferAmount.Float(), (solution.MaxVolume - solution.Volume).Float());
amountToInject = FixedPoint2.Min(injector.Comp.TransferAmount, (solution.MaxVolume - solution.Volume));
}
else
{
// additional delay is based on actual volume left to inject in syringe when smaller than transfer amount
amountToInject = Math.Min(injector.Comp.TransferAmount.Float(), solution.Volume.Float());
amountToInject = FixedPoint2.Min(injector.Comp.TransferAmount, solution.Volume);
}
// Injections take 0.5 seconds longer per 5u of possible space/content
actualDelay += TimeSpan.FromSeconds(amountToInject / 10);
// First 5u(MinimumTransferAmount) doesn't incur delay
actualDelay += injector.Comp.DelayPerVolume * FixedPoint2.Max(0, amountToInject - injector.Comp.MinimumTransferAmount).Double();
// Ensure that minimum delay before incapacitation checks is 1 seconds
actualDelay = MathHelper.Max(actualDelay, TimeSpan.FromSeconds(1));
var isTarget = user != target;
@@ -202,9 +206,9 @@ public sealed class InjectorSystem : SharedInjectorSystem
BreakOnMove = true,
BreakOnWeightlessMove = false,
BreakOnDamage = true,
NeedHand = true,
BreakOnHandChange = true,
MovementThreshold = 0.1f,
NeedHand = injector.Comp.NeedHand,
BreakOnHandChange = injector.Comp.BreakOnHandChange,
MovementThreshold = injector.Comp.MovementThreshold,
});
}

View File

@@ -308,6 +308,12 @@ namespace Content.Server.Connection
return (false, "");
var isAccountAgeInvalid = record.FirstSeenTime.CompareTo(DateTimeOffset.Now - TimeSpan.FromMinutes(maxAccountAgeMinutes)) <= 0;
if (isAccountAgeInvalid)
{
_sawmill.Debug($"Baby jail will deny {userId} for account age {record.FirstSeenTime}"); // Remove on or after 2024-09
}
if (isAccountAgeInvalid && showReason)
{
var locAccountReason = reason != string.Empty
@@ -322,7 +328,12 @@ namespace Content.Server.Connection
}
var overallTime = ( await _db.GetPlayTimes(e.UserId)).Find(p => p.Tracker == PlayTimeTrackingShared.TrackerOverall);
var isTotalPlaytimeInvalid = overallTime == null || overallTime.TimeSpent.TotalMinutes >= maxPlaytimeMinutes;
var isTotalPlaytimeInvalid = overallTime != null && overallTime.TimeSpent.TotalMinutes >= maxPlaytimeMinutes;
if (isTotalPlaytimeInvalid)
{
_sawmill.Debug($"Baby jail will deny {userId} for playtime {overallTime!.TimeSpent}"); // Remove on or after 2024-09
}
if (isTotalPlaytimeInvalid && showReason)
{

View File

@@ -1,7 +1,7 @@
using Content.Server._CP14.MeleeWeapon;
using Content.Server.Administration.Logs;
using Content.Server.Damage.Components;
using Content.Server.Weapons.Ranged.Systems;
using Content.Shared._CP14.MeleeWeapon.Components;
using Content.Shared.Camera;
using Content.Shared.Damage;
using Content.Shared.Damage.Events;
@@ -42,7 +42,7 @@ namespace Content.Server.Damage.Systems
damage *= sharp.Sharpness;
var dmg = _damageable.TryChangeDamage(args.Target, damage, component.IgnoreResistances, origin: args.Component.Thrower);
//CrystallPunk Melee pgrade end
//CrystallPunk Melee upgrade end
// Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying.
if (dmg != null && HasComp<MobStateComponent>(args.Target))

View File

@@ -9,6 +9,7 @@ using Content.Shared.Disposal;
using Content.Shared.Interaction;
using Robust.Server.GameObjects;
using Robust.Shared.Player;
using Robust.Shared.Utility;
namespace Content.Server.Disposal.Mailing;
@@ -35,7 +36,7 @@ public sealed class MailingUnitSystem : EntitySystem
SubscribeLocalEvent<MailingUnitComponent, DeviceNetworkPacketEvent>(OnPacketReceived);
SubscribeLocalEvent<MailingUnitComponent, BeforeDisposalFlushEvent>(OnBeforeFlush);
SubscribeLocalEvent<MailingUnitComponent, ConfigurationSystem.ConfigurationUpdatedEvent>(OnConfigurationUpdated);
SubscribeLocalEvent<MailingUnitComponent, ActivateInWorldEvent>(HandleActivate);
SubscribeLocalEvent<MailingUnitComponent, ActivateInWorldEvent>(HandleActivate, before: new[] { typeof(DisposalUnitSystem) });
SubscribeLocalEvent<MailingUnitComponent, DisposalUnitUIStateUpdatedEvent>(OnDisposalUnitUIStateChange);
SubscribeLocalEvent<MailingUnitComponent, TargetSelectedMessage>(OnTargetSelected);
}
@@ -179,7 +180,7 @@ public sealed class MailingUnitSystem : EntitySystem
if (component.DisposalUnitInterfaceState == null)
return;
var state = new MailingUnitBoundUserInterfaceState(component.DisposalUnitInterfaceState, component.Target, component.TargetList, component.Tag);
var state = new MailingUnitBoundUserInterfaceState(component.DisposalUnitInterfaceState, component.Target, component.TargetList.ShallowClone(), component.Tag);
_userInterfaceSystem.SetUiState(uid, MailingUnitUiKey.Key, state);
}

View File

@@ -8,6 +8,7 @@ using Content.Shared.Maps;
using Content.Shared.Mind;
using Content.Shared.Mind.Components;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Systems;
using Content.Shared.Movement.Systems;
using Content.Shared.NPC.Systems;
using Content.Shared.Zombies;
@@ -27,6 +28,7 @@ public sealed partial class DragonSystem : EntitySystem
[Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
private EntityQuery<CarpRiftsConditionComponent> _objQuery;
@@ -91,7 +93,8 @@ public sealed partial class DragonSystem : EntitySystem
}
}
comp.RiftAccumulator += frameTime;
if (!_mobState.IsDead(uid))
comp.RiftAccumulator += frameTime;
// Delete it, naughty dragon!
if (comp.RiftAccumulator >= comp.RiftMaxAccumulator)

View File

@@ -4,6 +4,7 @@ namespace Content.Server.Entry
public static class IgnoredComponents
{
public static string[] List => new[] {
"CP14WaveShader", //CP14 Wave shader
"ConstructionGhost",
"IconSmooth",
"InteractionOutline",

View File

@@ -1,8 +0,0 @@
namespace Content.Server.Eye.Blinding
{
[RegisterComponent]
public sealed partial class ActivatableUIRequiresVisionComponent : Component
{
}
}

View File

@@ -1,56 +0,0 @@
using Content.Shared.Eye.Blinding;
using Content.Shared.UserInterface;
using Content.Server.Popups;
using Content.Shared.Eye.Blinding.Components;
using Content.Shared.Eye.Blinding.Systems;
using Robust.Shared.Player;
using Robust.Server.GameObjects;
using Robust.Shared.Collections;
namespace Content.Server.Eye.Blinding;
public sealed class ActivatableUIRequiresVisionSystem : EntitySystem
{
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ActivatableUIRequiresVisionComponent, ActivatableUIOpenAttemptEvent>(OnOpenAttempt);
SubscribeLocalEvent<BlindableComponent, BlindnessChangedEvent>(OnBlindnessChanged);
}
private void OnOpenAttempt(EntityUid uid, ActivatableUIRequiresVisionComponent component, ActivatableUIOpenAttemptEvent args)
{
if (args.Cancelled)
return;
if (TryComp<BlindableComponent>(args.User, out var blindable) && blindable.IsBlind)
{
_popupSystem.PopupCursor(Loc.GetString("blindness-fail-attempt"), args.User, Shared.Popups.PopupType.MediumCaution);
args.Cancel();
}
}
private void OnBlindnessChanged(EntityUid uid, BlindableComponent component, ref BlindnessChangedEvent args)
{
if (!args.Blind)
return;
var toClose = new ValueList<(EntityUid Entity, Enum Key)>();
foreach (var bui in _userInterfaceSystem.GetActorUis(uid))
{
if (HasComp<ActivatableUIRequiresVisionComponent>(bui.Entity))
{
toClose.Add(bui);
}
}
foreach (var bui in toClose)
{
_userInterfaceSystem.CloseUi(bui.Entity, bui.Key, uid);
}
}
}

View File

@@ -1,63 +0,0 @@
using Content.Shared.StatusEffect;
using Content.Shared.Inventory;
using Content.Shared.Eye.Blinding.Components;
using Content.Shared.Eye.Blinding.Systems;
using Content.Shared.Tools.Components;
using Content.Shared.Item.ItemToggle.Components;
namespace Content.Server.Eye.Blinding.EyeProtection
{
public sealed class EyeProtectionSystem : EntitySystem
{
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
[Dependency] private readonly BlindableSystem _blindingSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RequiresEyeProtectionComponent, ToolUseAttemptEvent>(OnUseAttempt);
SubscribeLocalEvent<RequiresEyeProtectionComponent, ItemToggledEvent>(OnWelderToggled);
SubscribeLocalEvent<EyeProtectionComponent, GetEyeProtectionEvent>(OnGetProtection);
SubscribeLocalEvent<EyeProtectionComponent, InventoryRelayedEvent<GetEyeProtectionEvent>>(OnGetRelayedProtection);
}
private void OnGetRelayedProtection(EntityUid uid, EyeProtectionComponent component,
InventoryRelayedEvent<GetEyeProtectionEvent> args)
{
OnGetProtection(uid, component, args.Args);
}
private void OnGetProtection(EntityUid uid, EyeProtectionComponent component, GetEyeProtectionEvent args)
{
args.Protection += component.ProtectionTime;
}
private void OnUseAttempt(EntityUid uid, RequiresEyeProtectionComponent component, ToolUseAttemptEvent args)
{
if (!component.Toggled)
return;
if (!TryComp<BlindableComponent>(args.User, out var blindable) || blindable.IsBlind)
return;
var ev = new GetEyeProtectionEvent();
RaiseLocalEvent(args.User, ev);
var time = (float) (component.StatusEffectTime - ev.Protection).TotalSeconds;
if (time <= 0)
return;
// Add permanent eye damage if they had zero protection, also somewhat scale their temporary blindness by
// how much damage they already accumulated.
_blindingSystem.AdjustEyeDamage((args.User, blindable), 1);
var statusTimeSpan = TimeSpan.FromSeconds(time * MathF.Sqrt(blindable.EyeDamage));
_statusEffectsSystem.TryAddStatusEffect(args.User, TemporaryBlindnessSystem.BlindingStatusEffect,
statusTimeSpan, false, TemporaryBlindnessSystem.BlindingStatusEffect);
}
private void OnWelderToggled(EntityUid uid, RequiresEyeProtectionComponent component, ItemToggledEvent args)
{
component.Toggled = args.Activated;
}
}
}

View File

@@ -16,7 +16,7 @@ public sealed class DamagedByFlashingSystem : EntitySystem
{
_damageable.TryChangeDamage(ent, ent.Comp.FlashDamage);
//To Do: It would be more logical if different flashes had different power,
//TODO: It would be more logical if different flashes had different power,
//and the damage would be inflicted depending on the strength of the flash.
}
}

View File

@@ -171,7 +171,7 @@ namespace Content.Server.GameTicking
var gridIds = _map.LoadMap(targetMapId, ev.GameMap.MapPath.ToString(), ev.Options);
_metaData.SetEntityName(_mapManager.GetMapEntityId(targetMapId), $"station map - {map.MapName}");
_metaData.SetEntityName(_mapManager.GetMapEntityId(targetMapId), map.MapName);
var gridUids = gridIds.ToList();
RaiseLocalEvent(new PostGameMapLoad(map, targetMapId, gridUids, stationName));

View File

@@ -483,7 +483,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
if (!Resolve(ent, ref ent.Comp, false))
return null;
return ent.Comp.MapGrids.Where(e => HasComp<StationMemberComponent>(e) && !HasComp<NukeOpsShuttleComponent>(e)).FirstOrNull();
return ent.Comp.MapGrids.Where(e => !HasComp<NukeOpsShuttleComponent>(e)).FirstOrNull();
}
/// <remarks>

View File

@@ -1,30 +0,0 @@
using Robust.Shared.Prototypes;
namespace Content.Server.Ghost.Roles.Components
{
/// <summary>
/// Allows a ghost to take this role, spawning a new entity.
/// </summary>
[RegisterComponent, EntityCategory("Spawner")]
[Access(typeof(GhostRoleSystem))]
public sealed partial class GhostRoleMobSpawnerComponent : Component
{
[DataField]
public bool DeleteOnSpawn = true;
[DataField]
public int AvailableTakeovers = 1;
[ViewVariables]
public int CurrentTakeovers = 0;
[DataField]
public EntProtoId? Prototype;
/// <summary>
/// If this ghostrole spawner has multiple selectable ghostrole prototypes.
/// </summary>
[DataField]
public List<string> SelectablePrototypes = [];
}
}

View File

@@ -3,7 +3,6 @@ using Content.Server.Administration.Logs;
using Content.Server.EUI;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Ghost.Roles.Events;
using Content.Server.Ghost.Roles.Raffles;
using Content.Shared.Ghost.Roles.Raffles;
using Content.Server.Ghost.Roles.UI;
using Content.Server.Mind.Commands;
@@ -31,6 +30,7 @@ using Robust.Shared.Utility;
using Content.Server.Popups;
using Content.Shared.Verbs;
using Robust.Shared.Collections;
using Content.Shared.Ghost.Roles.Components;
namespace Content.Server.Ghost.Roles
{
@@ -80,6 +80,7 @@ namespace Content.Server.Ghost.Roles
SubscribeLocalEvent<GhostRoleMobSpawnerComponent, TakeGhostRoleEvent>(OnSpawnerTakeRole);
SubscribeLocalEvent<GhostTakeoverAvailableComponent, TakeGhostRoleEvent>(OnTakeoverTakeRole);
SubscribeLocalEvent<GhostRoleMobSpawnerComponent, GetVerbsEvent<Verb>>(OnVerb);
SubscribeLocalEvent<GhostRoleMobSpawnerComponent, GhostRoleRadioMessage>(OnGhostRoleRadioMessage);
_playerManager.PlayerStatusChanged += PlayerStatusChanged;
}
@@ -786,6 +787,21 @@ namespace Content.Server.Ghost.Roles
_popupSystem.PopupEntity(msg, uid, userUid.Value);
}
}
public void OnGhostRoleRadioMessage(Entity<GhostRoleMobSpawnerComponent> entity, ref GhostRoleRadioMessage args)
{
if (!_prototype.TryIndex(args.ProtoId, out var ghostRoleProto))
return;
// if the prototype chosen isn't actually part of the selectable options, ignore it
foreach (var selectableProto in entity.Comp.SelectablePrototypes)
{
if (selectableProto == ghostRoleProto.EntityPrototype.Id)
return;
}
SetMode(entity.Owner, ghostRoleProto, ghostRoleProto.Name, entity.Comp);
}
}
[AnyCommand]

View File

@@ -96,7 +96,7 @@ public sealed class ToggleableGhostRoleSystem : EntitySystem
private void AddWipeVerb(EntityUid uid, ToggleableGhostRoleComponent component, GetVerbsEvent<ActivationVerb> args)
{
if (!args.CanAccess || !args.CanInteract)
if (args.Hands == null || !args.CanAccess || !args.CanInteract)
return;
if (TryComp<MindContainerComponent>(uid, out var mind) && mind.HasMind)

View File

@@ -170,7 +170,7 @@ namespace Content.Server.Hands.Systems
private bool HandleThrowItem(ICommonSession? playerSession, EntityCoordinates coordinates, EntityUid entity)
{
if (playerSession?.AttachedEntity is not {Valid: true} player || !Exists(player))
if (playerSession?.AttachedEntity is not {Valid: true} player || !Exists(player) || !coordinates.IsValid(EntityManager))
return false;
return ThrowHeldItem(player, coordinates);

View File

@@ -79,6 +79,9 @@ namespace Content.Server.Kitchen.Components
public Container Storage = default!;
[DataField]
public string ContainerId = "microwave_entity_container";
[DataField, ViewVariables(VVAccess.ReadWrite)]
public int Capacity = 10;

View File

@@ -252,7 +252,7 @@ namespace Content.Server.Kitchen.EntitySystems
private void OnInit(Entity<MicrowaveComponent> ent, ref ComponentInit args)
{
// this really does have to be in ComponentInit
ent.Comp.Storage = _container.EnsureContainer<Container>(ent, "microwave_entity_container");
ent.Comp.Storage = _container.EnsureContainer<Container>(ent, ent.Comp.ContainerId);
}
private void OnMapInit(Entity<MicrowaveComponent> ent, ref MapInitEvent args)
@@ -312,6 +312,9 @@ namespace Content.Server.Kitchen.EntitySystems
private void OnInsertAttempt(Entity<MicrowaveComponent> ent, ref ContainerIsInsertingAttemptEvent args)
{
if (args.Container.ID != ent.Comp.ContainerId)
return;
if (ent.Comp.Broken)
{
args.Cancel();

View File

@@ -157,7 +157,7 @@ namespace Content.Server.Kitchen.EntitySystems
var outputContainer = _itemSlotsSystem.GetItemOrNull(uid, SharedReagentGrinder.BeakerSlotId);
_appearanceSystem.SetData(uid, ReagentGrinderVisualState.BeakerAttached, outputContainer.HasValue);
if (reagentGrinder.AutoMode != GrinderAutoMode.Off && !HasComp<ActiveReagentGrinderComponent>(uid))
if (reagentGrinder.AutoMode != GrinderAutoMode.Off && !HasComp<ActiveReagentGrinderComponent>(uid) && this.IsPowered(uid, EntityManager))
{
var program = reagentGrinder.AutoMode == GrinderAutoMode.Grind ? GrinderProgram.Grind : GrinderProgram.Juice;
DoWork(uid, reagentGrinder, program);

View File

@@ -3,11 +3,11 @@ using Content.Server.Audio;
using Content.Server.Light.Components;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared.Examine;
using Content.Shared.Light;
using Content.Shared.Light.Components;
using Content.Shared.Station.Components;
using Robust.Server.GameObjects;
using Color = Robust.Shared.Maths.Color;

View File

@@ -71,9 +71,9 @@ public sealed class LightningSystem : SharedLightningSystem
/// <param name="triggerLightningEvents">if the lightnings being fired should trigger lightning events.</param>
public void ShootRandomLightnings(EntityUid user, float range, int boltCount, string lightningPrototype = "Lightning", int arcDepth = 0, bool triggerLightningEvents = true)
{
//To Do: add support to different priority target tablem for different lightning types
//To Do: Remove Hardcode LightningTargetComponent (this should be a parameter of the SharedLightningComponent)
//To Do: This is still pretty bad for perf but better than before and at least it doesn't re-allocate
//TODO: add support to different priority target tablem for different lightning types
//TODO: Remove Hardcode LightningTargetComponent (this should be a parameter of the SharedLightningComponent)
//TODO: This is still pretty bad for perf but better than before and at least it doesn't re-allocate
// several hashsets every time
var targets = _lookup.GetComponentsInRange<LightningTargetComponent>(_transform.GetMapCoordinates(user), range).ToList();

View File

@@ -1,4 +1,4 @@
using Content.Server.DeviceNetwork;
using Content.Server.DeviceNetwork;
using Content.Server.DeviceNetwork.Components;
using Content.Server.DeviceNetwork.Systems;
using Content.Server.Medical.SuitSensors;

View File

@@ -0,0 +1,11 @@
using Robust.Shared.Prototypes;
namespace Content.Server.NPC.Queries.Queries;
/// <summary>
/// Remove anchored entities from the query
/// </summary>
public sealed partial class RemoveAnchoredFilter : UtilityQueryFilter
{
}

View File

@@ -1,7 +1,6 @@
using Content.Server.NPC.Components;
using Content.Shared.CombatMode;
using Content.Shared.Interaction;
using Content.Shared.Physics;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Events;
using Robust.Shared.Map;
@@ -134,7 +133,7 @@ public sealed partial class NPCCombatSystem
{
comp.LOSAccumulator += UnoccludedCooldown;
// For consistency with NPC steering.
comp.TargetInLOS = _interaction.InRangeUnobstructed(uid, Transform(comp.Target).Coordinates, distance + 0.1f);
comp.TargetInLOS = _interaction.InRangeUnobstructed(uid, comp.Target, distance + 0.1f);
}
if (!comp.TargetInLOS)

View File

@@ -499,6 +499,26 @@ public sealed class NPCUtilitySystem : EntitySystem
break;
}
case RemoveAnchoredFilter:
{
_entityList.Clear();
foreach (var ent in entities)
{
if (!TryComp(ent, out TransformComponent? xform))
continue;
if (xform.Anchored)
_entityList.Add(ent);
}
foreach (var ent in _entityList)
{
entities.Remove(ent);
}
break;
}
case PuddleFilter:
{
_entityList.Clear();

View File

@@ -211,6 +211,7 @@ public sealed class DrinkSystem : SharedDrinkSystem
target: target,
used: item)
{
BreakOnHandChange = false,
BreakOnMove = forceDrink,
BreakOnDamage = true,
MovementThreshold = 0.01f,

View File

@@ -198,6 +198,7 @@ public sealed class FoodSystem : EntitySystem
target: target,
used: food)
{
BreakOnHandChange = false,
BreakOnMove = forceFeed,
BreakOnDamage = true,
MovementThreshold = 0.01f,

View File

@@ -1,13 +1,12 @@
using Content.Shared.Singularity.Components;
using Robust.Shared.Prototypes;
namespace Content.Server.ParticleAccelerator.Components;
[RegisterComponent]
public sealed partial class ParticleAcceleratorEmitterComponent : Component
{
[DataField("emittedPrototype")]
[ViewVariables(VVAccess.ReadWrite)]
public string EmittedPrototype = "ParticlesProjectile";
[DataField]
public EntProtoId EmittedPrototype = "ParticlesProjectile";
[DataField("emitterType")]
[ViewVariables(VVAccess.ReadWrite)]

View File

@@ -101,6 +101,7 @@ public sealed partial class ParticleAcceleratorSystem
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):player} has turned {ToPrettyString(uid)} off");
comp.Enabled = false;
SetStrength(uid, ParticleAcceleratorPowerState.Standby, user, comp);
UpdatePowerDraw(uid, comp);
PowerOff(uid, comp);
UpdateUI(uid, comp);
@@ -174,12 +175,14 @@ public sealed partial class ParticleAcceleratorSystem
var pos = Transform(uid);
if (_timing.CurTime > comp.EffectCooldown)
{
_chat.SendAdminAlert(player, Loc.GetString("particle-accelerator-admin-power-strength-warning",
_chat.SendAdminAlert(player,
Loc.GetString("particle-accelerator-admin-power-strength-warning",
("machine", ToPrettyString(uid)),
("powerState", strength),
("powerState", GetPANumericalLevel(strength)),
("coordinates", pos.Coordinates)));
_audio.PlayGlobal("/Audio/Misc/adminlarm.ogg",
Filter.Empty().AddPlayers(_adminManager.ActiveAdmins), false,
Filter.Empty().AddPlayers(_adminManager.ActiveAdmins),
false,
AudioParams.Default.WithVolume(-8f));
comp.EffectCooldown = _timing.CurTime + comp.CooldownDuration;
}
@@ -230,7 +233,7 @@ public sealed partial class ParticleAcceleratorSystem
powerConsumer.DrawRate = powerDraw;
}
private void UpdateUI(EntityUid uid, ParticleAcceleratorControlBoxComponent? comp = null)
public void UpdateUI(EntityUid uid, ParticleAcceleratorControlBoxComponent? comp = null)
{
if (!Resolve(uid, ref comp))
return;
@@ -247,7 +250,9 @@ public sealed partial class ParticleAcceleratorSystem
receive = powerConsumer.ReceivedPower;
}
_uiSystem.SetUiState(uid, ParticleAcceleratorControlBoxUiKey.Key, new ParticleAcceleratorUIState(
_uiSystem.SetUiState(uid,
ParticleAcceleratorControlBoxUiKey.Key,
new ParticleAcceleratorUIState(
comp.Assembled,
comp.Enabled,
comp.SelectedStrength,
@@ -396,4 +401,16 @@ public sealed partial class ParticleAcceleratorSystem
UpdateUI(uid, comp);
}
public static int GetPANumericalLevel(ParticleAcceleratorPowerState state)
{
return state switch
{
ParticleAcceleratorPowerState.Level0 => 1,
ParticleAcceleratorPowerState.Level1 => 2,
ParticleAcceleratorPowerState.Level2 => 3,
ParticleAcceleratorPowerState.Level3 => 4,
_ => 0
};
}
}

View File

@@ -1,10 +1,8 @@
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using Content.Server.ParticleAccelerator.Components;
using JetBrains.Annotations;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Events;
using Robust.Shared.Player;
namespace Content.Server.ParticleAccelerator.EntitySystems;
@@ -26,8 +24,6 @@ public sealed partial class ParticleAcceleratorSystem
if (controller.CurrentlyRescanning)
return;
SwitchOff(uid, user, controller);
var partQuery = GetEntityQuery<ParticleAcceleratorPartComponent>();
foreach (var part in AllParts(uid, controller))
{
@@ -45,19 +41,25 @@ public sealed partial class ParticleAcceleratorSystem
var xformQuery = GetEntityQuery<TransformComponent>();
if (!xformQuery.TryGetComponent(uid, out var xform) || !xform.Anchored)
{
SwitchOff(uid, user, controller);
return;
}
var gridUid = xform.GridUid;
if (gridUid == null || gridUid != xform.ParentUid || !TryComp<MapGridComponent>(gridUid, out var grid))
{
SwitchOff(uid, user, controller);
return;
}
// Find fuel chamber first by scanning cardinals.
var fuelQuery = GetEntityQuery<ParticleAcceleratorFuelChamberComponent>();
foreach (var adjacent in _mapSystem.GetCardinalNeighborCells(gridUid.Value, grid, xform.Coordinates))
{
if (fuelQuery.HasComponent(adjacent)
&& partQuery.TryGetComponent(adjacent, out var partState)
&& partState.Master == null)
&& partQuery.TryGetComponent(adjacent, out var partState)
&& partState.Master == null)
{
controller.FuelChamber = adjacent;
break;
@@ -66,7 +68,7 @@ public sealed partial class ParticleAcceleratorSystem
if (controller.FuelChamber == null)
{
UpdateUI(uid, controller);
SwitchOff(uid, user, controller);
return;
}
@@ -93,19 +95,19 @@ public sealed partial class ParticleAcceleratorSystem
var positionForeEmitter = positionFuelChamber + offsetVect * 2;
var positionStarboardEmitter = positionFuelChamber + offsetVect * 2 - orthoOffsetVect;
ScanPart<ParticleAcceleratorEndCapComponent>(gridUid!.Value, positionEndCap, rotation, out controller.EndCap, out var _, grid);
ScanPart<ParticleAcceleratorPowerBoxComponent>(gridUid!.Value, positionPowerBox, rotation, out controller.PowerBox, out var _, grid);
ScanPart<ParticleAcceleratorEndCapComponent>(gridUid.Value, positionEndCap, rotation, out controller.EndCap, out _, grid);
ScanPart<ParticleAcceleratorPowerBoxComponent>(gridUid.Value, positionPowerBox, rotation, out controller.PowerBox, out _, grid);
if (!ScanPart<ParticleAcceleratorEmitterComponent>(gridUid!.Value, positionPortEmitter, rotation, out controller.PortEmitter, out var portEmitter, grid)
|| portEmitter!.Type != ParticleAcceleratorEmitterType.Port)
if (!ScanPart<ParticleAcceleratorEmitterComponent>(gridUid.Value, positionPortEmitter, rotation, out controller.PortEmitter, out var portEmitter, grid)
|| portEmitter.Type != ParticleAcceleratorEmitterType.Port)
controller.PortEmitter = null;
if (!ScanPart<ParticleAcceleratorEmitterComponent>(gridUid!.Value, positionForeEmitter, rotation, out controller.ForeEmitter, out var foreEmitter, grid)
|| foreEmitter!.Type != ParticleAcceleratorEmitterType.Fore)
if (!ScanPart<ParticleAcceleratorEmitterComponent>(gridUid.Value, positionForeEmitter, rotation, out controller.ForeEmitter, out var foreEmitter, grid)
|| foreEmitter.Type != ParticleAcceleratorEmitterType.Fore)
controller.ForeEmitter = null;
if (!ScanPart<ParticleAcceleratorEmitterComponent>(gridUid!.Value, positionStarboardEmitter, rotation, out controller.StarboardEmitter, out var starboardEmitter, grid)
|| starboardEmitter!.Type != ParticleAcceleratorEmitterType.Starboard)
if (!ScanPart<ParticleAcceleratorEmitterComponent>(gridUid.Value, positionStarboardEmitter, rotation, out controller.StarboardEmitter, out var starboardEmitter, grid)
|| starboardEmitter.Type != ParticleAcceleratorEmitterType.Starboard)
controller.StarboardEmitter = null;
controller.Assembled =
@@ -157,19 +159,19 @@ public sealed partial class ParticleAcceleratorSystem
private void OnComponentShutdown(EntityUid uid, ParticleAcceleratorPartComponent comp, ComponentShutdown args)
{
if (EntityManager.EntityExists(comp.Master))
if (Exists(comp.Master))
RescanParts(comp.Master!.Value);
}
private void BodyTypeChanged(EntityUid uid, ParticleAcceleratorPartComponent comp, ref PhysicsBodyTypeChangedEvent args)
{
if (EntityManager.EntityExists(comp.Master))
if (Exists(comp.Master))
RescanParts(comp.Master!.Value);
}
private void OnMoveEvent(EntityUid uid, ParticleAcceleratorPartComponent comp, ref MoveEvent args)
{
if (EntityManager.EntityExists(comp.Master))
if (Exists(comp.Master))
RescanParts(comp.Master!.Value);
}
}

View File

@@ -1,4 +1,5 @@
using Content.Server.ParticleAccelerator.Components;
using Content.Server.ParticleAccelerator.EntitySystems;
using Content.Server.Wires;
using Content.Shared.Singularity.Components;
using Content.Shared.Wires;
@@ -19,12 +20,16 @@ public sealed partial class ParticleAcceleratorKeyboardWireAction : ComponentWir
public override bool Cut(EntityUid user, Wire wire, ParticleAcceleratorControlBoxComponent controller)
{
controller.InterfaceDisabled = true;
var paSystem = EntityManager.System<ParticleAcceleratorSystem>();
paSystem.UpdateUI(wire.Owner, controller);
return true;
}
public override bool Mend(EntityUid user, Wire wire, ParticleAcceleratorControlBoxComponent controller)
{
controller.InterfaceDisabled = false;
var paSystem = EntityManager.System<ParticleAcceleratorSystem>();
paSystem.UpdateUI(wire.Owner, controller);
return true;
}

View File

@@ -5,7 +5,6 @@ using Content.Server.Wires;
using Content.Shared.Popups;
using Content.Shared.Singularity.Components;
using Content.Shared.Wires;
using Robust.Shared.Player;
namespace Content.Server.ParticleAccelerator.Wires;
@@ -35,6 +34,8 @@ public sealed partial class ParticleAcceleratorLimiterWireAction : ComponentWire
public override bool Cut(EntityUid user, Wire wire, ParticleAcceleratorControlBoxComponent controller)
{
controller.MaxStrength = ParticleAcceleratorPowerState.Level3;
var paSystem = EntityManager.System<ParticleAcceleratorSystem>();
paSystem.UpdateUI(wire.Owner, controller);
return true;
}
@@ -49,12 +50,14 @@ public sealed partial class ParticleAcceleratorLimiterWireAction : ComponentWire
// Since that blocks SetStrength().
var paSystem = EntityManager.System<ParticleAcceleratorSystem>();
paSystem.SetStrength(wire.Owner, controller.MaxStrength, user, controller);
paSystem.UpdateUI(wire.Owner, controller);
return true;
}
public override void Pulse(EntityUid user, Wire wire, ParticleAcceleratorControlBoxComponent controller)
{
EntityManager.System<PopupSystem>().PopupEntity(
EntityManager.System<PopupSystem>()
.PopupEntity(
Loc.GetString("particle-accelerator-control-box-component-wires-update-limiter-on-pulse"),
user,
PopupType.SmallCaution

View File

@@ -21,12 +21,16 @@ public sealed partial class ParticleAcceleratorStrengthWireAction : ComponentWir
public override bool Cut(EntityUid user, Wire wire, ParticleAcceleratorControlBoxComponent controller)
{
controller.StrengthLocked = true;
var paSystem = EntityManager.System<ParticleAcceleratorSystem>();
paSystem.UpdateUI(wire.Owner, controller);
return true;
}
public override bool Mend(EntityUid user, Wire wire, ParticleAcceleratorControlBoxComponent controller)
{
controller.StrengthLocked = false;
var paSystem = EntityManager.System<ParticleAcceleratorSystem>();
paSystem.UpdateUI(wire.Owner, controller);
return true;
}

View File

@@ -65,7 +65,7 @@ public sealed partial class ChasingWalkComponent : Component
/// The component that the entity is chasing
/// </summary>
[DataField(required: true)]
public ComponentRegistry ChasingComponent = default!;
public ComponentRegistry ChasingComponent = [];
/// <summary>
/// The maximum radius in which the entity chooses the target component to follow

View File

@@ -61,6 +61,9 @@ public sealed class ChasingWalkSystem : VirtualController
private void ChangeTarget(EntityUid uid, ChasingWalkComponent component)
{
if (component.ChasingComponent.Count <= 0)
return;
//We find our coordinates and calculate the radius of the target search.
var xform = Transform(uid);
var range = component.MaxChaseRadius;

View File

@@ -4,10 +4,10 @@ using Content.Server.NodeContainer.Nodes;
using Content.Server.Power.Components;
using Content.Server.Power.Nodes;
using Content.Server.Power.NodeGroups;
using Content.Server.Station.Components;
using Content.Server.StationEvents.Components;
using Content.Shared.GameTicking.Components;
using Content.Shared.Pinpointer;
using Content.Shared.Station.Components;
using Content.Shared.Power;
using JetBrains.Annotations;
using Robust.Server.GameObjects;

View File

@@ -2,7 +2,7 @@
using Content.Server.Atmos.EntitySystems;
using Content.Server.Chat.Managers;
using Content.Server.GameTicking;
using Content.Server.Station.Components;
using Content.Shared.Station.Components;
using Content.Server.Station.Systems;
using Content.Shared.Database;
using Content.Shared.Maps;

View File

@@ -26,6 +26,11 @@ public interface IGridSpawnGroup
/// </summary>
public float MinimumDistance { get; }
/// <summary>
/// Maximum distance to spawn away from the station.
/// </summary>
public float MaximumDistance { get; }
/// <inheritdoc />
public ProtoId<DatasetPrototype>? NameDataset { get; }
@@ -67,6 +72,8 @@ public sealed class DungeonSpawnGroup : IGridSpawnGroup
/// <inheritdoc />
public float MinimumDistance { get; }
public float MaximumDistance { get; }
/// <inheritdoc />
public ProtoId<DatasetPrototype>? NameDataset { get; }
@@ -94,7 +101,11 @@ public sealed class GridSpawnGroup : IGridSpawnGroup
{
public List<ResPath> Paths = new();
/// <inheritdoc />
public float MinimumDistance { get; }
/// <inheritdoc />
public float MaximumDistance { get; }
public ProtoId<DatasetPrototype>? NameDataset { get; }
public int MinCount { get; set; } = 1;
public int MaxCount { get; set; } = 1;

View File

@@ -281,24 +281,24 @@ namespace Content.Server.Shuttles.Systems
{
if (_doorSystem.TryOpen(dockAUid, doorA))
{
doorA.ChangeAirtight = false;
if (TryComp<DoorBoltComponent>(dockAUid, out var airlockA))
{
_doorSystem.SetBoltsDown((dockAUid, airlockA), true);
}
}
doorA.ChangeAirtight = false;
}
if (TryComp(dockBUid, out DoorComponent? doorB))
{
if (_doorSystem.TryOpen(dockBUid, doorB))
{
doorB.ChangeAirtight = false;
if (TryComp<DoorBoltComponent>(dockBUid, out var airlockB))
{
_doorSystem.SetBoltsDown((dockBUid, airlockB), true);
}
}
doorB.ChangeAirtight = false;
}
if (_pathfinding.TryCreatePortal(dockAXform.Coordinates, dockBXform.Coordinates, out var handle))

View File

@@ -1,6 +1,6 @@
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Events;
using Content.Server.Station.Components;
using Content.Shared.Station.Components;
using Content.Shared.UserInterface;
namespace Content.Server.Shuttles.Systems;

View File

@@ -7,8 +7,10 @@ using Content.Shared.CCVar;
using Content.Shared.Procedural;
using Content.Shared.Salvage;
using Content.Shared.Shuttles.Components;
using Content.Shared.Station.Components;
using Robust.Shared.Collections;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Random;
using Robust.Shared.Utility;
@@ -85,9 +87,15 @@ public sealed partial class ShuttleSystem
_mapManager.DeleteMap(mapId);
}
private bool TryDungeonSpawn(EntityUid targetGrid, EntityUid stationUid, MapId mapId, DungeonSpawnGroup group, out EntityUid spawned)
private bool TryDungeonSpawn(Entity<MapGridComponent?> targetGrid, EntityUid stationUid, MapId mapId, DungeonSpawnGroup group, out EntityUid spawned)
{
spawned = EntityUid.Invalid;
if (!_gridQuery.Resolve(targetGrid.Owner, ref targetGrid.Comp))
{
return false;
}
var dungeonProtoId = _random.Pick(group.Protos);
if (!_protoManager.TryIndex(dungeonProtoId, out var dungeonProto))
@@ -95,11 +103,13 @@ public sealed partial class ShuttleSystem
return false;
}
var spawnCoords = new EntityCoordinates(targetGrid, Vector2.Zero);
var targetPhysics = _physicsQuery.Comp(targetGrid);
var spawnCoords = new EntityCoordinates(targetGrid, targetPhysics.LocalCenter);
if (group.MinimumDistance > 0f)
{
spawnCoords = spawnCoords.Offset(_random.NextVector2(group.MinimumDistance, group.MinimumDistance * 1.5f));
var distancePadding = MathF.Max(targetGrid.Comp.LocalAABB.Width, targetGrid.Comp.LocalAABB.Height);
spawnCoords = spawnCoords.Offset(_random.NextVector2(distancePadding + group.MinimumDistance, distancePadding + group.MaximumDistance));
}
var spawnMapCoords = _transform.ToMapCoordinates(spawnCoords);

View File

@@ -1,4 +1,5 @@
using Content.Server.Shuttles.Components;
using Content.Shared.CCVar;
using Content.Shared.Shuttles.BUIStates;
using Content.Shared.Shuttles.Components;
using Content.Shared.Shuttles.Events;
@@ -12,6 +13,26 @@ public sealed partial class ShuttleSystem
SubscribeLocalEvent<IFFConsoleComponent, AnchorStateChangedEvent>(OnIFFConsoleAnchor);
SubscribeLocalEvent<IFFConsoleComponent, IFFShowIFFMessage>(OnIFFShow);
SubscribeLocalEvent<IFFConsoleComponent, IFFShowVesselMessage>(OnIFFShowVessel);
SubscribeLocalEvent<GridSplitEvent>(OnGridSplit);
}
private void OnGridSplit(ref GridSplitEvent ev)
{
var splitMass = _cfg.GetCVar(CCVars.HideSplitGridsUnder);
if (splitMass < 0)
return;
foreach (var grid in ev.NewGrids)
{
if (!_physicsQuery.TryGetComponent(grid, out var physics) ||
physics.Mass > splitMass)
{
continue;
}
AddIFFFlag(grid, IFFFlags.HideLabel);
}
}
private void OnIFFShow(EntityUid uid, IFFConsoleComponent component, IFFShowIFFMessage args)

View File

@@ -60,12 +60,16 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
[Dependency] private readonly AtmosphereSystem _atmos = default!; //CP14 FTL atmos
private EntityQuery<MapGridComponent> _gridQuery;
public const float TileMassMultiplier = 0.5f;
public override void Initialize()
{
base.Initialize();
_gridQuery = GetEntityQuery<MapGridComponent>();
InitializeFTL();
InitializeGridFills();
InitializeIFF();

View File

@@ -1,16 +0,0 @@
using Content.Server.Station.Systems;
namespace Content.Server.Station.Components;
/// <summary>
/// Indicates that a grid is a member of the given station.
/// </summary>
[RegisterComponent, Access(typeof(StationSystem))]
public sealed partial class StationMemberComponent : Component
{
/// <summary>
/// Station that this grid is a part of.
/// </summary>
[DataField]
public EntityUid Station = EntityUid.Invalid;
}

View File

@@ -68,6 +68,8 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
_spawnerCallbacks = new Dictionary<SpawnPriorityPreference, Action<PlayerSpawningEvent>>()
{
{ SpawnPriorityPreference.Arrivals, _CP14expedition.HandlePlayerSpawning }, //CP14 expedition system replaced
{ SpawnPriorityPreference.Cryosleep, _CP14expedition.HandlePlayerSpawning }, //CP14 expedition system replaced
/*
{
SpawnPriorityPreference.Cryosleep, ev =>
{
@@ -76,7 +78,7 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
else
_containerSpawnPointSystem.HandlePlayerSpawning(ev);
}
}
}*/
};
}

View File

@@ -5,6 +5,7 @@ using Content.Server.Station.Components;
using Content.Server.Station.Events;
using Content.Shared.CCVar;
using Content.Shared.Station;
using Content.Shared.Station.Components;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
using Robust.Server.Player;

View File

@@ -1,11 +0,0 @@
using Content.Server.StationEvents.Events;
namespace Content.Server.StationEvents.Components;
/// <summary>
/// This is used to keep track of hallucinated entities to remove effects when event ends
/// </summary>
[RegisterComponent, Access(typeof(MassHallucinationsRule))]
public sealed partial class MassHallucinationsComponent : Component
{
}

View File

@@ -1,5 +1,6 @@
using Content.Server.StationEvents.Events;
using Robust.Shared.Audio;
using Robust.Shared.Collections;
namespace Content.Server.StationEvents.Components;
@@ -23,4 +24,7 @@ public sealed partial class MassHallucinationsRuleComponent : Component
[DataField("sounds", required: true)]
public SoundSpecifier Sounds = default!;
[DataField, ViewVariables(VVAccess.ReadOnly)]
public List<EntityUid> AffectedEntities = new();
}

View File

@@ -1,10 +1,9 @@
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Resist;
using Content.Server.Station.Components;
using Content.Server.StationEvents.Components;
using Content.Server.Storage.Components;
using Content.Server.Storage.EntitySystems;
using Content.Shared.Access.Components;
using Content.Shared.Station.Components;
using Content.Shared.GameTicking.Components;
using Content.Shared.Coordinates;

View File

@@ -1,8 +1,8 @@
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Station.Components;
using Content.Server.StationEvents.Components;
using Content.Shared.GameTicking.Components;
using Content.Shared.GameTicking.Components;
using Content.Shared.Station.Components;
using JetBrains.Annotations;
namespace Content.Server.StationEvents.Events;

View File

@@ -1,6 +1,5 @@
using System.Linq;
using Content.Server.Silicons.Laws;
using Content.Server.Station.Components;
using Content.Server.StationEvents.Components;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
@@ -11,6 +10,7 @@ using Content.Shared.Random;
using Content.Shared.Random.Helpers;
using Content.Shared.Silicons.Laws;
using Content.Shared.Silicons.Laws.Components;
using Content.Shared.Station.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;

View File

@@ -2,9 +2,11 @@ using Content.Server.GameTicking.Rules.Components;
using Content.Server.StationEvents.Components;
using Content.Server.Traits.Assorted;
using Content.Shared.GameTicking.Components;
using Content.Shared.Humanoid;
using Content.Shared.Mind.Components;
using Content.Shared.Traits.Assorted;
namespace Content.Server.StationEvents.Events;
public sealed class MassHallucinationsRule : StationEventSystem<MassHallucinationsRuleComponent>
@@ -14,16 +16,17 @@ public sealed class MassHallucinationsRule : StationEventSystem<MassHallucinatio
protected override void Started(EntityUid uid, MassHallucinationsRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args)
{
base.Started(uid, component, gameRule, args);
var query = EntityQueryEnumerator<MindContainerComponent>();
while (query.MoveNext(out var ent, out _))
var query = EntityQueryEnumerator<MindContainerComponent, HumanoidAppearanceComponent>();
while (query.MoveNext(out var ent, out _, out _))
{
if (!HasComp<ParacusiaComponent>(ent))
if (!EnsureComp<ParacusiaComponent>(ent, out var paracusia))
{
EnsureComp<MassHallucinationsComponent>(ent);
var paracusia = EnsureComp<ParacusiaComponent>(ent);
_paracusia.SetSounds(ent, component.Sounds, paracusia);
_paracusia.SetTime(ent, component.MinTimeBetweenIncidents, component.MaxTimeBetweenIncidents, paracusia);
_paracusia.SetDistance(ent, component.MaxSoundDistance);
component.AffectedEntities.Add(ent);
}
}
}
@@ -31,10 +34,12 @@ public sealed class MassHallucinationsRule : StationEventSystem<MassHallucinatio
protected override void Ended(EntityUid uid, MassHallucinationsRuleComponent component, GameRuleComponent gameRule, GameRuleEndedEvent args)
{
base.Ended(uid, component, gameRule, args);
var query = EntityQueryEnumerator<MassHallucinationsComponent>();
while (query.MoveNext(out var ent, out _))
foreach (var ent in component.AffectedEntities)
{
RemComp<ParacusiaComponent>(ent);
}
component.AffectedEntities.Clear();
}
}

View File

@@ -1,10 +1,9 @@
using System.Threading;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Station.Components;
using Content.Server.StationEvents.Components;
using Content.Shared.GameTicking.Components;
using Content.Shared.Station.Components;
using JetBrains.Annotations;
using Robust.Shared.Audio;
using Robust.Shared.Player;

View File

@@ -1,14 +1,13 @@
using Content.Server.Atmos.Piping.Unary.Components;
using Content.Server.Station.Components;
using Content.Server.Fluids.EntitySystems;
using Content.Server.StationEvents.Components;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.GameTicking.Components;
using Content.Shared.Station.Components;
using JetBrains.Annotations;
using Robust.Shared.Random;
using System.Linq;
using Content.Server.Fluids.EntitySystems;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.StationEvents.Components;
using Content.Shared.GameTicking.Components;
namespace Content.Server.StationEvents.Events;

View File

@@ -1,7 +1,6 @@
using Content.Server.StationEvents.Components;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.Station.Components;
using Content.Shared.GameTicking.Components;
using Content.Shared.Station.Components;
using Content.Shared.Storage;
using Robust.Shared.Map;
using Robust.Shared.Random;

View File

@@ -1,7 +1,6 @@
using System.Linq;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Resist;
using Content.Server.Station.Components;
using Content.Server.Storage.Components;
using Content.Shared.Access;
using Content.Shared.Access.Components;
@@ -9,6 +8,7 @@ using Content.Shared.Coordinates;
using Content.Shared.DoAfter;
using Content.Shared.Lock;
using Content.Shared.Mind.Components;
using Content.Shared.Station.Components;
using Content.Shared.Storage.Components;
using Content.Shared.Storage.EntitySystems;
using Content.Shared.Tools.Systems;

View File

@@ -47,21 +47,6 @@ public sealed class EntityHeaterSystem : EntitySystem
_temperature.ChangeHeat(ent, energy);
}
}
//CrystallPunk bonfire
var flammbaleQuery = EntityQueryEnumerator<CP14FlammableEntityHeaterComponent, ItemPlacerComponent, FlammableComponent>();
while (flammbaleQuery.MoveNext(out var uid, out var heater, out var placer, out var flammable))
{
if (!flammable.OnFire)
return;
var energy = flammable.FireStacks * deltaTime * heater.EnergyPerFireStack;
foreach (var ent in placer.PlacedEntities)
{
_temperature.ChangeHeat(ent, energy);
}
}
//CrystallPunk bonfire end
}
private void OnExamined(EntityUid uid, EntityHeaterComponent comp, ExaminedEvent args)

View File

@@ -4,7 +4,7 @@ using Content.Shared.IdentityManagement;
using Content.Shared.Popups;
using Content.Shared.Tag;
using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Audio;
using Content.Shared.Throwing;
using Robust.Shared.Audio.Systems;
namespace Content.Server.Weapons.Melee.Balloon;
@@ -23,6 +23,7 @@ public sealed class BalloonPopperSystem : EntitySystem
public override void Initialize()
{
SubscribeLocalEvent<BalloonPopperComponent, MeleeHitEvent>(OnMeleeHit);
SubscribeLocalEvent<BalloonPopperComponent, ThrowDoHitEvent>(OnThrowHit);
}
private void OnMeleeHit(EntityUid uid, BalloonPopperComponent component, MeleeHitEvent args)
@@ -40,6 +41,15 @@ public sealed class BalloonPopperSystem : EntitySystem
}
}
private void OnThrowHit(EntityUid uid, BalloonPopperComponent component, ThrowDoHitEvent args)
{
foreach (var held in _hands.EnumerateHeld(args.Target))
{
if (_tag.HasTag(held, component.BalloonTag))
PopBallooon(uid, held, component);
}
}
/// <summary>
/// Pops a target balloon, making a popup and playing a sound.
/// </summary>

View File

@@ -9,7 +9,6 @@ using Content.Server.Inventory;
using Content.Server.Mind;
using Content.Server.Mind.Commands;
using Content.Server.NPC;
using Content.Server.NPC.Components;
using Content.Server.NPC.HTN;
using Content.Server.NPC.Systems;
using Content.Server.Roles;
@@ -24,10 +23,8 @@ using Content.Shared.Humanoid;
using Content.Shared.Interaction.Components;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Movement.Systems;
using Content.Shared.NPC.Components;
using Content.Shared.NPC.Systems;
using Content.Shared.Nutrition.AnimalHusbandry;
using Content.Shared.Nutrition.Components;
@@ -38,6 +35,7 @@ using Content.Shared.Zombies;
using Content.Shared.Prying.Components;
using Content.Shared.Traits.Assorted;
using Robust.Shared.Audio.Systems;
using Content.Shared.Ghost.Roles.Components;
namespace Content.Server.Zombies
{

View File

@@ -0,0 +1,22 @@
/*
* All right reserved to CrystallPunk.
*
* BUT this file is sublicensed under MIT License
*
*/
using Content.Server._CP14.BiomeSpawner.EntitySystems;
using Content.Shared.Parallax.Biomes;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.BiomeSpawner.Components;
/// <summary>
/// fills the tile in which it is located with the contents of the biome. Includes: tile, decals and entities
/// </summary>
[RegisterComponent, Access(typeof(CP14BiomeSpawnerSystem))]
public sealed partial class CP14BiomeSpawnerComponent : Component
{
[DataField]
public ProtoId<BiomeTemplatePrototype> Biome = "Grasslands";
}

View File

@@ -0,0 +1,92 @@
/*
* All right reserved to CrystallPunk.
*
* BUT this file is sublicensed under MIT License
*
*/
using System.Linq;
using Content.Server._CP14.BiomeSpawner.Components;
using Content.Server._CP14.RoundSeed;
using Content.Server.Decals;
using Content.Server.Parallax;
using Robust.Server.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.BiomeSpawner.EntitySystems;
public sealed class CP14BiomeSpawnerSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly BiomeSystem _biome = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;
[Dependency] private readonly DecalSystem _decals = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly CP14RoundSeedSystem _roundSeed = default!;
public override void Initialize()
{
SubscribeLocalEvent<CP14BiomeSpawnerComponent, MapInitEvent>(OnMapInit);
}
private void OnMapInit(Entity<CP14BiomeSpawnerComponent> ent, ref MapInitEvent args)
{
SpawnBiome(ent);
QueueDel(ent);
}
private void SpawnBiome(Entity<CP14BiomeSpawnerComponent> ent)
{
var biome = _proto.Index(ent.Comp.Biome);
var spawnerTransform = Transform(ent);
if (spawnerTransform.GridUid == null)
return;
var gridUid = spawnerTransform.GridUid.Value;
if (!TryComp<MapGridComponent>(gridUid, out var map))
return;
var seed = _roundSeed.GetSeed();
var vec = _transform.GetGridOrMapTilePosition(ent);
if (!_biome.TryGetTile(vec, biome.Layers, seed, map, out var tile))
return;
// Set new tile
_maps.SetTile(gridUid, map, vec, tile.Value);
var tileCenterVec = vec + map.TileSizeHalfVector;
// Remove old decals
var oldDecals = _decals.GetDecalsInRange(gridUid, tileCenterVec);
foreach (var (id, _) in oldDecals)
{
_decals.RemoveDecal(gridUid, id);
}
//Add decals
if (_biome.TryGetDecals(vec, biome.Layers, seed, map, out var decals))
{
foreach (var decal in decals)
{
_decals.TryAddDecal(decal.ID, new EntityCoordinates(gridUid, decal.Position), out _);
}
}
// Remove entities
var oldEntities = _lookup.GetEntitiesInRange(spawnerTransform.Coordinates, 0.48f);
// TODO: Replace this shit with GetEntitiesInBox2
foreach (var entToRemove in oldEntities.Concat(new[] { ent.Owner })) // Do not remove self
{
QueueDel(entToRemove);
}
if (_biome.TryGetEntity(vec, biome.Layers, tile.Value, seed, map, out var entityProto))
Spawn(entityProto, new EntityCoordinates(gridUid, tileCenterVec));
}
}

View File

@@ -1,11 +1,16 @@
using Content.Server._CP14.GameTicking.Rules.Components;
using Content.Server.Mind;
using Content.Shared.Random.Helpers;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.GameTicking.Rules;
public sealed class CP14ExpeditionObjectivesRule : GameRuleSystem<CP14ExpeditionObjectivesRuleComponent>
{
[Dependency] private readonly MindSystem _mind = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
@@ -25,9 +30,38 @@ public sealed class CP14ExpeditionObjectivesRule : GameRuleSystem<CP14Expedition
return;
}
foreach (var objective in expedition.Objectives)
foreach (var (job, groups) in expedition.RoleObjectives)
{
_mind.TryAddObjective(mindId.Value, mind, objective);
if (args.JobId is null || args.JobId != job)
continue;
foreach (var weightGroupProto in groups)
{
if (!_proto.TryIndex(weightGroupProto, out var weightGroup))
continue;
_mind.TryAddObjective(mindId.Value, mind, weightGroup.Pick(_random));
}
}
foreach (var (departmentProto, objectives) in expedition.DepartmentObjectives)
{
if (args.JobId is null)
continue;
if (!_proto.TryIndex(departmentProto, out var department))
continue;
if (!department.Roles.Contains(args.JobId))
continue;
foreach (var weightGroupProto in objectives)
{
if (!_proto.TryIndex(weightGroupProto, out var weightGroup))
continue;
_mind.TryAddObjective(mindId.Value, mind, weightGroup.Pick(_random));
}
}
}
}

View File

@@ -1,4 +1,6 @@
using Content.Server.GameTicking.Rules;
using Content.Shared.Random;
using Content.Shared.Roles;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.GameTicking.Rules.Components;
@@ -10,5 +12,8 @@ namespace Content.Server._CP14.GameTicking.Rules.Components;
public sealed partial class CP14ExpeditionObjectivesRuleComponent : Component
{
[DataField]
public List<EntProtoId> Objectives = new();
public Dictionary<ProtoId<JobPrototype>, List<ProtoId<WeightedRandomPrototype>>> RoleObjectives = new();
[DataField]
public Dictionary<ProtoId<DepartmentPrototype>, List<ProtoId<WeightedRandomPrototype>>> DepartmentObjectives = new();
}

View File

@@ -1,14 +1,10 @@
using System.Linq;
using Content.Server.GameTicking.Events;
using Content.Shared._CP14.LockKey;
using Content.Shared.Containers.ItemSlots;
using Content.Shared._CP14.LockKey.Components;
using Content.Shared.Examine;
using Content.Shared.Lock;
using Content.Shared.Popups;
using Content.Shared.GameTicking;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using CP14KeyComponent = Content.Shared._CP14.LockKey.Components.CP14KeyComponent;
using CP14LockComponent = Content.Shared._CP14.LockKey.Components.CP14LockComponent;
namespace Content.Server._CP14.LockKey;
@@ -16,9 +12,6 @@ public sealed partial class CP14KeyholeGenerationSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
[Dependency] private readonly LockSystem _lock = default!;
private Dictionary<ProtoId<CP14LockCategoryPrototype>, List<int>> _roundKeyData = new();
@@ -28,7 +21,7 @@ public sealed partial class CP14KeyholeGenerationSystem : EntitySystem
{
base.Initialize();
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStart);
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundEnd);
SubscribeLocalEvent<CP14LockComponent, MapInitEvent>(OnLockInit);
SubscribeLocalEvent<CP14KeyComponent, MapInitEvent>(OnKeyInit);
@@ -37,7 +30,7 @@ public sealed partial class CP14KeyholeGenerationSystem : EntitySystem
}
#region Init
private void OnRoundStart(RoundStartingEvent ev)
private void OnRoundEnd(RoundRestartCleanupEvent ev)
{
_roundKeyData = new();
}
@@ -68,7 +61,7 @@ public sealed partial class CP14KeyholeGenerationSystem : EntitySystem
if (key.Comp.LockShape == null)
return;
var markup = Loc.GetString("cp-lock-examine-key", ("item", MetaData(key).EntityName));
var markup = Loc.GetString("cp14-lock-examine-key", ("item", MetaData(key).EntityName));
markup += " (";
foreach (var item in key.Comp.LockShape)
{

View File

@@ -0,0 +1,93 @@
using System.Numerics;
using Content.Server._CP14.MagicEnergy.Components;
using Content.Shared._CP14.MagicEnergy.Components;
namespace Content.Server._CP14.MagicEnergy;
public partial class CP14MagicEnergySystem
{
private void InitializeDraw()
{
SubscribeLocalEvent<CP14MagicEnergyDrawComponent, MapInitEvent>(OnDrawMapInit);
SubscribeLocalEvent<CP14RandomAuraNodeComponent, MapInitEvent>(OnRandomRangeMapInit);
}
private void OnRandomRangeMapInit(Entity<CP14RandomAuraNodeComponent> random, ref MapInitEvent args)
{
if (!TryComp<CP14AuraNodeComponent>(random, out var draw))
return;
draw.Energy = _random.NextFloat(random.Comp.MinDraw, random.Comp.MaxDraw);
draw.Range = _random.NextFloat(random.Comp.MinRange, random.Comp.MaxRange);
}
private void OnDrawMapInit(Entity<CP14MagicEnergyDrawComponent> ent, ref MapInitEvent args)
{
ent.Comp.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(ent.Comp.Delay);
}
private void UpdateDraw(float frameTime)
{
UpdateEnergyContainer();
UpdateEnergyCrystalSlot();
UpdateEnergyRadiusDraw();
}
private void UpdateEnergyContainer()
{
var query = EntityQueryEnumerator<CP14MagicEnergyDrawComponent, CP14MagicEnergyContainerComponent>();
while (query.MoveNext(out var uid, out var draw, out var magicContainer))
{
if (draw.NextUpdateTime >= _gameTiming.CurTime)
continue;
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
ChangeEnergy(uid, magicContainer, draw.Energy, safe: draw.Safe);
}
}
private void UpdateEnergyCrystalSlot()
{
var query = EntityQueryEnumerator<CP14MagicEnergyDrawComponent, CP14MagicEnergyCrystalSlotComponent>();
while (query.MoveNext(out var uid, out var draw, out var slot))
{
if (!draw.Enable)
continue;
if (draw.NextUpdateTime >= _gameTiming.CurTime)
continue;
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
if (!_magicSlot.TryGetEnergyCrystalFromSlot(uid, out var energyEnt, out var energyComp))
continue;
ChangeEnergy(energyEnt.Value, energyComp, draw.Energy, draw.Safe);
}
}
private void UpdateEnergyRadiusDraw()
{
var query = EntityQueryEnumerator<CP14AuraNodeComponent>();
while (query.MoveNext(out var uid, out var draw))
{
if (!draw.Enable)
continue;
if (draw.NextUpdateTime >= _gameTiming.CurTime)
continue;
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
var containers = _lookup.GetEntitiesInRange<CP14MagicEnergyContainerComponent>(Transform(uid).Coordinates, draw.Range);
foreach (var container in containers)
{
var distance = Vector2.Distance(_transform.GetWorldPosition(uid), _transform.GetWorldPosition(container));
var energyDraw = draw.Energy * (1 - distance / draw.Range);
ChangeEnergy(container, container.Comp, energyDraw, true);
}
}
}
}

View File

@@ -0,0 +1,60 @@
using System.Numerics;
using Content.Server._CP14.MagicEnergy.Components;
using Content.Shared._CP14.MagicEnergy;
using Content.Shared._CP14.MagicEnergy.Components;
using Content.Shared.Examine;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction.Events;
using Content.Shared.Inventory;
namespace Content.Server._CP14.MagicEnergy;
public partial class CP14MagicEnergySystem
{
private void InitializeScanner()
{
SubscribeLocalEvent<CP14MagicEnergyExaminableComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<CP14MagicEnergyScannerComponent, CP14MagicEnergyScanEvent>(OnMagicScanAttempt);
SubscribeLocalEvent<CP14MagicEnergyScannerComponent, InventoryRelayedEvent<CP14MagicEnergyScanEvent>>((e, c, ev) => OnMagicScanAttempt(e, c, ev.Args));
SubscribeLocalEvent<CP14AuraScannerComponent, UseInHandEvent>(OnAuraScannerUseInHand);
}
private void OnMagicScanAttempt(EntityUid uid, CP14MagicEnergyScannerComponent component, CP14MagicEnergyScanEvent args)
{
args.CanScan = true;
}
private void OnExamined(Entity<CP14MagicEnergyExaminableComponent> ent, ref ExaminedEvent args)
{
if (!TryComp<CP14MagicEnergyContainerComponent>(ent, out var magicContainer))
return;
var scanEvent = new CP14MagicEnergyScanEvent();
RaiseLocalEvent(args.Examiner, scanEvent);
if (!scanEvent.CanScan)
return;
args.PushMarkup(GetEnergyExaminedText(ent, magicContainer));
}
private void OnAuraScannerUseInHand(Entity<CP14AuraScannerComponent> scanner, ref UseInHandEvent args)
{
FixedPoint2 sumDraw = 0f;
var query = EntityQueryEnumerator<CP14AuraNodeComponent, TransformComponent>();
while (query.MoveNext(out var auraUid, out var node, out var xform))
{
if (xform.MapUid != Transform(scanner).MapUid)
continue;
var distance = Vector2.Distance(_transform.GetWorldPosition(auraUid), _transform.GetWorldPosition(scanner));
if (distance > node.Range)
continue;
sumDraw += node.Energy * (1 - distance / node.Range);
}
_popup.PopupCoordinates(Loc.GetString("cp14-magic-scanner", ("power", sumDraw)), Transform(scanner).Coordinates, args.User);
}
}

View File

@@ -1,152 +1,29 @@
using Content.Server._CP14.MagicEnergy.Components;
using Content.Server.Popups;
using Content.Shared._CP14.MagicEnergy;
using Content.Shared._CP14.MagicEnergy.Components;
using Content.Shared.Examine;
using Content.Shared.FixedPoint;
using Content.Shared.Inventory;
using Robust.Server.GameObjects;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server._CP14.MagicEnergy;
public sealed partial class CP14MagicEnergySystem : SharedCP14MagicEnergySystem
{
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly PointLightSystem _light = default!;
[Dependency] private readonly CP14MagicEnergyCrystalSlotSystem _magicSlot = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly PopupSystem _popup = default!;
public override void Initialize()
{
SubscribeLocalEvent<CP14MagicEnergyDrawComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<CP14MagicEnergyPointLightControllerComponent, CP14MagicEnergyLevelChangeEvent>(OnEnergyChange);
SubscribeLocalEvent<CP14MagicEnergyExaminableComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<CP14MagicEnergyScannerComponent, CP14MagicEnergyScanEvent>(OnMagicScanAttempt);
SubscribeLocalEvent<CP14MagicEnergyScannerComponent, InventoryRelayedEvent<CP14MagicEnergyScanEvent>>((e, c, ev) => OnMagicScanAttempt(e, c, ev.Args));
InitializeDraw();
InitializeScanner();
}
private void OnEnergyChange(Entity<CP14MagicEnergyPointLightControllerComponent> ent, ref CP14MagicEnergyLevelChangeEvent args)
{
if (!TryComp<PointLightComponent>(ent, out var light))
return;
var lightEnergy = MathHelper.Lerp(ent.Comp.MinEnergy, ent.Comp.MaxEnergy, (float)(args.NewValue / args.MaxValue));
_light.SetEnergy(ent, lightEnergy, light);
}
private void OnMapInit(Entity<CP14MagicEnergyDrawComponent> ent, ref MapInitEvent args)
{
ent.Comp.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(ent.Comp.Delay);
}
private void OnMagicScanAttempt(EntityUid uid, CP14MagicEnergyScannerComponent component, CP14MagicEnergyScanEvent args)
{
args.CanScan = true;
}
private void OnExamined(Entity<CP14MagicEnergyExaminableComponent> ent, ref ExaminedEvent args)
{
if (!TryComp<CP14MagicEnergyContainerComponent>(ent, out var magicContainer))
return;
var scanEvent = new CP14MagicEnergyScanEvent();
RaiseLocalEvent(args.Examiner, scanEvent);
if (!scanEvent.CanScan)
return;
args.PushMarkup(GetEnergyExaminedText(ent, magicContainer));
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<CP14MagicEnergyDrawComponent, CP14MagicEnergyContainerComponent>();
while (query.MoveNext(out var uid, out var draw, out var magicContainer))
{
if (draw.NextUpdateTime >= _gameTiming.CurTime)
continue;
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
ChangeEnergy(uid, magicContainer, draw.Energy, safe: draw.Safe);
}
var query2 = EntityQueryEnumerator<CP14MagicEnergyDrawComponent, CP14MagicEnergyCrystalSlotComponent>();
while (query2.MoveNext(out var uid, out var draw, out var slot))
{
if (!draw.Enable)
continue;
if (draw.NextUpdateTime >= _gameTiming.CurTime)
continue;
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
if (!_magicSlot.TryGetEnergyCrystalFromSlot(uid, out var energyEnt, out var energyComp))
continue;
ChangeEnergy(energyEnt.Value, energyComp, draw.Energy, draw.Safe);
}
}
public bool TryConsumeEnergy(EntityUid uid, FixedPoint2 energy, CP14MagicEnergyContainerComponent? component = null, bool safe = false)
{
if (!Resolve(uid, ref component))
return false;
if (energy <= 0)
return true;
// Attempting to absorb more energy than is contained in the carrier will still waste all the energy
if (component.Energy < energy)
{
ChangeEnergy(uid, component, -component.Energy);
return false;
}
ChangeEnergy(uid, component, -energy, safe);
return true;
}
public void ChangeEnergy(EntityUid uid, CP14MagicEnergyContainerComponent component, FixedPoint2 energy, bool safe = false)
{
if (!safe)
{
//Overload
if (component.Energy + energy > component.MaxEnergy)
{
RaiseLocalEvent(uid, new CP14MagicEnergyOverloadEvent()
{
OverloadEnergy = (component.Energy + energy) - component.MaxEnergy,
});
}
//Burn out
if (component.Energy + energy < 0)
{
RaiseLocalEvent(uid, new CP14MagicEnergyBurnOutEvent()
{
BurnOutEnergy = -energy - component.Energy
});
}
}
var oldEnergy = component.Energy;
var newEnergy = Math.Clamp((float)component.Energy + (float)energy, 0, (float)component.MaxEnergy);
component.Energy = newEnergy;
if (oldEnergy != newEnergy)
{
RaiseLocalEvent(uid, new CP14MagicEnergyLevelChangeEvent()
{
OldValue = component.Energy,
NewValue = newEnergy,
MaxValue = component.MaxEnergy,
});
}
UpdateDraw(frameTime);
}
}

View File

@@ -0,0 +1,50 @@
using Content.Shared.FixedPoint;
namespace Content.Server._CP14.MagicEnergy.Components;
[RegisterComponent, Access(typeof(CP14MagicEnergySystem))]
public sealed partial class CP14AuraNodeComponent : Component
{
[DataField]
public bool Enable = true;
[DataField]
public FixedPoint2 Energy = 1f;
[DataField]
public float Range = 10f;
/// <summary>
/// If not safe, restoring or drawing power across boundaries call dangerous events, that may destroy crystals
/// </summary>
[DataField]
public bool Safe = true;
/// <summary>
/// how often objects will try to change magic energy. In Seconds
/// </summary>
[DataField]
public float Delay = 5f;
/// <summary>
/// the time of the next magic energy change
/// </summary>
[DataField]
public TimeSpan NextUpdateTime { get; set; } = TimeSpan.Zero;
}
[RegisterComponent, Access(typeof(CP14MagicEnergySystem))]
public sealed partial class CP14RandomAuraNodeComponent : Component
{
[DataField]
public float MinDraw = -2f;
[DataField]
public float MaxDraw = 2f;
[DataField]
public float MinRange = 5f;
[DataField]
public float MaxRange = 10f;
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._CP14.MagicEnergy.Components;
[RegisterComponent, Access(typeof(CP14MagicEnergySystem))]
public sealed partial class CP14AuraScannerComponent : Component
{
}

View File

@@ -0,0 +1,40 @@
using Content.Server.Chat.Systems;
using Content.Shared._CP14.MagicSpell;
using Content.Shared._CP14.MagicSpell.Components;
using Content.Shared._CP14.MagicSpell.Events;
using Robust.Server.GameObjects;
namespace Content.Server._CP14.MagicSpell;
public sealed partial class CP14MagicSystem : CP14SharedMagicSystem
{
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly TransformSystem _transform = default!;
public override void Initialize()
{
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14VerbalAspectSpeechEvent>(OnSpellSpoken);
SubscribeLocalEvent<CP14MagicEffectCastingVisualComponent, CP14StartCastMagicEffectEvent>(OnSpawnMagicVisualEffect);
SubscribeLocalEvent<CP14MagicEffectCastingVisualComponent, CP14EndCastMagicEffectEvent>(OnDespawnMagicVisualEffect);
}
private void OnSpellSpoken(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14VerbalAspectSpeechEvent args)
{
if (args.Performer is not null && args.Speech is not null)
_chat.TrySendInGameICMessage(args.Performer.Value, args.Speech, InGameICChatType.Speak, true);
}
private void OnSpawnMagicVisualEffect(Entity<CP14MagicEffectCastingVisualComponent> ent, ref CP14StartCastMagicEffectEvent args)
{
var vfx = SpawnAttachedTo(ent.Comp.Proto, Transform(args.Performer).Coordinates);
_transform.SetParent(vfx, args.Performer);
ent.Comp.SpawnedEntity = vfx;
}
private void OnDespawnMagicVisualEffect(Entity<CP14MagicEffectCastingVisualComponent> ent, ref CP14EndCastMagicEffectEvent args)
{
QueueDel(ent.Comp.SpawnedEntity);
ent.Comp.SpawnedEntity = null;
}
}

View File

@@ -1,15 +0,0 @@
namespace Content.Server._CP14.MeleeWeapon;
/// <summary>
/// allows the object to become blunt with use
/// </summary>
[RegisterComponent, Access(typeof(CP14SharpeningSystem))]
public sealed partial class CP14SharpenedComponent : Component
{
[DataField]
public float Sharpness = 1f;
[DataField]
public float SharpnessDamageBy1Damage = 0.002f; //500 damage
}

View File

@@ -1,51 +0,0 @@
using Content.Shared.Damage;
using Robust.Shared.Audio;
namespace Content.Server._CP14.MeleeWeapon;
/// <summary>
/// component allows you to sharpen objects by restoring their damage.
/// </summary>
[RegisterComponent, Access(typeof(CP14SharpeningSystem))]
public sealed partial class CP14SharpeningStoneComponent : Component
{
/// <summary>
/// the amount of acuity recoverable per use
/// </summary>
[DataField]
public float SharpnessHeal = 0.05f;
/// <summary>
/// sound when used
/// </summary>
[DataField]
public SoundSpecifier SharpeningSound =
new SoundPathSpecifier("/Audio/_CP14/Items/sharpening_stone.ogg")
{
Params = AudioParams.Default.WithVariation(0.02f),
};
/// <summary>
/// the damage that the sharpening stone does to itself for use
/// </summary>
[DataField]
public DamageSpecifier SelfDamage = new()
{
DamageDict = new()
{
{ "Blunt", 1 }
}
};
/// <summary>
/// the damage the sharpening stone does to the target
/// </summary>
[DataField]
public DamageSpecifier TargetDamage = new()
{
DamageDict = new()
{
{ "Blunt", 1 }
}
};
}

View File

@@ -1,132 +0,0 @@
using System.Linq;
using Content.Shared.Damage;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Placeable;
using Content.Shared.Timing;
using Content.Shared.Weapons.Melee.Events;
using Content.Shared.Wieldable;
using Robust.Shared.Audio.Systems;
namespace Content.Server._CP14.MeleeWeapon;
public sealed class CP14SharpeningSystem : EntitySystem
{
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly UseDelaySystem _useDelay = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14SharpenedComponent, GetMeleeDamageEvent>(OnGetMeleeDamage, after: new[] { typeof(WieldableSystem) });
SubscribeLocalEvent<CP14SharpenedComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<CP14SharpenedComponent, MeleeHitEvent>(OnMeleeHit);
SubscribeLocalEvent<CP14SharpeningStoneComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<CP14SharpeningStoneComponent, ActivateInWorldEvent>(OnInteract);
}
private void OnMeleeHit(Entity<CP14SharpenedComponent> sharpened, ref MeleeHitEvent args)
{
if (!args.HitEntities.Any())
return;
sharpened.Comp.Sharpness = MathHelper.Clamp(sharpened.Comp.Sharpness - args.BaseDamage.GetTotal().Float() * sharpened.Comp.SharpnessDamageBy1Damage, 0.1f, 1f);
}
private void OnInteract(Entity<CP14SharpeningStoneComponent> stone, ref ActivateInWorldEvent args)
{
if (args.Handled)
return;
if (!TryComp<ItemPlacerComponent>(stone, out var itemPlacer))
return;
if (itemPlacer.PlacedEntities.Count <= 0)
return;
foreach (var item in itemPlacer.PlacedEntities)
{
if (!TryComp<CP14SharpenedComponent>(item, out var sharpened))
continue;
SharpThing(stone, item, sharpened, args.User);
return;
}
}
private void OnAfterInteract(Entity<CP14SharpeningStoneComponent> stone, ref AfterInteractEvent args)
{
if (!args.CanReach || args.Target == null || !TryComp<CP14SharpenedComponent>(args.Target, out var sharpened))
return;
if (TryComp<UseDelayComponent>(stone, out var useDelay) && _useDelay.IsDelayed( new Entity<UseDelayComponent>(stone, useDelay)))
return;
SharpThing(stone, args.Target.Value, sharpened, args.User);
}
private void SharpThing(Entity<CP14SharpeningStoneComponent> stone, EntityUid target, CP14SharpenedComponent component, EntityUid user)
{
var ev = new SharpingEvent()
{
User = user,
Target = target,
};
RaiseLocalEvent(stone, ev);
if (!ev.Canceled)
{
_audio.PlayPvs(stone.Comp.SharpeningSound, target);
Spawn("EffectSparks", Transform(target).Coordinates);
_damageableSystem.TryChangeDamage(stone, stone.Comp.SelfDamage);
_damageableSystem.TryChangeDamage(target, stone.Comp.TargetDamage);
component.Sharpness = MathHelper.Clamp01(component.Sharpness + stone.Comp.SharpnessHeal);
}
_useDelay.TryResetDelay(stone);
}
private void OnExamined(Entity<CP14SharpenedComponent> sharpened, ref ExaminedEvent args)
{
if (sharpened.Comp.Sharpness > 0.95f)
{
args.PushMarkup(Loc.GetString("sharpening-examined-95"));
return;
}
if (sharpened.Comp.Sharpness > 0.75f)
{
args.PushMarkup(Loc.GetString("sharpening-examined-75"));
return;
}
if (sharpened.Comp.Sharpness > 0.5f)
{
args.PushMarkup(Loc.GetString("sharpening-examined-50"));
return;
}
args.PushMarkup(Loc.GetString("sharpening-examined-25"));
}
private void OnGetMeleeDamage(Entity<CP14SharpenedComponent> sharpened, ref GetMeleeDamageEvent args)
{
args.Damage *= sharpened.Comp.Sharpness;
}
}
/// <summary>
/// Caused on a sharpening stone when someone tries to sharpen an object with it
/// </summary>
public sealed class SharpingEvent : EntityEventArgs
{
public bool Canceled = false;
public EntityUid User;
public EntityUid Target;
}

View File

@@ -0,0 +1,26 @@
using Content.Server._CP14.Objectives.Systems;
using Robust.Shared.Utility;
namespace Content.Server._CP14.Objectives.Components;
[RegisterComponent, Access(typeof(CP14CurrencyCollectConditionSystem))]
public sealed partial class CP14CurrencyCollectConditionComponent : Component
{
[DataField]
public int Currency = 1000;
/// <summary>
/// Limits the goal to collecting values from a specific category.
/// </summary>
[DataField]
public string? Category;
[DataField(required: true)]
public LocId ObjectiveText;
[DataField(required: true)]
public LocId ObjectiveDescription;
[DataField(required: true)]
public SpriteSpecifier ObjectiveSprite;
}

View File

@@ -0,0 +1,113 @@
using Content.Server._CP14.Objectives.Components;
using Content.Shared._CP14.Currency;
using Content.Shared.Mind;
using Content.Shared.Mind.Components;
using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Objectives.Components;
using Content.Shared.Objectives.Systems;
using Robust.Shared.Containers;
namespace Content.Server._CP14.Objectives.Systems;
public sealed class CP14CurrencyCollectConditionSystem : EntitySystem
{
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
[Dependency] private readonly CP14CurrencySystem _currency = default!;
private EntityQuery<ContainerManagerComponent> _containerQuery;
public override void Initialize()
{
base.Initialize();
_containerQuery = GetEntityQuery<ContainerManagerComponent>();
SubscribeLocalEvent<CP14CurrencyCollectConditionComponent, ObjectiveAssignedEvent>(OnAssigned);
SubscribeLocalEvent<CP14CurrencyCollectConditionComponent, ObjectiveAfterAssignEvent>(OnAfterAssign);
SubscribeLocalEvent<CP14CurrencyCollectConditionComponent, ObjectiveGetProgressEvent>(OnGetProgress);
}
private void OnAssigned(Entity<CP14CurrencyCollectConditionComponent> condition, ref ObjectiveAssignedEvent args)
{
}
private void OnAfterAssign(Entity<CP14CurrencyCollectConditionComponent> condition, ref ObjectiveAfterAssignEvent args)
{
_metaData.SetEntityName(condition.Owner, Loc.GetString(condition.Comp.ObjectiveText), args.Meta);
_metaData.SetEntityDescription(condition.Owner, Loc.GetString(condition.Comp.ObjectiveDescription, ("coins", _currency.GetPrettyCurrency(condition.Comp.Currency))), args.Meta);
_objectives.SetIcon(condition.Owner, condition.Comp.ObjectiveSprite);
}
private void OnGetProgress(Entity<CP14CurrencyCollectConditionComponent> condition, ref ObjectiveGetProgressEvent args)
{
args.Progress = GetProgress(args.Mind, condition);
}
private float GetProgress(MindComponent mind, CP14CurrencyCollectConditionComponent condition)
{
if (!_containerQuery.TryGetComponent(mind.OwnedEntity, out var currentManager))
return 0;
var containerStack = new Stack<ContainerManagerComponent>();
var count = 0;
//check pulling object
if (TryComp<PullerComponent>(mind.OwnedEntity, out var pull)) //TO DO: to make the code prettier? don't like the repetition
{
var pulledEntity = pull.Pulling;
if (pulledEntity != null)
{
CheckEntity(pulledEntity.Value, condition, ref containerStack, ref count);
}
}
// recursively check each container for the item
// checks inventory, bag, implants, etc.
do
{
foreach (var container in currentManager.Containers.Values)
{
foreach (var entity in container.ContainedEntities)
{
// check if this is the item
count += CheckCurrency(entity, condition);
// if it is a container check its contents
if (_containerQuery.TryGetComponent(entity, out var containerManager))
containerStack.Push(containerManager);
}
}
} while (containerStack.TryPop(out currentManager));
var result = count / (float) condition.Currency;
result = Math.Clamp(result, 0, 1);
return result;
}
private void CheckEntity(EntityUid entity, CP14CurrencyCollectConditionComponent condition, ref Stack<ContainerManagerComponent> containerStack, ref int counter)
{
// check if this is the item
counter += CheckCurrency(entity, condition);
//we don't check the inventories of sentient entity
if (!TryComp<MindContainerComponent>(entity, out _))
{
// if it is a container check its contents
if (_containerQuery.TryGetComponent(entity, out var containerManager))
containerStack.Push(containerManager);
}
}
private int CheckCurrency(EntityUid entity, CP14CurrencyCollectConditionComponent condition)
{
// check if this is the target
if (!TryComp<CP14CurrencyComponent>(entity, out var target))
return 0;
if (target.Category != condition.Category)
return 0;
return _currency.GetTotalCurrency(entity);
}
}

View File

@@ -0,0 +1,10 @@
using Robust.Shared.Audio;
namespace Content.Server._CP14.PersonalSignature;
[RegisterComponent]
public sealed partial class CP14PersonalSignatureComponent : Component
{
[DataField]
public SoundSpecifier? SignSound;
}

View File

@@ -0,0 +1,79 @@
using System.Diagnostics.CodeAnalysis;
using Content.Server.Mind;
using Content.Server.Paper;
using Content.Shared.Hands.Components;
using Content.Shared.Paper;
using Content.Shared.Verbs;
using Robust.Server.Audio;
using Robust.Shared.Audio;
using Robust.Shared.Player;
namespace Content.Server._CP14.PersonalSignature;
public sealed class CP14PersonalSignatureSystem : EntitySystem
{
[Dependency] private readonly AudioSystem _audio = default!;
[Dependency] private readonly MindSystem _mind = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PaperComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerb);
}
private void OnGetVerb(Entity<PaperComponent> entity, ref GetVerbsEvent<AlternativeVerb> args)
{
if (!_mind.TryGetMind(args.User, out _, out var mind))
return;
if (mind.CharacterName is null)
return;
if (!CanSign(args.Using, out var signature))
return;
if (HasSign(entity, mind.CharacterName))
return;
args.Verbs.Add(new AlternativeVerb
{
Text = Loc.GetString("cp-sign-verb"),
Act = () =>
{
Sign(entity, mind.CharacterName, signature.SignSound);
},
});
}
private bool CanSign(EntityUid? item, [NotNullWhen(true)] out CP14PersonalSignatureComponent? personalSignature)
{
personalSignature = null;
return item is not null && TryComp(item, out personalSignature);
}
private bool HasSign(Entity<PaperComponent> entity, string sign)
{
foreach (var info in entity.Comp.StampedBy)
{
if (info.StampedName == sign)
return true;
}
return false;
}
private void Sign(Entity<PaperComponent> target, string name, SoundSpecifier? sound)
{
var info = new StampDisplayInfo
{
StampedName = name,
StampedColor = Color.Gray,
};
if (sound is not null)
_audio.PlayEntity(sound, Filter.Pvs(target), target, true);
target.Comp.StampedBy.Add(info);
}
}

View File

@@ -0,0 +1,21 @@
/*
* All right reserved to CrystallPunk.
*
* BUT this file is sublicensed under MIT License
*
*/
namespace Content.Server._CP14.RoundSeed;
/// <summary>
/// This is used for round seed
/// </summary>
[RegisterComponent, Access(typeof(CP14RoundSeedSystem))]
public sealed partial class CP14RoundSeedComponent : Component
{
[ViewVariables]
public static int MaxValue = 10000;
[ViewVariables]
public int Seed;
}

View File

@@ -0,0 +1,53 @@
/*
* All right reserved to CrystallPunk.
*
* BUT this file is sublicensed under MIT License
*
*/
using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
using Robust.Shared.Map;
using Robust.Shared.Random;
namespace Content.Server._CP14.RoundSeed;
/// <summary>
/// Provides a round seed for another systems
/// </summary>
public sealed class CP14RoundSeedSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
SubscribeLocalEvent<CP14RoundSeedComponent, ComponentStartup>(OnComponentStartup);
}
private void OnComponentStartup(Entity<CP14RoundSeedComponent> ent, ref ComponentStartup args)
{
ent.Comp.Seed = _random.Next(CP14RoundSeedComponent.MaxValue);
}
private int SetupSeed()
{
return AddComp<CP14RoundSeedComponent>(Spawn(null, MapCoordinates.Nullspace)).Seed;
}
/// <summary>
/// Returns the round seed if assigned, otherwise assigns the round seed itself.
/// </summary>
/// <returns>seed of the round</returns>
public int GetSeed()
{
var query = EntityQuery<CP14RoundSeedComponent>();
foreach (var comp in query)
{
return comp.Seed;
}
var seed = SetupSeed();
Log.Warning($"Missing RoundSeed. Seed set to {seed}");
return seed;
}
}

View File

@@ -29,21 +29,31 @@ public sealed class CP14ExpeditionSystem : EntitySystem
/// </summary>
public float ArrivalTime { get; private set; }
/// <summary>
/// If enabled then spawns players on an expedition ship.
/// </summary>
public bool Enabled { get; private set; }
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CP14StationExpeditionTargetComponent, StationPostInitEvent>(OnPostInitSetupExpeditionShip);
SubscribeLocalEvent<CP14StationExpeditionTargetComponent, FTLCompletedEvent>(OnArrivalsDocked);
SubscribeLocalEvent<CP14StationExpeditionTargetComponent, FTLCompletedEvent>(OnExpeditionShipLanded);
ArrivalTime = _cfgManager.GetCVar(CCVars.CP14ExpeditionArrivalTime);
_cfgManager.OnValueChanged(CCVars.CP14ExpeditionArrivalTime, time => ArrivalTime = time, true);
}
Enabled = _cfgManager.GetCVar(CCVars.CP14ExpeditionShip);
_cfgManager.OnValueChanged(CCVars.CP14ExpeditionArrivalTime, time => ArrivalTime = time, true);
_cfgManager.OnValueChanged(CCVars.CP14ExpeditionShip, value => Enabled = value, true);
}
private void OnPostInitSetupExpeditionShip(Entity<CP14StationExpeditionTargetComponent> station, ref StationPostInitEvent args)
{
if (!Enabled)
return;
if (!Deleted(station.Comp.Shuttle))
return;
@@ -76,7 +86,7 @@ public sealed class CP14ExpeditionSystem : EntitySystem
}
}
private void OnArrivalsDocked(Entity<CP14StationExpeditionTargetComponent> ent, ref FTLCompletedEvent args)
private void OnExpeditionShipLanded(Entity<CP14StationExpeditionTargetComponent> ent, ref FTLCompletedEvent args)
{
//Some announsement logic?
}
@@ -97,6 +107,9 @@ public sealed class CP14ExpeditionSystem : EntitySystem
public void HandlePlayerSpawning(PlayerSpawningEvent ev)
{
if (!Enabled)
return;
if (ev.SpawnResult != null)
return;
@@ -114,8 +127,10 @@ public sealed class CP14ExpeditionSystem : EntitySystem
var possiblePositions = new List<EntityCoordinates>();
while (points.MoveNext(out var uid, out var spawnPoint, out var xform))
{
if (ev.Job != null && spawnPoint.Job != ev.Job.Prototype)
continue;
if (spawnPoint.SpawnType != SpawnPointType.LateJoin || xform.GridUid != gridUid)
if (xform.GridUid != gridUid)
continue;
possiblePositions.Add(xform.Coordinates);

View File

@@ -1,15 +1,12 @@
using System.Numerics;
using Content.Server._CP14.Alchemy;
using Content.Server._CP14.MeleeWeapon;
using Content.Server.Popups;
using Content.Shared._CP14.MeleeWeapon.EntitySystems;
using Content.Shared._CP14.Skills;
using Content.Shared._CP14.Skills.Components;
using Content.Shared.Chemistry.Components;
using Content.Shared.Damage;
using Content.Shared.Examine;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Popups;
using Content.Shared.Stunnable;
using Content.Shared.Throwing;
using Content.Shared.Weapons.Melee;
using Content.Shared.Weapons.Melee.Events;

View File

@@ -3,7 +3,7 @@ using Robust.Shared.Utility;
namespace Content.Server._CP14.StationDungeonMap;
/// <summary>
/// Initializes a procedurally generated world with points of interest
/// Loads additional maps from the list at the start of the round.
/// </summary>
[RegisterComponent, Access(typeof(CP14StationAdditionalMapSystem))]
public sealed partial class CP14StationAdditionalMapComponent : Component

View File

@@ -9,5 +9,5 @@ namespace Content.Server._CP14.Temperature;
public sealed partial class CP14FlammableEntityHeaterComponent : Component
{
[DataField]
public float EnergyPerFireStack = 300f;
public float DegreesPerStack = 300f;
}

View File

@@ -3,7 +3,7 @@ namespace Content.Server._CP14.Temperature;
/// <summary>
/// allows you to heat the temperature of solutions depending on the number of stacks of fire
/// </summary>
[RegisterComponent, Access(typeof(CP14SolutionTemperatureSystem))]
[RegisterComponent, Access(typeof(CP14TemperatureSystem))]
public sealed partial class CP14FlammableSolutionHeaterComponent : Component
{
[DataField]

View File

@@ -3,7 +3,7 @@ namespace Content.Server._CP14.Temperature;
/// <summary>
/// passively returns the solution temperature to the standard
/// </summary>
[RegisterComponent, Access(typeof(CP14SolutionTemperatureSystem))]
[RegisterComponent, Access(typeof(CP14TemperatureSystem))]
public sealed partial class CP14SolutionTemperatureComponent : Component
{
[DataField]

View File

@@ -1,34 +1,60 @@
using Content.Server.Atmos.Components;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Temperature.Components;
using Content.Server.Temperature.Systems;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.FixedPoint;
using Content.Shared.Placeable;
using Robust.Shared.Timing;
namespace Content.Server._CP14.Temperature;
public sealed partial class CP14SolutionTemperatureSystem : EntitySystem
public sealed partial class CP14TemperatureSystem : EntitySystem
{
[Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly TemperatureSystem _temperature = default!;
private TimeSpan _updateTick = TimeSpan.FromSeconds(1f);
private readonly TimeSpan _updateTick = TimeSpan.FromSeconds(1f);
private TimeSpan _timeToNextUpdate = TimeSpan.Zero;
public override void Update(float frameTime)
{
base.Update(frameTime);
FlammableEntityHeating(frameTime);
if (_timing.CurTime <= _timeToNextUpdate)
return;
_timeToNextUpdate = _timing.CurTime + _updateTick;
FlammableHeating();
NormalizeTemperature();
FlammableSolutionHeating();
NormalizeSolutionTemperature();
}
private void NormalizeTemperature()
private float GetTargetTemperature(FlammableComponent flammable, CP14FlammableSolutionHeaterComponent heater)
{
return flammable.FireStacks * heater.DegreesPerStack;
}
private void FlammableEntityHeating(float frameTime)
{
var flammableQuery = EntityQueryEnumerator<CP14FlammableEntityHeaterComponent, ItemPlacerComponent, FlammableComponent>();
while (flammableQuery.MoveNext(out var uid, out var heater, out var placer, out var flammable))
{
if (!flammable.OnFire)
return;
var energy = flammable.FireStacks * frameTime * heater.DegreesPerStack;
foreach (var ent in placer.PlacedEntities)
{
_temperature.ChangeHeat(ent, energy);
}
}
}
private void NormalizeSolutionTemperature()
{
var query = EntityQueryEnumerator<CP14SolutionTemperatureComponent, SolutionContainerManagerComponent>();
while (query.MoveNext(out var uid, out var temp, out var container))
@@ -40,7 +66,8 @@ public sealed partial class CP14SolutionTemperatureSystem : EntitySystem
}
}
}
private void FlammableHeating()
private void FlammableSolutionHeating()
{
var query =
EntityQueryEnumerator<CP14FlammableSolutionHeaterComponent, ItemPlacerComponent, FlammableComponent>();
@@ -54,10 +81,9 @@ public sealed partial class CP14SolutionTemperatureSystem : EntitySystem
if (!TryComp<SolutionContainerManagerComponent>(heatingEntity, out var container))
continue;
var targetT = flammable.FireStacks * heater.DegreesPerStack;
foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((heatingEntity, container)))
{
if (TryAffectTemp(soln.Comp.Solution.Temperature, targetT, soln.Comp.Solution.Volume, out var newT))
if (TryAffectTemp(soln.Comp.Solution.Temperature, GetTargetTemperature(flammable, heater), soln.Comp.Solution.Volume, out var newT))
_solutionContainer.SetTemperature(soln, newT);
}
}
@@ -71,7 +97,7 @@ public sealed partial class CP14SolutionTemperatureSystem : EntitySystem
if (mass == 0)
return false;
newT = (float) (oldT + ((targetT - oldT) / mass) * power);
newT = (float) (oldT + (targetT - oldT) / mass * power);
return true;
}
}

View File

@@ -0,0 +1,19 @@
using Content.Shared._CP14.Workbench.Prototypes;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.Workbench;
[RegisterComponent]
[Access(typeof(CP14WorkbenchSystem))]
public sealed partial class CP14WorkbenchComponent : Component
{
[DataField]
public float CraftSpeed = 1f;
[DataField]
public List<ProtoId<CP14WorkbenchRecipePrototype>> Recipes = new();
[DataField]
public SoundSpecifier CraftSound = new SoundCollectionSpecifier("CP14Hammering");
}

View File

@@ -0,0 +1,229 @@
using Content.Server.Popups;
using Content.Shared._CP14.Workbench;
using Content.Shared._CP14.Workbench.Prototypes;
using Content.Shared.DoAfter;
using Content.Shared.Stacks;
using Content.Shared.Verbs;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.Workbench;
public sealed class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
{
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedStackSystem _stack = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
private EntityQuery<MetaDataComponent> _metaQuery;
private EntityQuery<StackComponent> _stackQuery;
private const float WorkbenchRadius = 0.5f;
public override void Initialize()
{
base.Initialize();
_metaQuery = GetEntityQuery<MetaDataComponent>();
_stackQuery = GetEntityQuery<StackComponent>();
SubscribeLocalEvent<CP14WorkbenchComponent, GetVerbsEvent<InteractionVerb>>(OnInteractionVerb);
SubscribeLocalEvent<CP14WorkbenchComponent, CP14CraftDoAfterEvent>(OnCraftFinished);
}
private void OnInteractionVerb(Entity<CP14WorkbenchComponent> ent, ref GetVerbsEvent<InteractionVerb> args)
{
if (!args.CanAccess || !args.CanInteract || args.Hands is null)
return;
var placedEntities = _lookup.GetEntitiesInRange(Transform(ent).Coordinates, WorkbenchRadius);
var user = args.User;
foreach (var craftProto in ent.Comp.Recipes)
{
if (!_proto.TryIndex(craftProto, out var craft))
continue;
if (!_proto.TryIndex(craft.Result, out var result))
continue;
args.Verbs.Add(new()
{
Act = () =>
{
StartCraft(ent, user, craft);
},
Text = result.Name,
Message = GetCraftRecipeMessage(result.Description, craft),
Category = VerbCategory.CP14Craft,
Disabled = !CanCraftRecipe(craft, placedEntities),
});
}
}
private void OnCraftFinished(Entity<CP14WorkbenchComponent> ent, ref CP14CraftDoAfterEvent args)
{
if (args.Cancelled || args.Handled)
return;
if (!_proto.TryIndex(args.Recipe, out var recipe))
return;
var placedEntities = _lookup.GetEntitiesInRange(Transform(ent).Coordinates, WorkbenchRadius);
if (!CanCraftRecipe(recipe, placedEntities))
{
_popup.PopupEntity(Loc.GetString("cp14-workbench-no-resource"), ent, args.User);
return;
}
foreach (var requiredIngredient in recipe.Entities)
{
var requiredCount = requiredIngredient.Value;
foreach (var placedEntity in placedEntities)
{
var placedProto = MetaData(placedEntity).EntityPrototype?.ID;
if (placedProto != null && placedProto == requiredIngredient.Key && requiredCount > 0)
{
requiredCount--;
QueueDel(placedEntity);
}
}
}
foreach (var requiredStack in recipe.Stacks)
{
var requiredCount = requiredStack.Value;
foreach (var placedEntity in placedEntities)
{
if (!_stackQuery.TryGetComponent(placedEntity, out var stack))
continue;
if (stack.StackTypeId != requiredStack.Key)
continue;
var count = (int)MathF.Min(requiredCount, stack.Count);
_stack.SetCount(placedEntity, stack.Count - count, stack);
requiredCount -= count;
}
}
Spawn(_proto.Index(args.Recipe).Result, Transform(ent).Coordinates);
args.Handled = true;
}
private void StartCraft(Entity<CP14WorkbenchComponent> workbench, EntityUid user, CP14WorkbenchRecipePrototype recipe)
{
var craftDoAfter = new CP14CraftDoAfterEvent
{
Recipe = recipe.ID,
};
var doAfterArgs = new DoAfterArgs(EntityManager,
user,
recipe.CraftTime * workbench.Comp.CraftSpeed,
craftDoAfter,
workbench,
workbench)
{
BreakOnMove = true,
BreakOnDamage = true,
NeedHand = true,
};
_doAfter.TryStartDoAfter(doAfterArgs);
_audio.PlayPvs(recipe.OverrideCraftSound ?? workbench.Comp.CraftSound, workbench);
}
private List<CP14WorkbenchRecipePrototype> GetPossibleCrafts(Entity<CP14WorkbenchComponent> workbench, HashSet<EntityUid> ingrediEnts)
{
List<CP14WorkbenchRecipePrototype> result = new();
if (ingrediEnts.Count == 0)
return result;
foreach (var recipeProto in workbench.Comp.Recipes)
{
var recipe = _proto.Index(recipeProto);
if (CanCraftRecipe(recipe, ingrediEnts))
{
result.Add(recipe);
}
}
return result;
}
private bool CanCraftRecipe(CP14WorkbenchRecipePrototype recipe, HashSet<EntityUid> entities)
{
var indexedIngredients = IndexIngredients(entities);
foreach (var requiredIngredient in recipe.Entities)
{
if (!indexedIngredients.TryGetValue(requiredIngredient.Key, out var availableQuantity) ||
availableQuantity < requiredIngredient.Value)
return false;
}
foreach (var (key, value) in recipe.Stacks)
{
var count = 0;
foreach (var ent in entities)
{
if (_stackQuery.TryGetComponent(ent, out var stack))
{
if (stack.StackTypeId != key)
continue;
count += stack.Count;
}
}
if (count < value)
return false;
}
return true;
}
private string GetCraftRecipeMessage(string desc, CP14WorkbenchRecipePrototype recipe)
{
var result = desc + "\n \n" + Loc.GetString("cp14-workbench-recipe-list")+ "\n";
foreach (var pair in recipe.Entities)
{
var proto = _proto.Index(pair.Key);
result += $"{proto.Name} x{pair.Value}\n";
}
foreach (var pair in recipe.Stacks)
{
var proto = _proto.Index(pair.Key);
result += $"{proto.Name} x{pair.Value}\n";
}
return result;
}
private Dictionary<EntProtoId, int> IndexIngredients(HashSet<EntityUid> ingredients)
{
var indexedIngredients = new Dictionary<EntProtoId, int>();
foreach (var ingredient in ingredients)
{
var protoId = _metaQuery.GetComponent(ingredient).EntityPrototype?.ID;
if (protoId == null)
continue;
if (indexedIngredients.ContainsKey(protoId))
indexedIngredients[protoId]++;
else
indexedIngredients[protoId] = 1;
}
return indexedIngredients;
}
}