Merge branch 'master' into ed-17-07-2024-dungenagain
This commit is contained in:
@@ -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)));
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Content.Server.Entry
|
||||
public static class IgnoredComponents
|
||||
{
|
||||
public static string[] List => new[] {
|
||||
"CP14WaveShader", //CP14 Wave shader
|
||||
"ConstructionGhost",
|
||||
"IconSmooth",
|
||||
"InteractionOutline",
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Content.Server.Eye.Blinding
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed partial class ActivatableUIRequiresVisionComponent : Component
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 = [];
|
||||
}
|
||||
}
|
||||
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
11
Content.Server/NPC/Queries/Queries/RemoveAnchored.cs
Normal file
11
Content.Server/NPC/Queries/Queries/RemoveAnchored.cs
Normal 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
|
||||
{
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -211,6 +211,7 @@ public sealed class DrinkSystem : SharedDrinkSystem
|
||||
target: target,
|
||||
used: item)
|
||||
{
|
||||
BreakOnHandChange = false,
|
||||
BreakOnMove = forceDrink,
|
||||
BreakOnDamage = true,
|
||||
MovementThreshold = 0.01f,
|
||||
|
||||
@@ -198,6 +198,7 @@ public sealed class FoodSystem : EntitySystem
|
||||
target: target,
|
||||
used: food)
|
||||
{
|
||||
BreakOnHandChange = false,
|
||||
BreakOnMove = forceFeed,
|
||||
BreakOnDamage = true,
|
||||
MovementThreshold = 0.01f,
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Content.Server._CP14.MagicEnergy.Components;
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14MagicEnergySystem))]
|
||||
public sealed partial class CP14AuraScannerComponent : Component
|
||||
{
|
||||
}
|
||||
40
Content.Server/_CP14/MagicSpell/CP14MagicSystem.cs
Normal file
40
Content.Server/_CP14/MagicSpell/CP14MagicSystem.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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 }
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server._CP14.PersonalSignature;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14PersonalSignatureComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public SoundSpecifier? SignSound;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
21
Content.Server/_CP14/RoundSeed/CP14RoundSeedComponent.cs
Normal file
21
Content.Server/_CP14/RoundSeed/CP14RoundSeedComponent.cs
Normal 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;
|
||||
}
|
||||
53
Content.Server/_CP14/RoundSeed/CP14RoundSeedSystem.cs
Normal file
53
Content.Server/_CP14/RoundSeed/CP14RoundSeedSystem.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -9,5 +9,5 @@ namespace Content.Server._CP14.Temperature;
|
||||
public sealed partial class CP14FlammableEntityHeaterComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float EnergyPerFireStack = 300f;
|
||||
public float DegreesPerStack = 300f;
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
19
Content.Server/_CP14/Workbench/CP14WorkbenchComponent.cs
Normal file
19
Content.Server/_CP14/Workbench/CP14WorkbenchComponent.cs
Normal 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");
|
||||
}
|
||||
229
Content.Server/_CP14/Workbench/CP14WorkbenchSystem.cs
Normal file
229
Content.Server/_CP14/Workbench/CP14WorkbenchSystem.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user