Upstream core (#284)
* [Feature] Holo Update (#948) * Это база, основа, фундамент. * update icons * based2 * zamena headcoder * протоНовые функции Обновлены окна персонажа для отображения статистики и навыков игрока. Добавлена система боевой музыки, которая активируется во время боя. Реализована функция широковещательной передачи сообщений в чате для нескольких получателей. Внедрены изменения на основе навыков и статистики для медицинских систем, включая дефибриллятор и лечение. Улучшена система ближнего боя с новыми действиями и сообщениями. Введена система предсказуемого рандома для продвинутой генерации случайных значений. Навыки и статистика теперь зависят от назначений на работу. * abilities * zvuk * tweaks & fixes * sprite fix * govno * govno2 * fix govna * GOVNOOOOOOOOOOOO * finally * цена (cherry picked from commit cf4a7d0a7ccb780905e0df7db80d60d2338c02d0) * Automatic changelog update (cherry picked from commit 32a1f13849b4593fa03eafff99179814278f5f11) --------- Co-authored-by: RavmorganButOnCocaine <valtos@nextmail.ru>
This commit is contained in:
114
Content.Client/_White/Guardian/GuardianSelectorBUI.cs
Normal file
114
Content.Client/_White/Guardian/GuardianSelectorBUI.cs
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
using Content.Client._White.UserInterface.Radial;
|
||||||
|
using Content.Shared._White.Guardian;
|
||||||
|
|
||||||
|
namespace Content.Client._White.Guardian;
|
||||||
|
|
||||||
|
public sealed class GuardianSelectorBUI : BoundUserInterface
|
||||||
|
{
|
||||||
|
private readonly Dictionary<GuardianSelector, string> _names = new()
|
||||||
|
{
|
||||||
|
{ GuardianSelector.Assasin, Loc.GetString("guardian-assasin-name")},
|
||||||
|
{ GuardianSelector.Charger, Loc.GetString("guardian-charger-name")},
|
||||||
|
{ GuardianSelector.Lighting, Loc.GetString("guardian-lighting-name")},
|
||||||
|
{ GuardianSelector.Standart, Loc.GetString("guardian-standart-name")},
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly Dictionary<GuardianSelector, string> _icons = new()
|
||||||
|
{
|
||||||
|
{ GuardianSelector.Assasin, "/Textures/White/Interface/guardianselector.rsi/assasin.png" },
|
||||||
|
{ GuardianSelector.Charger, "/Textures/White/Interface/guardianselector.rsi/charger.png" },
|
||||||
|
{ GuardianSelector.Lighting, "/Textures/White/Interface/guardianselector.rsi/lighting.png" },
|
||||||
|
{ GuardianSelector.Standart, "/Textures/White/Interface/guardianselector.rsi/standart.png" },
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly Dictionary<string, GuardianSelector> _guardianSelectors = new()
|
||||||
|
{
|
||||||
|
{ "Assasin", GuardianSelector.Assasin },
|
||||||
|
{ "Charger", GuardianSelector.Charger },
|
||||||
|
{ "Lighting", GuardianSelector.Lighting },
|
||||||
|
{ "Standart", GuardianSelector.Standart },
|
||||||
|
};
|
||||||
|
|
||||||
|
private RadialContainer? _radialContainer;
|
||||||
|
private bool _updated;
|
||||||
|
|
||||||
|
public GuardianSelectorBUI(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Open()
|
||||||
|
{
|
||||||
|
base.Open();
|
||||||
|
|
||||||
|
if (_radialContainer != null)
|
||||||
|
UIReset();
|
||||||
|
|
||||||
|
_radialContainer = new RadialContainer();
|
||||||
|
|
||||||
|
_radialContainer.Closed += Close;
|
||||||
|
|
||||||
|
if (State != null)
|
||||||
|
UpdateState(State);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UIReset()
|
||||||
|
{
|
||||||
|
_radialContainer?.Close();
|
||||||
|
_radialContainer = null;
|
||||||
|
_updated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PopulateRadial(IReadOnlyCollection<string> ids, NetEntity target)
|
||||||
|
{
|
||||||
|
foreach (var id in ids)
|
||||||
|
{
|
||||||
|
if (_radialContainer == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!_guardianSelectors.TryGetValue(id, out var guardianSelector))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(!_names.TryGetValue(guardianSelector, out var name) || !_icons.TryGetValue(guardianSelector, out var icon))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var button = _radialContainer.AddButton(name, icon);
|
||||||
|
button.Controller.OnPressed += _ =>
|
||||||
|
{
|
||||||
|
Select(guardianSelector, target);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Select(GuardianSelector type, NetEntity target)
|
||||||
|
{
|
||||||
|
SendMessage(new GuardianSelectorSelectedBuiMessage(type, target));
|
||||||
|
UIReset();
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
base.Dispose(disposing);
|
||||||
|
_radialContainer?.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateState(BoundUserInterfaceState state)
|
||||||
|
{
|
||||||
|
base.UpdateState(state);
|
||||||
|
|
||||||
|
if (_updated)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (state is GuardianSelectorBUIState newState)
|
||||||
|
{
|
||||||
|
PopulateRadial(newState.Ids, newState.Target);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_radialContainer == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_radialContainer?.OpenAttachedLocalPlayer();
|
||||||
|
_updated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
|
using Content.Shared._White.Guardian;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
namespace Content.Server.Guardian
|
namespace Content.Server.Guardian
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -15,20 +20,63 @@ namespace Content.Server.Guardian
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Percentage of damage reflected from the guardian to the host
|
/// Percentage of damage reflected from the guardian to the host
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField("damageShare")]
|
||||||
public float DamageShare { get; set; } = 0.65f;
|
public float DamageShare { get; set; } = 0.65f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maximum distance the guardian can travel before it's forced to recall, use YAML to set
|
/// Maximum distance the guardian can travel before it's forced to recall, use YAML to set
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField("distance")]
|
||||||
public float DistanceAllowed { get; set; } = 5f;
|
public float DistanceAllowed { get; set; } = 5f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum default distance the guardian can travel before it's forced to recall, use YAML to set
|
||||||
|
/// </summary>
|
||||||
|
[DataField("distanceDefault")]
|
||||||
|
public float DistanceAllowedDefault { get; set; } = 10f;
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public float DistancePowerAssasin { get; set; } = 25f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If the guardian is currently manifested
|
/// If the guardian is currently manifested
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField]
|
[DataField]
|
||||||
public bool GuardianLoose;
|
public bool GuardianLoose;
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public GuardianSelector GuardianType = GuardianSelector.Standart;
|
||||||
|
|
||||||
|
[DataField("powerToggleAction", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||||
|
public string PowerToggleAction = "ActionGuardianPowerToggle";
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public EntityUid? PowerToggleActionEntity;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField]
|
||||||
|
public bool IsInPowerMode;
|
||||||
|
|
||||||
|
[DataField("chargerPowerAction", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||||
|
public string ChargerPowerAction = "ActionChargerPower";
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public EntityUid? ChargerPowerActionEntity;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField]
|
||||||
|
public bool IsCharged;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("assasinDamageModifier")]
|
||||||
|
public float AssasinDamageModifier = 3F;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField]
|
||||||
|
public int LightingCount = 1;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField]
|
||||||
|
public SoundSpecifier? ChargerSound = new SoundPathSpecifier("/Audio/White/Guardian/charger.ogg");
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public EntProtoId Action = "ActionToggleGuardian";
|
||||||
|
|
||||||
|
[DataField] public EntityUid? ActionEntity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
|
||||||
|
|
||||||
namespace Content.Server.Guardian
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a GuardianComponent attached to the user's GuardianHost.
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class GuardianCreatorComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Counts as spent upon exhausting the injection
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// We don't mark as deleted as examine depends on this.
|
|
||||||
/// </remarks>
|
|
||||||
public bool Used = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The prototype of the guardian entity which will be created
|
|
||||||
/// </summary>
|
|
||||||
[DataField("guardianProto", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>), required: true)]
|
|
||||||
public string GuardianProto { get; set; } = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How long it takes to inject someone.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("delay")]
|
|
||||||
public float InjectionDelay = 5f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
|
using Content.Server._White.IncorporealSystem;
|
||||||
using Content.Server.Body.Systems;
|
using Content.Server.Body.Systems;
|
||||||
|
using Content.Server.Lightning;
|
||||||
using Content.Server.Popups;
|
using Content.Server.Popups;
|
||||||
|
using Content.Shared._White.Guardian;
|
||||||
using Content.Shared.Actions;
|
using Content.Shared.Actions;
|
||||||
using Content.Shared.Audio;
|
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.DoAfter;
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
@@ -12,7 +14,7 @@ using Content.Shared.Interaction;
|
|||||||
using Content.Shared.Interaction.Events;
|
using Content.Shared.Interaction.Events;
|
||||||
using Content.Shared.Mobs;
|
using Content.Shared.Mobs;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Robust.Server.GameObjects;
|
using Content.Shared.Weapons.Melee;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Audio.Systems;
|
using Robust.Shared.Audio.Systems;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
@@ -35,6 +37,9 @@ namespace Content.Server.Guardian
|
|||||||
[Dependency] private readonly BodySystem _bodySystem = default!;
|
[Dependency] private readonly BodySystem _bodySystem = default!;
|
||||||
[Dependency] private readonly SharedContainerSystem _container = default!;
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||||
|
[Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
|
||||||
|
[Dependency] private readonly LightningSystem _lightningSystem = default!;
|
||||||
|
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -58,8 +63,93 @@ namespace Content.Server.Guardian
|
|||||||
SubscribeLocalEvent<GuardianHostComponent, GuardianToggleActionEvent>(OnPerformAction);
|
SubscribeLocalEvent<GuardianHostComponent, GuardianToggleActionEvent>(OnPerformAction);
|
||||||
|
|
||||||
SubscribeLocalEvent<GuardianComponent, AttackAttemptEvent>(OnGuardianAttackAttempt);
|
SubscribeLocalEvent<GuardianComponent, AttackAttemptEvent>(OnGuardianAttackAttempt);
|
||||||
|
|
||||||
|
// PARSEC EDIT START
|
||||||
|
SubscribeLocalEvent<GuardianCreatorComponent, GuardianSelectorSelectedBuiMessage>(OnGuardianSelected);
|
||||||
|
SubscribeLocalEvent<GuardianComponent, ToggleGuardianPowerActionEvent>(OnPerformGuardianPowerAction);
|
||||||
|
SubscribeLocalEvent<GuardianComponent, ChargerPowerActionEvent>(OnPerformChargerPowerAction);
|
||||||
|
SubscribeLocalEvent<GuardianComponent, GuardianToggleActionEvent>(OnPerformGuardianAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PARSEC EDIT START
|
||||||
|
|
||||||
|
private void OnGuardianSelected(EntityUid uid,
|
||||||
|
GuardianCreatorComponent component,
|
||||||
|
GuardianSelectorSelectedBuiMessage args)
|
||||||
|
{
|
||||||
|
var target = GetEntity(args.Target);
|
||||||
|
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.Actor, component.InjectionDelay, new GuardianCreatorDoAfterEvent{SelectedType = args.GuardianType}, uid, target: target, used: uid){BreakOnMove = true});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPerformGuardianPowerAction(EntityUid uid,
|
||||||
|
GuardianComponent component,
|
||||||
|
ToggleGuardianPowerActionEvent args)
|
||||||
|
{
|
||||||
|
if(args.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Handled = true;
|
||||||
|
ToggleGuardianPower(uid, component, !component.IsInPowerMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ToggleGuardianPower(EntityUid uid, GuardianComponent component, bool toggleValue)
|
||||||
|
{
|
||||||
|
if (component.IsInPowerMode == toggleValue)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(component.PowerToggleActionEntity == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (component is { IsInPowerMode: false, GuardianLoose: true })
|
||||||
|
{
|
||||||
|
_popupSystem.PopupEntity("Вы должны находится в теле, чтобы активировать способность!", uid, uid, PopupType.MediumCaution);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
component.IsInPowerMode = toggleValue;
|
||||||
|
|
||||||
|
_actionSystem.SetToggled(component.PowerToggleActionEntity, component.IsInPowerMode);
|
||||||
|
SetupPower(uid, component, component.GuardianType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupPower(EntityUid uid, GuardianComponent component, GuardianSelector type)
|
||||||
|
{
|
||||||
|
if (type == GuardianSelector.Assasin)
|
||||||
|
SetupAssasin(uid, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupAssasin(EntityUid uid, GuardianComponent component)
|
||||||
|
{
|
||||||
|
if (HasComp<IncorporealComponent>(uid))
|
||||||
|
{
|
||||||
|
RemComp<IncorporealComponent>(uid);
|
||||||
|
_actionSystem.SetToggled(component.PowerToggleActionEntity, !component.IsInPowerMode);
|
||||||
|
component.IsInPowerMode = false;
|
||||||
|
component.DistanceAllowed = component.DistanceAllowedDefault;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var incorporealComp = EnsureComp<IncorporealComponent>(uid);
|
||||||
|
incorporealComp.Effect = false;
|
||||||
|
component.DistanceAllowed = component.DistancePowerAssasin;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPerformChargerPowerAction(EntityUid uid, GuardianComponent component, ChargerPowerActionEvent args)
|
||||||
|
{
|
||||||
|
if(args.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Handled = true;
|
||||||
|
|
||||||
|
if(component.IsCharged)
|
||||||
|
return;
|
||||||
|
|
||||||
|
component.IsCharged = true;
|
||||||
|
_audio.PlayPvs(component.ChargerSound, uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Parsec edit end
|
||||||
|
|
||||||
private void OnGuardianShutdown(EntityUid uid, GuardianComponent component, ComponentShutdown args)
|
private void OnGuardianShutdown(EntityUid uid, GuardianComponent component, ComponentShutdown args)
|
||||||
{
|
{
|
||||||
var host = component.Host;
|
var host = component.Host;
|
||||||
@@ -70,6 +160,10 @@ namespace Content.Server.Guardian
|
|||||||
|
|
||||||
_container.Remove(uid, hostComponent.GuardianContainer);
|
_container.Remove(uid, hostComponent.GuardianContainer);
|
||||||
hostComponent.HostedGuardian = null;
|
hostComponent.HostedGuardian = null;
|
||||||
|
if(component.PowerToggleActionEntity != null)
|
||||||
|
_actionSystem.RemoveAction(uid, component.PowerToggleActionEntity); // Parsec
|
||||||
|
if(component.ChargerPowerActionEntity != null)
|
||||||
|
_actionSystem.RemoveAction(uid, component.ChargerPowerActionEntity); // parsec
|
||||||
Dirty(host.Value, hostComponent);
|
Dirty(host.Value, hostComponent);
|
||||||
QueueDel(hostComponent.ActionEntity);
|
QueueDel(hostComponent.ActionEntity);
|
||||||
hostComponent.ActionEntity = null;
|
hostComponent.ActionEntity = null;
|
||||||
@@ -86,6 +180,24 @@ namespace Content.Server.Guardian
|
|||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnPerformGuardianAction(EntityUid uid, GuardianComponent component, GuardianToggleActionEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(component.Host == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var host = (EntityUid) component.Host;
|
||||||
|
|
||||||
|
if(!TryComp<GuardianHostComponent>(host, out var guardianHostComponent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ToggleGuardian(host, guardianHostComponent);
|
||||||
|
|
||||||
|
args.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
private void OnGuardianPlayerDetached(EntityUid uid, GuardianComponent component, PlayerDetachedEvent args)
|
private void OnGuardianPlayerDetached(EntityUid uid, GuardianComponent component, PlayerDetachedEvent args)
|
||||||
{
|
{
|
||||||
var host = component.Host;
|
var host = component.Host;
|
||||||
@@ -109,6 +221,19 @@ namespace Content.Server.Guardian
|
|||||||
}
|
}
|
||||||
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString("guardian-available"), host.Value, host.Value);
|
_popupSystem.PopupEntity(Loc.GetString("guardian-available"), host.Value, host.Value);
|
||||||
|
|
||||||
|
_actionSystem.AddAction(uid, ref component.ActionEntity, component.Action);
|
||||||
|
|
||||||
|
if (component.GuardianType is GuardianSelector.Standart or GuardianSelector.Lighting)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (component.GuardianType == GuardianSelector.Charger)
|
||||||
|
{
|
||||||
|
_actionSystem.AddAction(uid, ref component.ChargerPowerActionEntity, component.ChargerPowerAction);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_actionSystem.AddAction(uid, ref component.PowerToggleActionEntity, component.PowerToggleAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnHostInit(EntityUid uid, GuardianHostComponent component, ComponentInit args)
|
private void OnHostInit(EntityUid uid, GuardianHostComponent component, ComponentInit args)
|
||||||
@@ -133,12 +258,55 @@ namespace Content.Server.Guardian
|
|||||||
|
|
||||||
private void OnGuardianAttackAttempt(EntityUid uid, GuardianComponent component, AttackAttemptEvent args)
|
private void OnGuardianAttackAttempt(EntityUid uid, GuardianComponent component, AttackAttemptEvent args)
|
||||||
{
|
{
|
||||||
if (args.Cancelled || args.Target != component.Host)
|
if (args.Cancelled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// why is this server side code? This should be in shared
|
if (args.Target == null)
|
||||||
_popupSystem.PopupCursor(Loc.GetString("guardian-attack-host"), uid, PopupType.LargeCaution);
|
return;
|
||||||
args.Cancel();
|
|
||||||
|
if (args.Target == component.Host)
|
||||||
|
{
|
||||||
|
_popupSystem.PopupCursor(Loc.GetString("guardian-attack-host"), uid, PopupType.LargeCaution);
|
||||||
|
args.Cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var target = (EntityUid) args.Target;
|
||||||
|
|
||||||
|
if (component.GuardianType == GuardianSelector.Lighting)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < component.LightingCount; i++)
|
||||||
|
{
|
||||||
|
_lightningSystem.ShootLightning(uid, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component.GuardianType == GuardianSelector.Assasin)
|
||||||
|
{
|
||||||
|
if (!component.IsInPowerMode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!TryComp<MeleeWeaponComponent>(args.Weapon, out var meleeWeaponComponent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_damageableSystem.TryChangeDamage(args.Target,
|
||||||
|
meleeWeaponComponent.Damage * component.AssasinDamageModifier,
|
||||||
|
true);
|
||||||
|
SetupAssasin(uid, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (component.GuardianType == GuardianSelector.Charger)
|
||||||
|
{
|
||||||
|
if(!component.IsCharged)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var hand in _handsSystem.EnumerateHands(target))
|
||||||
|
{
|
||||||
|
_handsSystem.TryDrop(target, hand);
|
||||||
|
}
|
||||||
|
|
||||||
|
component.IsCharged = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ToggleGuardian(EntityUid user, GuardianHostComponent hostComponent)
|
public void ToggleGuardian(EntityUid user, GuardianHostComponent hostComponent)
|
||||||
@@ -172,6 +340,7 @@ namespace Content.Server.Guardian
|
|||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
UseCreator(args.User, args.Target.Value, uid, component);
|
UseCreator(args.User, args.Target.Value, uid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UseCreator(EntityUid user, EntityUid target, EntityUid injector, GuardianCreatorComponent component)
|
private void UseCreator(EntityUid user, EntityUid target, EntityUid injector, GuardianCreatorComponent component)
|
||||||
{
|
{
|
||||||
if (component.Used)
|
if (component.Used)
|
||||||
@@ -194,10 +363,11 @@ namespace Content.Server.Guardian
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, component.InjectionDelay, new GuardianCreatorDoAfterEvent(), injector, target: target, used: injector){BreakOnMove = true});
|
_ui.SetUiState(injector, GuardianSelectorUiKey.Key, new GuardianSelectorBUIState(component.GuardiansAvaliable, GetNetEntity(target)));
|
||||||
|
_ui.OpenUi(injector, GuardianSelectorUiKey.Key, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDoAfter(EntityUid uid, GuardianCreatorComponent component, DoAfterEvent args)
|
private void OnDoAfter(EntityUid uid, GuardianCreatorComponent component, GuardianCreatorDoAfterEvent args)
|
||||||
{
|
{
|
||||||
if (args.Handled || args.Args.Target == null)
|
if (args.Handled || args.Args.Target == null)
|
||||||
return;
|
return;
|
||||||
@@ -207,14 +377,16 @@ namespace Content.Server.Guardian
|
|||||||
|
|
||||||
var hostXform = Transform(args.Args.Target.Value);
|
var hostXform = Transform(args.Args.Target.Value);
|
||||||
var host = EnsureComp<GuardianHostComponent>(args.Args.Target.Value);
|
var host = EnsureComp<GuardianHostComponent>(args.Args.Target.Value);
|
||||||
|
var guardianProto = component.GuardianSelectorToProto[args.SelectedType]; // Parsec
|
||||||
// Use map position so it's not inadvertantly parented to the host + if it's in a container it spawns outside I guess.
|
// Use map position so it's not inadvertantly parented to the host + if it's in a container it spawns outside I guess.
|
||||||
var guardian = Spawn(component.GuardianProto, _transform.GetMapCoordinates(args.Args.Target.Value, xform: hostXform));
|
var guardian = Spawn(guardianProto, _transform.GetMapCoordinates(args.Args.Target.Value, xform: hostXform)); // Parsec edit
|
||||||
|
|
||||||
_container.Insert(guardian, host.GuardianContainer);
|
_container.Insert(guardian, host.GuardianContainer);
|
||||||
host.HostedGuardian = guardian;
|
host.HostedGuardian = guardian;
|
||||||
|
|
||||||
if (TryComp<GuardianComponent>(guardian, out var guardianComp))
|
if (TryComp<GuardianComponent>(guardian, out var guardianComp))
|
||||||
{
|
{
|
||||||
|
guardianComp.GuardianType = args.SelectedType;
|
||||||
guardianComp.Host = args.Args.Target.Value;
|
guardianComp.Host = args.Args.Target.Value;
|
||||||
_audio.PlayPvs("/Audio/Effects/guardian_inject.ogg", args.Args.Target.Value);
|
_audio.PlayPvs("/Audio/Effects/guardian_inject.ogg", args.Args.Target.Value);
|
||||||
_popupSystem.PopupEntity(Loc.GetString("guardian-created"), args.Args.Target.Value, args.Args.Target.Value);
|
_popupSystem.PopupEntity(Loc.GetString("guardian-created"), args.Args.Target.Value, args.Args.Target.Value);
|
||||||
@@ -273,8 +445,8 @@ namespace Content.Server.Guardian
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void OnCreatorExamine(EntityUid uid, GuardianCreatorComponent component, ExaminedEvent args)
|
private void OnCreatorExamine(EntityUid uid, GuardianCreatorComponent component, ExaminedEvent args)
|
||||||
{
|
{
|
||||||
if (component.Used)
|
if (component.Used)
|
||||||
args.PushMarkup(Loc.GetString("guardian-activator-empty-examine"));
|
args.PushMarkup(Loc.GetString("guardian-activator-empty-examine"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -344,7 +516,7 @@ namespace Content.Server.Guardian
|
|||||||
guardianComponent.GuardianLoose = true;
|
guardianComponent.GuardianLoose = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RetractGuardian(EntityUid host,GuardianHostComponent hostComponent, EntityUid guardian, GuardianComponent guardianComponent)
|
private void RetractGuardian(EntityUid host, GuardianHostComponent hostComponent, EntityUid guardian, GuardianComponent guardianComponent)
|
||||||
{
|
{
|
||||||
if (!guardianComponent.GuardianLoose)
|
if (!guardianComponent.GuardianLoose)
|
||||||
{
|
{
|
||||||
@@ -355,6 +527,20 @@ namespace Content.Server.Guardian
|
|||||||
_container.Insert(guardian, hostComponent.GuardianContainer);
|
_container.Insert(guardian, hostComponent.GuardianContainer);
|
||||||
DebugTools.Assert(hostComponent.GuardianContainer.Contains(guardian));
|
DebugTools.Assert(hostComponent.GuardianContainer.Contains(guardian));
|
||||||
_popupSystem.PopupEntity(Loc.GetString("guardian-entity-recall"), host);
|
_popupSystem.PopupEntity(Loc.GetString("guardian-entity-recall"), host);
|
||||||
|
if (guardianComponent.IsInPowerMode)
|
||||||
|
{
|
||||||
|
if (guardianComponent.GuardianType == GuardianSelector.Assasin)
|
||||||
|
{
|
||||||
|
SetupPower(guardian, guardianComponent, guardianComponent.GuardianType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
guardianComponent.IsInPowerMode = false;
|
||||||
|
if (guardianComponent.PowerToggleActionEntity != null)
|
||||||
|
{
|
||||||
|
_actionSystem.SetToggled(guardianComponent.PowerToggleActionEntity, guardianComponent.IsInPowerMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
guardianComponent.GuardianLoose = false;
|
guardianComponent.GuardianLoose = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public sealed class PoshelnahuiCommand : IConsoleCommand
|
|||||||
public string Command => "poshelnahui";
|
public string Command => "poshelnahui";
|
||||||
public string Description => "Close client game lol";
|
public string Description => "Close client game lol";
|
||||||
public string Help => "poshelnahui <ckey>";
|
public string Help => "poshelnahui <ckey>";
|
||||||
private readonly List<string> _vip = ["Valtos", "SamsungS", "Dosharus", "BIG_Zi_348"];
|
private readonly List<string> _vip = ["Valtos", "SamsungS", "Dosharus", "CaypenNow"];
|
||||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
{
|
{
|
||||||
if (args.Length != 1 || string.IsNullOrEmpty(args[0]))
|
if (args.Length != 1 || string.IsNullOrEmpty(args[0]))
|
||||||
|
|||||||
@@ -157,6 +157,8 @@ public partial class CultSystem
|
|||||||
_statusEffectsSystem.TryAddStatusEffect<IncorporealComponent>(ev.Performer, ev.StatusEffectId,
|
_statusEffectsSystem.TryAddStatusEffect<IncorporealComponent>(ev.Performer, ev.StatusEffectId,
|
||||||
TimeSpan.FromSeconds(ev.Duration), false);
|
TimeSpan.FromSeconds(ev.Duration), false);
|
||||||
|
|
||||||
|
Spawn("EffectEmpPulse", Transform(ev.Performer).Coordinates);
|
||||||
|
|
||||||
ev.Handled = true;
|
ev.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ namespace Content.Server._White.IncorporealSystem;
|
|||||||
public sealed partial class IncorporealComponent : Component
|
public sealed partial class IncorporealComponent : Component
|
||||||
{
|
{
|
||||||
[DataField] public float MovementSpeedBuff = 1.5f;
|
[DataField] public float MovementSpeedBuff = 1.5f;
|
||||||
|
[DataField] public bool Effect = true;
|
||||||
|
|
||||||
[DataField] public int CollisionMask = (int) CollisionGroup.GhostImpassable;
|
[DataField] public int CollisionMask = (int) CollisionGroup.GhostImpassable;
|
||||||
[DataField] public int CollisionLayer = 0;
|
[DataField] public int CollisionLayer = 0;
|
||||||
|
|
||||||
public int StoredMask;
|
public int StoredMask;
|
||||||
public int StoredLayer;
|
public int StoredLayer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,6 @@ public sealed class IncorporealSystem : EntitySystem
|
|||||||
_visibilitySystem.RefreshVisibility(uid);
|
_visibilitySystem.RefreshVisibility(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Spawn("EffectEmpPulse", Transform(uid).Coordinates);
|
|
||||||
EnsureComp<StealthComponent>(uid);
|
EnsureComp<StealthComponent>(uid);
|
||||||
_stealth.SetVisibility(uid, -1);
|
_stealth.SetVisibility(uid, -1);
|
||||||
if (TryComp(uid, out PullableComponent? pullable))
|
if (TryComp(uid, out PullableComponent? pullable))
|
||||||
@@ -79,7 +78,12 @@ public sealed class IncorporealSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
component.MovementSpeedBuff = 1;
|
component.MovementSpeedBuff = 1;
|
||||||
Spawn("EffectEmpPulse", _transform.GetMapCoordinates(uid));
|
|
||||||
|
if (component.Effect)
|
||||||
|
{
|
||||||
|
Spawn("EffectEmpPulse", _transform.GetMapCoordinates(uid));
|
||||||
|
}
|
||||||
|
|
||||||
_stealth.SetVisibility(uid, 1);
|
_stealth.SetVisibility(uid, 1);
|
||||||
RemComp<StealthComponent>(uid);
|
RemComp<StealthComponent>(uid);
|
||||||
_movement.RefreshMovementSpeedModifiers(uid);
|
_movement.RefreshMovementSpeedModifiers(uid);
|
||||||
|
|||||||
@@ -404,6 +404,8 @@ public sealed class WizardSpellsSystem : EntitySystem
|
|||||||
_statusEffectsSystem.TryAddStatusEffect<IncorporealComponent>(msg.Performer, "Incorporeal",
|
_statusEffectsSystem.TryAddStatusEffect<IncorporealComponent>(msg.Performer, "Incorporeal",
|
||||||
TimeSpan.FromSeconds(10), false);
|
TimeSpan.FromSeconds(10), false);
|
||||||
|
|
||||||
|
Spawn("EffectEmpPulse", Transform(msg.Performer).Coordinates);
|
||||||
|
|
||||||
Cast(msg);
|
Cast(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
49
Content.Shared/Guardian/GuardianCreatorComponent.cs
Normal file
49
Content.Shared/Guardian/GuardianCreatorComponent.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using Content.Shared._White.Guardian;
|
||||||
|
using Robust.Shared.GameStates;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
|
namespace Content.Shared.Guardian
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a GuardianComponent attached to the user's GuardianHost.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed partial class GuardianCreatorComponent : Component
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Counts as spent upon exhausting the injection
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// We don't mark as deleted as examine depends on this.
|
||||||
|
/// </remarks>
|
||||||
|
[DataField]
|
||||||
|
public bool Used = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The prototype of the guardian entity which will be created
|
||||||
|
/// </summary>
|
||||||
|
[DataField("guardianProto",
|
||||||
|
customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>),
|
||||||
|
required: true)]
|
||||||
|
public string GuardianProto;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How long it takes to inject someone.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("delay")]
|
||||||
|
public float InjectionDelay = 5f;
|
||||||
|
|
||||||
|
[DataField("guardiansAvaliable")]
|
||||||
|
public IReadOnlyCollection<string> GuardiansAvaliable = ArraySegment<string>.Empty;
|
||||||
|
|
||||||
|
[DataField]
|
||||||
|
public Dictionary<GuardianSelector, string> GuardianSelectorToProto = new()
|
||||||
|
{
|
||||||
|
{ GuardianSelector.Assasin, "MobHoloparasiteGuardianAssasin" },
|
||||||
|
{ GuardianSelector.Standart, "MobHoloparasiteGuardianStandart" },
|
||||||
|
{ GuardianSelector.Charger, "MobHoloparasiteGuardianCharger" },
|
||||||
|
{ GuardianSelector.Lighting, "MobHoloparasiteGuardianLighting" }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.DoAfter;
|
using Content.Shared._White.Guardian;
|
||||||
|
using Content.Shared.DoAfter;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
namespace Content.Shared.Guardian;
|
namespace Content.Shared.Guardian;
|
||||||
@@ -6,4 +7,5 @@ namespace Content.Shared.Guardian;
|
|||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed partial class GuardianCreatorDoAfterEvent : SimpleDoAfterEvent
|
public sealed partial class GuardianCreatorDoAfterEvent : SimpleDoAfterEvent
|
||||||
{
|
{
|
||||||
|
public GuardianSelector SelectedType; // Parsec Edit
|
||||||
}
|
}
|
||||||
|
|||||||
53
Content.Shared/_White/Guardian/GuardianEvents.cs
Normal file
53
Content.Shared/_White/Guardian/GuardianEvents.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using Content.Shared.Actions;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared._White.Guardian;
|
||||||
|
|
||||||
|
public enum GuardianSelector : byte
|
||||||
|
{
|
||||||
|
Assasin,
|
||||||
|
Standart,
|
||||||
|
Charger,
|
||||||
|
Lighting
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum GuardianSelectorUiKey : byte
|
||||||
|
{
|
||||||
|
Key
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class GuardianSelectorBUIState : BoundUserInterfaceState
|
||||||
|
{
|
||||||
|
public IReadOnlyCollection<string> Ids { get; set; }
|
||||||
|
|
||||||
|
public NetEntity Target { get; set; }
|
||||||
|
|
||||||
|
public GuardianSelectorBUIState(IReadOnlyCollection<string> ids, NetEntity target)
|
||||||
|
{
|
||||||
|
Ids = ids;
|
||||||
|
Target = target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class GuardianSelectorSelectedBuiMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public GuardianSelector GuardianType;
|
||||||
|
public NetEntity Target;
|
||||||
|
|
||||||
|
public GuardianSelectorSelectedBuiMessage(GuardianSelector guardianType, NetEntity target)
|
||||||
|
{
|
||||||
|
GuardianType = guardianType;
|
||||||
|
Target = target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed partial class ToggleGuardianPowerActionEvent : InstantActionEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed partial class ChargerPowerActionEvent : InstantActionEvent
|
||||||
|
{
|
||||||
|
}
|
||||||
BIN
Resources/Audio/White/Guardian/charger.ogg
Normal file
BIN
Resources/Audio/White/Guardian/charger.ogg
Normal file
Binary file not shown.
@@ -1,16 +1,4 @@
|
|||||||
Entries:
|
Entries:
|
||||||
- author: Aviu
|
|
||||||
changes:
|
|
||||||
- message: "\u0411\u0417 \u0442\u0435\u043F\u0435\u0440\u044C \u0443\u0441\u044B\
|
|
||||||
\u043F\u043B\u044F\u0435\u0442 \u0433\u0435\u043D\u043E\u043A\u0440\u0430\u0434\
|
|
||||||
\u043E\u0432."
|
|
||||||
type: Add
|
|
||||||
- message: "\u041D\u0438\u0442\u0440\u0438\u0443\u043C \u0441\u043D\u043E\u0432\u0430\
|
|
||||||
\ \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442."
|
|
||||||
type: Fix
|
|
||||||
id: 178
|
|
||||||
time: '2024-03-03T08:09:04.0000000+00:00'
|
|
||||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/167
|
|
||||||
- author: ThereDrD
|
- author: ThereDrD
|
||||||
changes:
|
changes:
|
||||||
- message: "\u0424\u0438\u043A\u0441 \u043F\u0443\u0441\u0442\u044B\u0445 \u0441\
|
- message: "\u0424\u0438\u043A\u0441 \u043F\u0443\u0441\u0442\u044B\u0445 \u0441\
|
||||||
@@ -9078,3 +9066,45 @@
|
|||||||
id: 677
|
id: 677
|
||||||
time: '2025-04-13T16:14:06.0000000+00:00'
|
time: '2025-04-13T16:14:06.0000000+00:00'
|
||||||
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/947
|
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/947
|
||||||
|
- author: CaypenNow
|
||||||
|
changes:
|
||||||
|
- message: "\u0413\u043E\u043B\u043E\u043F\u0430\u0440\u0430\u0437\u0438\u0442\u044B\
|
||||||
|
\ \u043F\u043E\u043B\u0443\u0447\u0438\u043B\u0438 \u043F\u043E\u043B\u043D\u043E\
|
||||||
|
\u0435 \u043E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435. \u0422\u0435\
|
||||||
|
\u043F\u0435\u0440\u044C, \u043F\u0440\u0438 \u0438\u043C\u043F\u043B\u0430\u043D\
|
||||||
|
\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0438 \u0433\u043E\u043B\u043E\
|
||||||
|
\u043F\u0430\u0440\u0430\u0437\u0438\u0442\u0430, \u0435\u0441\u0442\u044C \u0432\
|
||||||
|
\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u044C \u0432\u044B\u0431\
|
||||||
|
\u0440\u0430\u0442\u044C \u043E\u0434\u0438\u043D \u0438\u0437 4 \u043A\u043B\
|
||||||
|
\u0430\u0441\u0441\u043E\u0432. \u041A\u0430\u0436\u0434\u044B\u0439 \u043A\u043B\
|
||||||
|
\u0430\u0441\u0441 \u0438\u043C\u0435\u0435\u0442 \u0440\u0430\u0437\u043B\u0438\
|
||||||
|
\u0447\u0438\u044F, \u0430 \u043D\u0435\u043A\u043E\u0442\u043E\u0440\u044B\u0435\
|
||||||
|
\ \u0438 \u0441\u043E\u0431\u0441\u0442\u0432\u0435\u043D\u043D\u044B\u0435\
|
||||||
|
\ \u0441\u043F\u043E\u0441\u043E\u0431\u043D\u043E\u0441\u0442\u0438."
|
||||||
|
type: Add
|
||||||
|
- message: "\u0413\u043E\u043B\u043E\u043F\u0430\u0440\u0430\u0437\u0438\u0442 \u043F\
|
||||||
|
\u043E\u043B\u0443\u0447\u0438\u043B \u043D\u043E\u0432\u044B\u0439 \u0441\u043F\
|
||||||
|
\u0440\u0430\u0439\u0442"
|
||||||
|
type: Add
|
||||||
|
- message: "\u0422\u0435\u043F\u0435\u0440\u044C \u0433\u043E\u043B\u043E\u043F\u0430\
|
||||||
|
\u0440\u0430\u0437\u0438\u0442 \u043C\u043E\u0436\u0435\u0442 \u0432\u044B\u0445\
|
||||||
|
\u043E\u0434\u0438\u0442\u044C \u0438\u0437 \u0442\u0435\u043B\u0430 \u0441\u0430\
|
||||||
|
\u043C"
|
||||||
|
type: Tweak
|
||||||
|
- message: "\u0422\u0435\u043F\u0435\u0440\u044C \u0433\u043E\u043B\u043E\u043F\u0430\
|
||||||
|
\u0440\u0430\u0437\u0438\u0442 \u043C\u043E\u0436\u0435\u0442 \u0442\u0430\u0441\
|
||||||
|
\u043A\u0430\u0442\u044C \u0432\u0435\u0449\u0438\u0442\u044C"
|
||||||
|
type: Tweak
|
||||||
|
- message: "\u0422\u0435\u043F\u0435\u0440\u044C \u0446\u0432\u0435\u0442 \u0433\
|
||||||
|
\u043E\u043B\u043E\u043F\u0430\u0440\u0430\u0437\u0438\u0442\u0430 - \u0443\u043D\
|
||||||
|
\u0438\u043A\u0430\u043B\u044C\u043D\u044B\u0439 \u0434\u043B\u044F \u043A\u043B\
|
||||||
|
\u0430\u0441\u0441\u0430, \u0430 \u043D\u0435 \u043F\u0440\u043E\u0441\u0442\
|
||||||
|
\u043E \u0440\u0430\u043D\u0434\u043E\u043C\u043D\u044B\u0439."
|
||||||
|
type: Tweak
|
||||||
|
- message: "\u0426\u0435\u043D\u0430 \u0433\u043E\u043B\u043E\u043F\u0430\u0440\u0430\
|
||||||
|
\u0437\u0438\u0442\u0430 \u043F\u043E\u0432\u044B\u0448\u0435\u043D\u0430. 12\
|
||||||
|
\ \u0422\u041A --> 13 \u0422\u041A"
|
||||||
|
type: Tweak
|
||||||
|
id: 678
|
||||||
|
time: '2025-04-18T03:18:09.0000000+00:00'
|
||||||
|
url: https://api.github.com/repos/frosty-dev/ss14-core/pulls/948
|
||||||
|
|||||||
4
Resources/Locale/ru-RU/_white/guardian/guardian.ftl
Normal file
4
Resources/Locale/ru-RU/_white/guardian/guardian.ftl
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
guardian-assasin-name = Ассасин
|
||||||
|
guardian-lighting-name = Молниеносный
|
||||||
|
guardian-charger-name = Быстрый
|
||||||
|
guardian-standart-name = Классический
|
||||||
@@ -922,7 +922,7 @@
|
|||||||
icon: { sprite: /Textures/Objects/Misc/guardian_info.rsi, state: icon }
|
icon: { sprite: /Textures/Objects/Misc/guardian_info.rsi, state: icon }
|
||||||
productEntity: BoxHoloparasite
|
productEntity: BoxHoloparasite
|
||||||
cost:
|
cost:
|
||||||
Telecrystal: 12
|
Telecrystal: 13
|
||||||
categories:
|
categories:
|
||||||
- UplinkAllies
|
- UplinkAllies
|
||||||
conditions:
|
conditions:
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
context: "human"
|
context: "human"
|
||||||
- type: MobMover
|
- type: MobMover
|
||||||
- type: InputMover
|
- type: InputMover
|
||||||
|
- type: Puller
|
||||||
- type: MovementSpeedModifier
|
- type: MovementSpeedModifier
|
||||||
baseWalkSpeed: 4
|
baseWalkSpeed: 4
|
||||||
baseSprintSpeed: 5.5
|
baseSprintSpeed: 5.5
|
||||||
@@ -29,20 +30,6 @@
|
|||||||
Blunt: 5
|
Blunt: 5
|
||||||
soundHit:
|
soundHit:
|
||||||
collection: MetalThud
|
collection: MetalThud
|
||||||
- type: RandomSprite
|
|
||||||
available:
|
|
||||||
- enum.DamageStateVisualLayers.Base:
|
|
||||||
magic_base: ""
|
|
||||||
enum.DamageStateVisualLayers.BaseUnshaded:
|
|
||||||
magic_flare: Sixteen
|
|
||||||
- enum.DamageStateVisualLayers.Base:
|
|
||||||
miner_base: ""
|
|
||||||
enum.DamageStateVisualLayers.BaseUnshaded:
|
|
||||||
miner_flare: Sixteen
|
|
||||||
- enum.DamageStateVisualLayers.Base:
|
|
||||||
tech_base: ""
|
|
||||||
enum.DamageStateVisualLayers.BaseUnshaded:
|
|
||||||
tech_flare: Sixteen
|
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
drawdepth: Mobs
|
drawdepth: Mobs
|
||||||
sprite: White/Mobs/Aliens/Guardians/guardians.rsi
|
sprite: White/Mobs/Aliens/Guardians/guardians.rsi
|
||||||
@@ -112,8 +99,8 @@
|
|||||||
|
|
||||||
# From the uplink injector
|
# From the uplink injector
|
||||||
- type: entity
|
- type: entity
|
||||||
name: Holoparasite
|
name: HoloparasiteStandart
|
||||||
id: MobHoloparasiteGuardian
|
id: MobHoloparasiteGuardianStandart
|
||||||
parent: MobGuardianBase
|
parent: MobGuardianBase
|
||||||
description: A mesmerising whirl of hard-light patterns weaves a marvelous, yet oddly familiar visage. It stands proud, tuning into its owner's life to sustain itself.
|
description: A mesmerising whirl of hard-light patterns weaves a marvelous, yet oddly familiar visage. It stands proud, tuning into its owner's life to sustain itself.
|
||||||
components:
|
components:
|
||||||
@@ -126,22 +113,208 @@
|
|||||||
raffle:
|
raffle:
|
||||||
settings: default
|
settings: default
|
||||||
- type: GhostTakeoverAvailable
|
- type: GhostTakeoverAvailable
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: Mobs
|
||||||
|
sprite: White/Mobs/Aliens/Guardians/guardians.rsi
|
||||||
|
layers:
|
||||||
|
- state: tech_base
|
||||||
|
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||||
|
- state: tech_flare
|
||||||
|
map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||||
|
color: "#707070"
|
||||||
|
shader: unshaded
|
||||||
|
noRot: true
|
||||||
|
- type: Guardian
|
||||||
|
damageShare: 0.5
|
||||||
|
distance: 6
|
||||||
|
- type: MovementSpeedModifier
|
||||||
|
baseWalkSpeed: 4.5
|
||||||
|
baseSprintSpeed: 6
|
||||||
|
- type: DamageOnHighSpeedImpact
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Blunt: 5
|
||||||
|
soundHit:
|
||||||
|
collection: MetalThud
|
||||||
|
- type: MeleeWeapon
|
||||||
|
hidden: false
|
||||||
|
altDisarm: false
|
||||||
|
animation: WeaponArcFist
|
||||||
|
attackRate: 2.2
|
||||||
|
autoAttack: true
|
||||||
|
soundHit:
|
||||||
|
collection: Punch
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Blunt: 24
|
||||||
|
Structural: 24
|
||||||
- type: NameIdentifier
|
- type: NameIdentifier
|
||||||
group: Holoparasite
|
group: Holoparasite
|
||||||
- type: TypingIndicator
|
- type: TypingIndicator
|
||||||
proto: holo
|
proto: holo
|
||||||
- type: Sprite
|
|
||||||
layers:
|
|
||||||
- state: tech_base
|
|
||||||
map: [ "enum.DamageStateVisualLayers.Base" ]
|
|
||||||
- state: tech_flare
|
|
||||||
map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
|
||||||
color: "#40a7d7"
|
|
||||||
shader: unshaded
|
|
||||||
- type: HTN
|
- type: HTN
|
||||||
rootTask:
|
rootTask:
|
||||||
task: SimpleHumanoidHostileCompound
|
task: SimpleHumanoidHostileCompound
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: HoloparasiteAssasin
|
||||||
|
id: MobHoloparasiteGuardianAssasin
|
||||||
|
parent: MobGuardianBase
|
||||||
|
description: A mesmerising whirl of hard-light patterns weaves a marvelous, yet oddly familiar visage. It stands proud, tuning into its owner's life to sustain itself.
|
||||||
|
components:
|
||||||
|
- type: GhostRole
|
||||||
|
allowMovement: true
|
||||||
|
allowSpeech: true
|
||||||
|
makeSentient: true
|
||||||
|
name: ghost-role-information-holoparasite-name
|
||||||
|
description: ghost-role-information-holoparasite-description
|
||||||
|
raffle:
|
||||||
|
settings: default
|
||||||
|
- type: GhostTakeoverAvailable
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: Mobs
|
||||||
|
sprite: White/Mobs/Aliens/Guardians/guardians.rsi
|
||||||
|
layers:
|
||||||
|
- state: tech_base
|
||||||
|
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||||
|
- state: tech_flare
|
||||||
|
map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||||
|
color: "#9d0016"
|
||||||
|
shader: unshaded
|
||||||
|
noRot: true
|
||||||
|
- type: Guardian
|
||||||
|
damageShare: 1
|
||||||
|
distance: 10
|
||||||
|
- type: MovementSpeedModifier
|
||||||
|
baseWalkSpeed: 4
|
||||||
|
baseSprintSpeed: 5.5
|
||||||
|
- type: DamageOnHighSpeedImpact
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Blunt: 5
|
||||||
|
soundHit:
|
||||||
|
collection: MetalThud
|
||||||
|
- type: MeleeWeapon
|
||||||
|
hidden: false
|
||||||
|
altDisarm: false
|
||||||
|
animation: WeaponArcFist
|
||||||
|
attackRate: 2
|
||||||
|
autoAttack: true
|
||||||
|
soundHit:
|
||||||
|
collection: Punch
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Blunt: 14
|
||||||
|
Structural: 14
|
||||||
|
- type: NameIdentifier
|
||||||
|
group: Holoparasite
|
||||||
|
- type: TypingIndicator
|
||||||
|
proto: holo
|
||||||
|
- type: HTN
|
||||||
|
rootTask:
|
||||||
|
task: SimpleHumanoidHostileCompound
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: HoloparasiteCharger
|
||||||
|
id: MobHoloparasiteGuardianCharger
|
||||||
|
parent: MobGuardianBase
|
||||||
|
description: A mesmerising whirl of hard-light patterns weaves a marvelous, yet oddly familiar visage. It stands proud, tuning into its owner's life to sustain itself.
|
||||||
|
components:
|
||||||
|
- type: GhostRole
|
||||||
|
allowMovement: true
|
||||||
|
allowSpeech: true
|
||||||
|
makeSentient: true
|
||||||
|
name: ghost-role-information-holoparasite-name
|
||||||
|
description: ghost-role-information-holoparasite-description
|
||||||
|
raffle:
|
||||||
|
settings: default
|
||||||
|
- type: GhostTakeoverAvailable
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: Mobs
|
||||||
|
sprite: White/Mobs/Aliens/Guardians/guardians.rsi
|
||||||
|
layers:
|
||||||
|
- state: tech_base
|
||||||
|
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||||
|
- state: tech_flare
|
||||||
|
map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||||
|
color: "#54f3ff"
|
||||||
|
shader: unshaded
|
||||||
|
noRot: true
|
||||||
|
- type: MovementSpeedModifier
|
||||||
|
baseWalkSpeed: 6
|
||||||
|
baseSprintSpeed: 7.5
|
||||||
|
- type: DamageOnHighSpeedImpact
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Blunt: 5
|
||||||
|
soundHit:
|
||||||
|
collection: MetalThud
|
||||||
|
- type: MeleeWeapon
|
||||||
|
hidden: false
|
||||||
|
altDisarm: false
|
||||||
|
animation: WeaponArcFist
|
||||||
|
attackRate: 2.5
|
||||||
|
autoAttack: true
|
||||||
|
soundHit:
|
||||||
|
collection: Punch
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Blunt: 15
|
||||||
|
Structural: 15
|
||||||
|
- type: NameIdentifier
|
||||||
|
group: Holoparasite
|
||||||
|
- type: TypingIndicator
|
||||||
|
proto: holo
|
||||||
|
- type: HTN
|
||||||
|
rootTask:
|
||||||
|
task: SimpleHumanoidHostileCompound
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
name: HoloparasiteLighting
|
||||||
|
id: MobHoloparasiteGuardianLighting
|
||||||
|
parent: MobGuardianBase
|
||||||
|
description: A mesmerising whirl of hard-light patterns weaves a marvelous, yet oddly familiar visage. It stands proud, tuning into its owner's life to sustain itself.
|
||||||
|
components:
|
||||||
|
- type: GhostRole
|
||||||
|
allowMovement: true
|
||||||
|
allowSpeech: true
|
||||||
|
makeSentient: true
|
||||||
|
name: ghost-role-information-holoparasite-name
|
||||||
|
description: ghost-role-information-holoparasite-description
|
||||||
|
raffle:
|
||||||
|
settings: default
|
||||||
|
- type: GhostTakeoverAvailable
|
||||||
|
- type: Sprite
|
||||||
|
drawdepth: Mobs
|
||||||
|
sprite: White/Mobs/Aliens/Guardians/guardians.rsi
|
||||||
|
layers:
|
||||||
|
- state: tech_base
|
||||||
|
map: [ "enum.DamageStateVisualLayers.Base" ]
|
||||||
|
- state: tech_flare
|
||||||
|
map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
|
||||||
|
color: "#2000c8"
|
||||||
|
shader: unshaded
|
||||||
|
noRot: true
|
||||||
|
- type: MeleeWeapon
|
||||||
|
hidden: false
|
||||||
|
altDisarm: false
|
||||||
|
animation: WeaponArcFist
|
||||||
|
attackRate: 1.8
|
||||||
|
autoAttack: true
|
||||||
|
soundHit:
|
||||||
|
collection: Punch
|
||||||
|
damage:
|
||||||
|
types:
|
||||||
|
Blunt: 5
|
||||||
|
Structural: 5
|
||||||
|
- type: NameIdentifier
|
||||||
|
group: Holoparasite
|
||||||
|
- type: TypingIndicator
|
||||||
|
proto: holo
|
||||||
|
- type: HTN
|
||||||
|
rootTask:
|
||||||
|
task: SimpleHumanoidHostileCompound
|
||||||
|
|
||||||
# From Wizard deck of cards
|
# From Wizard deck of cards
|
||||||
- type: entity
|
- type: entity
|
||||||
name: Ifrit
|
name: Ifrit
|
||||||
|
|||||||
@@ -9,6 +9,15 @@
|
|||||||
state: combat_hypo
|
state: combat_hypo
|
||||||
- type: GuardianCreator
|
- type: GuardianCreator
|
||||||
guardianProto: MobHoloparasiteGuardian
|
guardianProto: MobHoloparasiteGuardian
|
||||||
|
guardiansAvaliable:
|
||||||
|
- Assasin
|
||||||
|
- Charger
|
||||||
|
- Standart
|
||||||
|
- Lighting
|
||||||
|
- type: UserInterface # PARSEC EDIT
|
||||||
|
interfaces:
|
||||||
|
enum.GuardianSelectorUiKey.Key:
|
||||||
|
type: GuardianSelectorBUI
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: holoclown injector
|
name: holoclown injector
|
||||||
|
|||||||
36
Resources/Prototypes/_White/Actions/guardian.yml
Normal file
36
Resources/Prototypes/_White/Actions/guardian.yml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
- type: entity
|
||||||
|
id: ActionGuardianPowerToggle
|
||||||
|
name: "[color=green]Сила голопаразита[/color]"
|
||||||
|
description: Уникальная способность голопаразита.
|
||||||
|
noSpawn: true
|
||||||
|
components:
|
||||||
|
- type: InstantAction
|
||||||
|
checkCanInteract: false
|
||||||
|
checkConsciousness: false
|
||||||
|
icon: White/Interface/Guardian/powerOff.png
|
||||||
|
iconOn: White/Interface/Guardian/power.png
|
||||||
|
event: !type:ToggleGuardianPowerActionEvent
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ActionGuardianPowerOff
|
||||||
|
parent: ActionCombatModeToggle
|
||||||
|
name: "[color=red]Сила голопаразита[/color]"
|
||||||
|
description: Уникальная способность голопаразита.
|
||||||
|
noSpawn: true
|
||||||
|
components:
|
||||||
|
- type: InstantAction
|
||||||
|
enabled: false
|
||||||
|
autoPopulate: false
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ActionChargerPower
|
||||||
|
name: "[color=green]Сила голопаразита[/color]"
|
||||||
|
description: Уникальная способность голопаразита, позволяет зарядить ваш кулак и одним ударом поразить цель.
|
||||||
|
noSpawn: true
|
||||||
|
components:
|
||||||
|
- type: InstantAction
|
||||||
|
useDelay: 4
|
||||||
|
checkCanInteract: false
|
||||||
|
checkConsciousness: false
|
||||||
|
icon: White/Interface/Guardian/powerOff.png
|
||||||
|
event: !type:ChargerPowerActionEvent
|
||||||
BIN
Resources/Textures/White/Interface/Guardian/power.png
Normal file
BIN
Resources/Textures/White/Interface/Guardian/power.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Resources/Textures/White/Interface/Guardian/powerOff.png
Normal file
BIN
Resources/Textures/White/Interface/Guardian/powerOff.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 297 B |
Binary file not shown.
|
After Width: | Height: | Size: 276 B |
Binary file not shown.
|
After Width: | Height: | Size: 252 B |
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"license": "CC-BY-SA-3.0",
|
||||||
|
"copyright": "https://github.com/tgstation/tgstation/blob/master/icons/hud/guardian.dmi",
|
||||||
|
"version": 1,
|
||||||
|
"size": { "y": 32, "x": 32 },
|
||||||
|
"states": [
|
||||||
|
{
|
||||||
|
"name": "charger"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lighting"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "assasin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "standart"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 268 B |
Reference in New Issue
Block a user