diff --git a/Content.Server/_CP14/Alchemy/CP14SolutionNormalizerSystem.cs b/Content.Server/_CP14/Alchemy/CP14SolutionNormalizerSystem.cs index b8c4305a2c..addc709d05 100644 --- a/Content.Server/_CP14/Alchemy/CP14SolutionNormalizerSystem.cs +++ b/Content.Server/_CP14/Alchemy/CP14SolutionNormalizerSystem.cs @@ -1,3 +1,7 @@ +using Content.Server._CP14.MagicEnergy; +using Content.Server.Audio; +using Content.Shared._CP14.MagicEnergy.Components; +using Content.Shared.Audio; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; @@ -12,18 +16,35 @@ public sealed partial class CP14SolutionNormalizerSystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!; + [Dependency] private readonly CP14MagicEnergyCrystalSlotSystem _magicSlot = default!; + [Dependency] private readonly AmbientSoundSystem _ambient = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnSlotPowerChanged); + } + + private void OnSlotPowerChanged(Entity ent, ref CP14SlotCrystalPowerChangedEvent args) + { + if (TryComp(ent, out var ambient)) + { + _ambient.SetAmbience(ent, args.Powered); + } + } public override void Update(float frameTime) { base.Update(frameTime); var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var normalizer, out var containerManager)) { if (_timing.CurTime <= normalizer.NextUpdateTime) continue; + if (!_magicSlot.HasEnergy(uid, 1)) + continue; + normalizer.NextUpdateTime = _timing.CurTime + normalizer.UpdateFrequency; var solutionManager = new Entity(uid, containerManager); diff --git a/Content.Server/_CP14/MagicEnergy/CP14MagicEnergyCrystalSlotSystem.cs b/Content.Server/_CP14/MagicEnergy/CP14MagicEnergyCrystalSlotSystem.cs new file mode 100644 index 0000000000..3de913beab --- /dev/null +++ b/Content.Server/_CP14/MagicEnergy/CP14MagicEnergyCrystalSlotSystem.cs @@ -0,0 +1,150 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Shared._CP14.MagicEnergy; +using Content.Shared._CP14.MagicEnergy.Components; +using Content.Shared.Containers.ItemSlots; +using Content.Shared.Examine; +using Content.Shared.FixedPoint; +using Content.Shared.Popups; +using Robust.Shared.Containers; + +namespace Content.Server._CP14.MagicEnergy; + +public sealed partial class CP14MagicEnergyCrystalSlotSystem : SharedCP14MagicEnergyCrystalSlotSystem +{ + + [Dependency] private readonly ItemSlotsSystem _itemSlots = default!; + [Dependency] private readonly CP14MagicEnergySystem _magicEnergy = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnEnergyChanged); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnCrystalChanged); + } + + private void OnCrystalChanged(Entity ent, ref CP14SlotCrystalChangedEvent args) + { + var realPowered = TryGetEnergyCrystalFromSlot(ent, out var energyEnt, out var energyComp); + + if (energyComp != null) + realPowered = energyComp.Energy > 0; + + if (ent.Comp.Powered != realPowered) + { + ent.Comp.Powered = realPowered; + _appearance.SetData(ent, CP14MagicSlotVisuals.Powered, realPowered); + RaiseLocalEvent(ent, new CP14SlotCrystalPowerChangedEvent(realPowered)); + } + } + + private void OnEnergyChanged(Entity crystal, ref CP14MagicEnergyLevelChangeEvent args) + { + if (_container.TryGetContainingContainer(crystal, out var container) + && TryComp(container.Owner, out CP14MagicEnergyCrystalSlotComponent? slot) + && _itemSlots.TryGetSlot(container.Owner, slot.SlotId, out var itemSlot)) + { + if (itemSlot.Item == crystal) + { + RaiseLocalEvent(container.Owner, new CP14SlotCrystalChangedEvent(false)); + } + } + } + + private void OnExamined(Entity ent, ref ExaminedEvent args) + { + if (!TryGetEnergyCrystalFromSlot(ent, out var crystalUid, out var crystalComp, ent.Comp)) + return; + + var scanEvent = new CP14MagicEnergyScanEvent(); + RaiseLocalEvent(args.Examiner, scanEvent); + + if (!scanEvent.CanScan) + return; + + args.PushMarkup(_magicEnergy.GetEnergyExaminedText(crystalUid.Value, crystalComp)); + } + + public bool TryGetEnergyCrystalFromSlot(EntityUid uid, + [NotNullWhen(true)] out CP14MagicEnergyContainerComponent? energyComp, + CP14MagicEnergyCrystalSlotComponent? component = null) + { + return TryGetEnergyCrystalFromSlot(uid, out _, out energyComp, component); + } + + public bool TryGetEnergyCrystalFromSlot(EntityUid uid, + [NotNullWhen(true)] out EntityUid? energyEnt, + [NotNullWhen(true)] out CP14MagicEnergyContainerComponent? energyComp, + CP14MagicEnergyCrystalSlotComponent? component = null) + { + if (!Resolve(uid, ref component, false)) + { + energyEnt = null; + energyComp = null; + return false; + } + + if (_itemSlots.TryGetSlot(uid, component.SlotId, out ItemSlot? slot)) + { + energyEnt = slot.Item; + return TryComp(slot.Item, out energyComp); + } + + energyEnt = null; + energyComp = null; + return false; + } + + public bool HasEnergy(EntityUid uid, + FixedPoint2 energy, + CP14MagicEnergyCrystalSlotComponent? component = null, + EntityUid? user = null) + { + if (!TryGetEnergyCrystalFromSlot(uid, out var energyEnt, out var energyComp, component)) + { + if (user != null) + _popup.PopupEntity(Loc.GetString("cp14-magic-energy-no-crystal"), uid,user.Value); + + return false; + } + + if (energyComp.Energy < energy) + { + if (user != null) + _popup.PopupEntity(Loc.GetString("cp14-magic-energy-insufficient"), uid, user.Value); + + return false; + } + + return true; + } + public bool TryUseEnergy(EntityUid uid, + FixedPoint2 energy, + CP14MagicEnergyCrystalSlotComponent? component = null, + EntityUid? user = null, + bool safe = false) + { + if (!TryGetEnergyCrystalFromSlot(uid, out var energyEnt, out var energyComp, component)) + { + if (user != null) + _popup.PopupEntity(Loc.GetString("cp14-magic-energy-no-crystal"), uid,user.Value); + + return false; + } + + if (_magicEnergy.TryConsumeEnergy(energyEnt.Value, energy, energyComp, safe)) + { + if (user != null) + _popup.PopupEntity( + Loc.GetString(safe ? "cp14-magic-energy-insufficient" : "cp14-magic-energy-insufficient-unsafe"), + uid, + user.Value); + + return false; + } + + return true; + } +} diff --git a/Content.Server/_CP14/MagicEnergy/CP14MagicEnergySystem.cs b/Content.Server/_CP14/MagicEnergy/CP14MagicEnergySystem.cs new file mode 100644 index 0000000000..0ec735fe69 --- /dev/null +++ b/Content.Server/_CP14/MagicEnergy/CP14MagicEnergySystem.cs @@ -0,0 +1,152 @@ +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.Inventory; +using Robust.Server.GameObjects; +using Robust.Shared.Timing; + +namespace Content.Server._CP14.MagicEnergy; + +public sealed partial class CP14MagicEnergySystem : SharedCP14MagicEnergySystem +{ + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly PointLightSystem _light = default!; + [Dependency] private readonly CP14MagicEnergyCrystalSlotSystem _magicSlot = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnEnergyChange); + + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnMagicScanAttempt); + SubscribeLocalEvent>((e, c, ev) => OnMagicScanAttempt(e, c, ev.Args)); + } + + private void OnEnergyChange(Entity ent, ref CP14MagicEnergyLevelChangeEvent args) + { + if (!TryComp(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 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 ent, ref ExaminedEvent args) + { + if (!TryComp(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(); + 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(); + 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, + }); + } + } +} diff --git a/Content.Server/_CP14/MagicEnergy/Components/CP14MagicEnergyDrawComponent.cs b/Content.Server/_CP14/MagicEnergy/Components/CP14MagicEnergyDrawComponent.cs new file mode 100644 index 0000000000..141579bc6b --- /dev/null +++ b/Content.Server/_CP14/MagicEnergy/Components/CP14MagicEnergyDrawComponent.cs @@ -0,0 +1,34 @@ +using Content.Shared.FixedPoint; + +namespace Content.Server._CP14.MagicEnergy.Components; + +/// +/// Allows you to restore or deplete the magical energy in the item +/// +[RegisterComponent, Access(typeof(CP14MagicEnergySystem))] +public sealed partial class CP14MagicEnergyDrawComponent : Component +{ + [DataField] + public bool Enable = true; + + [DataField] + public FixedPoint2 Energy = 1f; + + /// + /// If not safe, restoring or drawing power across boundaries call dangerous events, that may destroy crystals + /// + [DataField] + public bool Safe = true; + + /// + /// how often objects will try to change magic energy. In Seconds + /// + [DataField] + public float Delay = 5f; + + /// + /// the time of the next magic energy change + /// + [DataField] + public TimeSpan NextUpdateTime { get; set; } = TimeSpan.Zero; +} diff --git a/Content.Shared/Inventory/InventorySystem.Relay.cs b/Content.Shared/Inventory/InventorySystem.Relay.cs index 6bd65622f1..0495d31af8 100644 --- a/Content.Shared/Inventory/InventorySystem.Relay.cs +++ b/Content.Shared/Inventory/InventorySystem.Relay.cs @@ -1,3 +1,4 @@ +using Content.Shared._CP14.MagicEnergy; using Content.Shared.Chemistry; using Content.Shared.Damage; using Content.Shared.Electrocution; @@ -36,6 +37,7 @@ public partial class InventorySystem SubscribeLocalEvent(RelayInventoryEvent); SubscribeLocalEvent(RelayInventoryEvent); SubscribeLocalEvent(RelayInventoryEvent); + SubscribeLocalEvent(RelayInventoryEvent); //CP14 Magic scanning // ComponentActivatedClientSystems SubscribeLocalEvent>(RelayInventoryEvent); diff --git a/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyContainerComponent.cs b/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyContainerComponent.cs new file mode 100644 index 0000000000..2bbbe22ddf --- /dev/null +++ b/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyContainerComponent.cs @@ -0,0 +1,16 @@ +using Content.Shared.FixedPoint; + +namespace Content.Shared._CP14.MagicEnergy.Components; + +/// +/// Allows an item to store magical energy within itself. +/// +[RegisterComponent, Access(typeof(SharedCP14MagicEnergySystem))] +public sealed partial class CP14MagicEnergyContainerComponent : Component +{ + [DataField] + public FixedPoint2 Energy = 0f; + + [DataField] + public FixedPoint2 MaxEnergy = 100f; +} diff --git a/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyCrystalComponent.cs b/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyCrystalComponent.cs new file mode 100644 index 0000000000..448717e1b1 --- /dev/null +++ b/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyCrystalComponent.cs @@ -0,0 +1,9 @@ +namespace Content.Shared._CP14.MagicEnergy.Components; + +/// +/// allows the object to be inserted into CP14MagicEnergyCrystalSlot +/// +[RegisterComponent, Access(typeof(SharedCP14MagicEnergyCrystalSlotSystem))] +public sealed partial class CP14MagicEnergyCrystalComponent : Component +{ +} diff --git a/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyCrystalSlotComponent.cs b/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyCrystalSlotComponent.cs new file mode 100644 index 0000000000..728a53b011 --- /dev/null +++ b/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyCrystalSlotComponent.cs @@ -0,0 +1,47 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared._CP14.MagicEnergy.Components; + +/// +/// Allows you to examine how much energy is in that object +/// +[RegisterComponent, Access(typeof(SharedCP14MagicEnergyCrystalSlotSystem))] +public sealed partial class CP14MagicEnergyCrystalSlotComponent : Component +{ + [DataField(required: true)] + public string SlotId = string.Empty; + + public bool Powered = false; +} + +[Serializable, NetSerializable] +public enum CP14MagicSlotVisuals : byte +{ + Inserted, + Powered +} + +/// +/// Is called when the state of the crystal is changed: it is pulled out, inserted, or the amount of energy in it has changed. +/// +public sealed class CP14SlotCrystalChangedEvent : EntityEventArgs +{ + public readonly bool Ejected; + + public CP14SlotCrystalChangedEvent(bool ejected) + { + Ejected = ejected; + } +} + +/// +/// Is called when the power status of the device changes. +/// +public sealed class CP14SlotCrystalPowerChangedEvent : EntityEventArgs +{ + public readonly bool Powered; + public CP14SlotCrystalPowerChangedEvent(bool powered) + { + Powered = powered; + } +} diff --git a/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyExaminableComponent.cs b/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyExaminableComponent.cs new file mode 100644 index 0000000000..398e429997 --- /dev/null +++ b/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyExaminableComponent.cs @@ -0,0 +1,9 @@ +namespace Content.Shared._CP14.MagicEnergy.Components; + +/// +/// Allows you to examine how much energy is in that object +/// +[RegisterComponent, Access(typeof(SharedCP14MagicEnergySystem))] +public sealed partial class CP14MagicEnergyExaminableComponent : Component +{ +} diff --git a/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyPointLightController.cs b/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyPointLightController.cs new file mode 100644 index 0000000000..85bf64e9e2 --- /dev/null +++ b/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyPointLightController.cs @@ -0,0 +1,16 @@ +using Content.Shared.Inventory; + +namespace Content.Shared._CP14.MagicEnergy.Components; + +/// +/// Controls the strength of the PointLight component, depending on the amount of mana in the object +/// +[RegisterComponent, Access(typeof(SharedCP14MagicEnergySystem))] +public sealed partial class CP14MagicEnergyPointLightControllerComponent : Component +{ + [DataField] + public float MaxEnergy = 1f; + + [DataField] + public float MinEnergy = 0f; +} diff --git a/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyScannerComponent.cs b/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyScannerComponent.cs new file mode 100644 index 0000000000..c50b4f62c5 --- /dev/null +++ b/Content.Shared/_CP14/MagicEnergy/Components/CP14MagicEnergyScannerComponent.cs @@ -0,0 +1,11 @@ +using Content.Shared.Inventory; + +namespace Content.Shared._CP14.MagicEnergy.Components; + +/// +/// Allows you to see how much magic energy is stored in objects +/// +[RegisterComponent, Access(typeof(SharedCP14MagicEnergySystem))] +public sealed partial class CP14MagicEnergyScannerComponent : Component +{ +} diff --git a/Content.Shared/_CP14/MagicEnergy/SharedCP14MagicEnergyCrystalSlotSystem.cs b/Content.Shared/_CP14/MagicEnergy/SharedCP14MagicEnergyCrystalSlotSystem.cs new file mode 100644 index 0000000000..be0974ad07 --- /dev/null +++ b/Content.Shared/_CP14/MagicEnergy/SharedCP14MagicEnergyCrystalSlotSystem.cs @@ -0,0 +1,42 @@ +using Content.Shared._CP14.MagicEnergy.Components; +using Content.Shared.Containers.ItemSlots; +using Robust.Shared.Containers; + +namespace Content.Shared._CP14.MagicEnergy; + +public partial class SharedCP14MagicEnergyCrystalSlotSystem : EntitySystem +{ + [Dependency] private readonly ItemSlotsSystem _itemSlots = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedContainerSystem _containerSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnCrystalInserted); + SubscribeLocalEvent(OnCrystalRemoved); + } + + private void OnCrystalRemoved(Entity slot, ref EntRemovedFromContainerMessage args) + { + if (args.Container.ID != slot.Comp.SlotId) + return; + + _appearance.SetData(slot, CP14MagicSlotVisuals.Inserted, false); + _appearance.SetData(slot, CP14MagicSlotVisuals.Powered, false); + RaiseLocalEvent(slot, new CP14SlotCrystalChangedEvent(true)); + } + + private void OnCrystalInserted(Entity slot, ref EntInsertedIntoContainerMessage args) + { + if (!slot.Comp.Initialized) + return; + + if (args.Container.ID != slot.Comp.SlotId) + return; + + _appearance.SetData(slot, CP14MagicSlotVisuals.Inserted, true); + RaiseLocalEvent(slot, new CP14SlotCrystalChangedEvent(false)); + } +} diff --git a/Content.Shared/_CP14/MagicEnergy/SharedCP14MagicEnergySystem.cs b/Content.Shared/_CP14/MagicEnergy/SharedCP14MagicEnergySystem.cs new file mode 100644 index 0000000000..9f5013468e --- /dev/null +++ b/Content.Shared/_CP14/MagicEnergy/SharedCP14MagicEnergySystem.cs @@ -0,0 +1,57 @@ +using Content.Shared._CP14.MagicEnergy.Components; +using Content.Shared.Examine; +using Content.Shared.FixedPoint; +using Content.Shared.Inventory; + +namespace Content.Shared._CP14.MagicEnergy; + +public partial class SharedCP14MagicEnergySystem : EntitySystem +{ + public string GetEnergyExaminedText(EntityUid uid, CP14MagicEnergyContainerComponent ent) + { + var power = (int)((ent.Energy / ent.MaxEnergy) * 100); + + var color = "#3fc488"; + if (power < 66) + color = "#f2a93a"; + if (power < 33) + color = "#c23030"; + + return Loc.GetString("cp14-magic-energy-scan-result", + ("item", MetaData(uid).EntityName), + ("power", power), + ("color", color)); + } +} + +/// +/// It's triggered when the energy change in MagicEnergyContainer +/// +public sealed class CP14MagicEnergyLevelChangeEvent : EntityEventArgs +{ + public FixedPoint2 OldValue; + public FixedPoint2 NewValue; + public FixedPoint2 MaxValue; +} + +/// +/// It's triggered when more energy enters the MagicEnergyContainer than it can hold. +/// +public sealed class CP14MagicEnergyOverloadEvent : EntityEventArgs +{ + public FixedPoint2 OverloadEnergy; +} + +/// +/// It's triggered they something try to get energy out of MagicEnergyContainer that is lacking there. +/// +public sealed class CP14MagicEnergyBurnOutEvent : EntityEventArgs +{ + public FixedPoint2 BurnOutEnergy; +} + +public sealed class CP14MagicEnergyScanEvent : EntityEventArgs, IInventoryRelayEvent +{ + public bool CanScan; + public SlotFlags TargetSlots { get; } = SlotFlags.EYES; +} diff --git a/Resources/Audio/_CP14/Ambience/ambiAlchemy.ogg b/Resources/Audio/_CP14/Ambience/ambiAlchemy.ogg new file mode 100644 index 0000000000..c24aa0522e Binary files /dev/null and b/Resources/Audio/_CP14/Ambience/ambiAlchemy.ogg differ diff --git a/Resources/Audio/_CP14/Ambience/attributions.yml b/Resources/Audio/_CP14/Ambience/attributions.yml index ad4a7a3dba..36b45a0b6e 100644 --- a/Resources/Audio/_CP14/Ambience/attributions.yml +++ b/Resources/Audio/_CP14/Ambience/attributions.yml @@ -21,4 +21,9 @@ - files: ["weatherWindy.ogg"] license: "CC-BY-4.0" copyright: 'by Benboncan of Freesound.org. Mixed from stereo to mono.' - source: "https://freesound.org/people/Benboncan/sounds/134699/" \ No newline at end of file + source: "https://freesound.org/people/Benboncan/sounds/134699/" + +- files: ["ambiAlchemy.ogg"] + license: "CC-BY-4.0" + copyright: 'by be-steele of Freesound.org.' + source: "https://freesound.org/people/be-steele/sounds/130753/" \ No newline at end of file diff --git a/Resources/Audio/_CP14/Ambience/normalizer_working.ogg b/Resources/Audio/_CP14/Ambience/normalizer_working.ogg new file mode 100644 index 0000000000..affd28294a Binary files /dev/null and b/Resources/Audio/_CP14/Ambience/normalizer_working.ogg differ diff --git a/Resources/Audio/_CP14/Items/attributions.yml b/Resources/Audio/_CP14/Items/attributions.yml index bac070465d..a5a59ca0f1 100644 --- a/Resources/Audio/_CP14/Items/attributions.yml +++ b/Resources/Audio/_CP14/Items/attributions.yml @@ -31,4 +31,14 @@ - files: ["shovel_dig1.ogg", "shovel_dig2.ogg", "shovel_dig3.ogg", "shovel_dig4.ogg", "shovel_dig5.ogg"] license: "CC0-1.0" copyright: 'by Ali_6868 of Freesound.org. Cropped and mixed from stereo to mono.' - source: "https://freesound.org/people/Ali_6868/sounds/384361/" \ No newline at end of file + source: "https://freesound.org/people/Ali_6868/sounds/384361/" + +- files: ["crystal_eject.ogg", "crystal_insert.ogg"] + license: "CC-BY-4.0" + copyright: 'by Joachim_Berger of Freesound.org. Cropped by TheShuEd.' + source: "https://freesound.org/people/Joachim_Berger/sounds/660526/" + +- files: ["normalizer_working.ogg"] + license: "CC0-1.0" + copyright: 'by craigsmith of Freesound.org. Cropped by TheShuEd.' + source: "https://freesound.org/people/craigsmith/sounds/438604/" \ No newline at end of file diff --git a/Resources/Audio/_CP14/Items/crystal_eject.ogg b/Resources/Audio/_CP14/Items/crystal_eject.ogg new file mode 100644 index 0000000000..f7514ca920 Binary files /dev/null and b/Resources/Audio/_CP14/Items/crystal_eject.ogg differ diff --git a/Resources/Audio/_CP14/Items/crystal_insert.ogg b/Resources/Audio/_CP14/Items/crystal_insert.ogg new file mode 100644 index 0000000000..29580828ca Binary files /dev/null and b/Resources/Audio/_CP14/Items/crystal_insert.ogg differ diff --git a/Resources/Locale/en-US/_CP14/magicEnergy/magic-energy.ftl b/Resources/Locale/en-US/_CP14/magicEnergy/magic-energy.ftl new file mode 100644 index 0000000000..2a3de7acf9 --- /dev/null +++ b/Resources/Locale/en-US/_CP14/magicEnergy/magic-energy.ftl @@ -0,0 +1,7 @@ +cp14-magic-energy-scan-result = The {$item} is filled with [color={$color}]{$power}%[/color] magical energy + +cp14-magic-energy-crystal-slot-name = Energy crystal + +cp14-magic-energy-no-crystal = No energy crystal! +cp14-magic-energy-insufficient = Not enough energy! +cp14-magic-energy-insufficient-unsafe = Crystal cracks from lack of energy! \ No newline at end of file diff --git a/Resources/Locale/ru-RU/_CP14/magicEnergy/magic-energy.ftl b/Resources/Locale/ru-RU/_CP14/magicEnergy/magic-energy.ftl new file mode 100644 index 0000000000..08146f578b --- /dev/null +++ b/Resources/Locale/ru-RU/_CP14/magicEnergy/magic-energy.ftl @@ -0,0 +1,7 @@ +cp14-magic-energy-scan-result = {$item} заполнен магической энергией на [color={$color}]{$power}%[/color] + +cp14-magic-energy-crystal-slot-name = Энергокристалл + +cp14-magic-energy-no-crystal = Отсутствует энергокристалл! +cp14-magic-energy-insufficient = Не достаточно энергии! +cp14-magic-energy-insufficient-unsafe = Кристалл трескается от нехватки энергии! \ No newline at end of file diff --git a/Resources/Prototypes/_CP14/Entities/Clothing/Eyes/eyes.yml b/Resources/Prototypes/_CP14/Entities/Clothing/Eyes/eyes.yml index 0002c28801..4219c28f5c 100644 --- a/Resources/Prototypes/_CP14/Entities/Clothing/Eyes/eyes.yml +++ b/Resources/Prototypes/_CP14/Entities/Clothing/Eyes/eyes.yml @@ -60,3 +60,22 @@ sprite: _CP14/Clothing/Eyes/alchemy_glasses.rsi - type: SolutionScanner +- type: entity + parent: CP14ClothingEyesBase + id: CP14ClothingEyesThaumaturgyGlasses + name: thaumaturgy glasses + description: Goggles that allow you to scan magical items and creatures to clearly see the amount of energy left in them. + components: + - type: Foldable + canFoldInsideContainer: true + unfoldVerbText: fold-flip-verb + foldVerbText: fold-flip-verb + - type: FoldableClothing + foldedEquippedPrefix: flipped + foldedHeldPrefix: flipped + - type: Sprite + sprite: _CP14/Clothing/Eyes/alchemy_glasses.rsi #TODO sprite + - type: Clothing + sprite: _CP14/Clothing/Eyes/alchemy_glasses.rsi + - type: CP14MagicEnergyScanner + diff --git a/Resources/Prototypes/_CP14/Entities/Objects/Specific/Alchemy/herbals.yml b/Resources/Prototypes/_CP14/Entities/Objects/Specific/Alchemy/herbals.yml index 9f1cb6fa73..5a1f5b2f43 100644 --- a/Resources/Prototypes/_CP14/Entities/Objects/Specific/Alchemy/herbals.yml +++ b/Resources/Prototypes/_CP14/Entities/Objects/Specific/Alchemy/herbals.yml @@ -157,8 +157,8 @@ - type: entity id: CP14QuartzShard parent: BaseItem - name: quartz shard - description: a shard of once luminous crystal. Unfortunately, careless handling destroyed much of the potential. + name: rough quartz + description: a natural crystal that is a natural storage of magical energy. Its color reflects the quality of the crystal - the higher the emission spectrum, the higher the level of energy leakage. components: - type: Tag tags: diff --git a/Resources/Prototypes/_CP14/Entities/Objects/Specific/Thaumaturgy/crystal.yml b/Resources/Prototypes/_CP14/Entities/Objects/Specific/Thaumaturgy/crystal.yml new file mode 100644 index 0000000000..2924a66380 --- /dev/null +++ b/Resources/Prototypes/_CP14/Entities/Objects/Specific/Thaumaturgy/crystal.yml @@ -0,0 +1,78 @@ +- type: entity + id: CP14EnergyCrystalBase + parent: BaseItem + abstract: true + description: Processed quartz crystals are excellent repositories of magical energy. And special connectors allow you to conveniently insert them into magical devices, turning them into energy batteries. + components: + - type: CP14MagicEnergyCrystal + - type: Item + size: Tiny + - type: Sprite + sprite: _CP14/Objects/Specific/Thaumaturgy/crystal.rsi + - type: CP14MagicEnergyContainer + - type: CP14MagicEnergyExaminable + - type: CP14MagicEnergyPointLightController + + +- type: entity + id: CP14EnergyCrystalSmall + parent: CP14EnergyCrystalBase + name: small energy crystal + suffix: Full + components: + - type: Sprite + layers: + - state: small1 + shader: unshaded + map: ["random"] + - state: small_connector + - type: RandomSprite + available: + - random: + small1: "" + small2: "" + small3: "" + - type: CP14MagicEnergyContainer + energy: 30 + maxEnergy: 30 + +- type: entity + id: CP14EnergyCrystalSmallEmpty + parent: CP14EnergyCrystalSmall + suffix: Empty + components: + - type: CP14MagicEnergyContainer + energy: 0 + + +- type: entity + id: CP14EnergyCrystalMedium + parent: CP14EnergyCrystalBase + name: energy crystal + suffix: Full + components: + - type: PointLight + radius: 1.2 + - type: Sprite + layers: + - state: medium1 + shader: unshaded + map: ["random"] + - state: medium_connector + - type: RandomSprite + available: + - random: + medium1: "" + medium2: "" + medium3: "" + - type: CP14MagicEnergyContainer + energy: 100 + maxEnergy: 100 + +- type: entity + id: CP14EnergyCrystalMediumEmpty + parent: CP14EnergyCrystalMedium + suffix: Empty + components: + - type: CP14MagicEnergyContainer + energy: 0 \ No newline at end of file diff --git a/Resources/Prototypes/_CP14/Entities/Structures/Specific/Alchemy/normalizer.yml b/Resources/Prototypes/_CP14/Entities/Structures/Specific/Alchemy/normalizer.yml index a2e6ef6983..61225abd48 100644 --- a/Resources/Prototypes/_CP14/Entities/Structures/Specific/Alchemy/normalizer.yml +++ b/Resources/Prototypes/_CP14/Entities/Structures/Specific/Alchemy/normalizer.yml @@ -1,7 +1,7 @@ - type: entity id: CP14AlchemyNormalizer parent: BaseStructureDynamic - name: solution stabilizer + name: solution normalizer description: An alchemical device that removes fine precipitates from solutions, and stabilizes it for further work placement: mode: PlaceFree @@ -14,13 +14,31 @@ offset: 0, 0.2 sprite: _CP14/Structures/Specific/Alchemy/normalizer.rsi layers: - - state: rotate_back + - state: rotate_back_stop + map: ["poweredBack"] - state: liq-1 map: ["enum.SolutionContainerLayers.Fill"] visible: false - state: base - - state: rotate_front - state: base + - state: rotate_front_stop + map: ["poweredFront"] + - state: crystal + shader: unshaded + map: ["crystal"] + visible: false + - type: GenericVisualizer + visuals: + enum.CP14MagicSlotVisuals.Inserted: + crystal: + True: { visible: true } + False: { visible: false } + enum.CP14MagicSlotVisuals.Powered: + poweredFront: + True: { state: rotate_front } + False: { state: rotate_front_stop } + poweredBack: + True: { state: rotate_back } + False: { state: rotate_back_stop } - type: Fixtures fixtures: fix1: @@ -48,7 +66,37 @@ solution: normalizer - type: CP14SolutionNormalizer solution: normalizer + - type: AmbientSound + enabled: false + range: 6 + volume: -3 + sound: + path: /Audio/_CP14/Ambience/normalizer_working.ogg - type: Appearance - type: SolutionContainerVisuals maxFillLevels: 5 - fillBaseName: liq- \ No newline at end of file + fillBaseName: liq- + - type: CP14MagicEnergyDraw + energy: -0.2 + delay: 1 + - type: CP14MagicEnergyCrystalSlot + slotId: crystal_slot + - type: ContainerContainer + containers: + crystal_slot: !type:ContainerSlot + - type: ItemSlots + slots: + crystal_slot: + insertSound: + path: /Audio/_CP14/Items/crystal_insert.ogg + params: + variation: 0.05 + ejectSound: + path: /Audio/_CP14/Items/crystal_eject.ogg + params: + variation: 0.05 + ejectOnInteract: true + name: cp14-magic-energy-crystal-slot-name + whitelist: + components: + - CP14MagicEnergyCrystal \ No newline at end of file diff --git a/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/medium1.png b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/medium1.png new file mode 100644 index 0000000000..7de9fc37f2 Binary files /dev/null and b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/medium1.png differ diff --git a/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/medium2.png b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/medium2.png new file mode 100644 index 0000000000..2b5935848a Binary files /dev/null and b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/medium2.png differ diff --git a/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/medium3.png b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/medium3.png new file mode 100644 index 0000000000..87a74db46f Binary files /dev/null and b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/medium3.png differ diff --git a/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/medium_connector.png b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/medium_connector.png new file mode 100644 index 0000000000..f7d2f44e4c Binary files /dev/null and b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/medium_connector.png differ diff --git a/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/meta.json b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/meta.json new file mode 100644 index 0000000000..add8b46e5e --- /dev/null +++ b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/meta.json @@ -0,0 +1,35 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Created by TheShuEd (Github) for CrystallPunk14", + "states": [ + { + "name": "small1" + }, + { + "name": "small2" + }, + { + "name": "small3" + }, + { + "name": "small_connector" + }, + { + "name": "medium1" + }, + { + "name": "medium2" + }, + { + "name": "medium3" + }, + { + "name": "medium_connector" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/small1.png b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/small1.png new file mode 100644 index 0000000000..480755d599 Binary files /dev/null and b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/small1.png differ diff --git a/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/small2.png b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/small2.png new file mode 100644 index 0000000000..0165769c62 Binary files /dev/null and b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/small2.png differ diff --git a/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/small3.png b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/small3.png new file mode 100644 index 0000000000..f2939d1c9f Binary files /dev/null and b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/small3.png differ diff --git a/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/small_connector.png b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/small_connector.png new file mode 100644 index 0000000000..c6209173e0 Binary files /dev/null and b/Resources/Textures/_CP14/Objects/Specific/Thaumaturgy/crystal.rsi/small_connector.png differ diff --git a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/base.png b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/base.png index 425e9e3efd..da7fdee075 100644 Binary files a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/base.png and b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/base.png differ diff --git a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/crystal.png b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/crystal.png new file mode 100644 index 0000000000..b8a471a7d2 Binary files /dev/null and b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/crystal.png differ diff --git a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/meta.json b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/meta.json index d45fe7fd2e..df73c4d886 100644 --- a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/meta.json +++ b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/meta.json @@ -25,6 +25,15 @@ { "name": "liq-5" }, + { + "name": "crystal" + }, + { + "name": "rotate_back_stop" + }, + { + "name": "rotate_front_stop" + }, { "name": "rotate_back", "delays": [ diff --git a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/rotate_back_stop.png b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/rotate_back_stop.png new file mode 100644 index 0000000000..d9b7f83316 Binary files /dev/null and b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/rotate_back_stop.png differ diff --git a/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/rotate_front_stop.png b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/rotate_front_stop.png new file mode 100644 index 0000000000..234c6460d5 Binary files /dev/null and b/Resources/Textures/_CP14/Structures/Specific/Alchemy/normalizer.rsi/rotate_front_stop.png differ