Spellblade update (#346)
* - tweak: Don't close eui too quickly. * - add: Spellblade update. * - fix: Cult teleport spell.
This commit is contained in:
@@ -3,23 +3,19 @@ using Content.Client._White.Cult.UI.TeleportRunesList;
|
||||
using Content.Client.Eui;
|
||||
using Content.Shared.Eui;
|
||||
using Content.Shared._White.Cult.UI;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace Content.Client._White.Cult.UI.TeleportSpell;
|
||||
|
||||
public sealed class TeleportSpellEui : BaseEui
|
||||
[UsedImplicitly]
|
||||
public sealed class CultTeleportSpellEui : BaseEui
|
||||
{
|
||||
|
||||
private TeleportRunesListWindow _window;
|
||||
|
||||
public TeleportSpellEui()
|
||||
{
|
||||
_window = new TeleportRunesListWindow();
|
||||
}
|
||||
private readonly TeleportRunesListWindow _window = new();
|
||||
|
||||
public override void Opened()
|
||||
{
|
||||
_window.OpenCentered();
|
||||
_window.ItemSelected += (index, _) => SendMessage(new TeleportSpellTargetRuneSelected(){RuneUid = index});
|
||||
_window.ItemSelected += (index, _) => SendMessage(new TeleportSpellTargetRuneSelected {RuneUid = index});
|
||||
_window.OnClose += () => SendMessage(new CloseEuiMessage());
|
||||
|
||||
base.Opened();
|
||||
@@ -33,7 +29,8 @@ public sealed class TeleportSpellEui : BaseEui
|
||||
|
||||
public override void HandleState(EuiStateBase state)
|
||||
{
|
||||
if(state is not TeleportSpellEuiState cast) return;
|
||||
if (state is not CultTeleportSpellEuiState cast)
|
||||
return;
|
||||
|
||||
_window.Clear();
|
||||
_window.PopulateList(cast.Runes.Keys.ToList(), cast.Runes.Values.ToList());
|
||||
57
Content.Client/_White/Wizard/SpellBlade/SpellBladeBUI.cs
Normal file
57
Content.Client/_White/Wizard/SpellBlade/SpellBladeBUI.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using Content.Client._White.UserInterface.Radial;
|
||||
using Content.Shared._White.Wizard.SpellBlade;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._White.Wizard.SpellBlade;
|
||||
|
||||
[UsedImplicitly]
|
||||
// ReSharper disable once InconsistentNaming
|
||||
public sealed class SpellBladeBUI(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
|
||||
private RadialContainer? _aspectSelector;
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
if (!_entityManager.TryGetComponent(Owner, out SpellBladeComponent? spellBlade) ||
|
||||
spellBlade.ChosenAspect != string.Empty)
|
||||
return;
|
||||
|
||||
var spriteSystem = _entityManager.System<SpriteSystem>();
|
||||
_aspectSelector = new RadialContainer();
|
||||
|
||||
_aspectSelector.Closed += Close;
|
||||
|
||||
foreach (var aspect in spellBlade.Aspects)
|
||||
{
|
||||
if (!_prototypeManager.TryIndex(aspect, out var proto))
|
||||
continue;
|
||||
|
||||
var button = _aspectSelector.AddButton(proto.Name,
|
||||
spriteSystem.GetPrototypeIcon(proto).Default);
|
||||
button.Tooltip = proto.Description;
|
||||
|
||||
button.Controller.OnPressed += _ =>
|
||||
{
|
||||
SendMessage(new SpellBladeSystemMessage(aspect));
|
||||
_aspectSelector.Close();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
_aspectSelector.OpenAttachedLocalPlayer();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
|
||||
_aspectSelector?.Close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using Content.Shared._White.Wizard.SpellBlade;
|
||||
|
||||
namespace Content.Client._White.Wizard.SpellBlade;
|
||||
|
||||
public sealed class SpellBladeSystem : SharedSpellBladeSystem
|
||||
{
|
||||
}
|
||||
@@ -8,7 +8,7 @@ using JetBrains.Annotations;
|
||||
namespace Content.Client._White.Wizard.TeleportSpell;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class TeleportSpellEui : BaseEui
|
||||
public sealed class WizardTeleportSpellEui : BaseEui
|
||||
{
|
||||
private readonly TeleportRunesListWindow _window = new();
|
||||
|
||||
@@ -30,7 +30,7 @@ public sealed class TeleportSpellEui : BaseEui
|
||||
|
||||
public override void HandleState(EuiStateBase state)
|
||||
{
|
||||
if (state is not TeleportSpellEuiState cast)
|
||||
if (state is not WizardTeleportSpellEuiState cast)
|
||||
return;
|
||||
|
||||
_window.Clear();
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Server._White.Wizard.SpellBlade;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.IgnitionSource;
|
||||
@@ -49,6 +50,7 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SpellBladeSystem _spellBlade = default!; // WD
|
||||
|
||||
public const float MinimumFireStacks = -10f;
|
||||
public const float MaximumFireStacks = 20f;
|
||||
@@ -84,13 +86,19 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
|
||||
private void OnMeleeHit(EntityUid uid, IgniteOnMeleeHitComponent component, MeleeHitEvent args)
|
||||
{
|
||||
// WD START
|
||||
var fireStacks = component.FireStacks;
|
||||
if (args.Direction != null) // Heavy attack
|
||||
fireStacks *= 0.5f;
|
||||
// WD END
|
||||
|
||||
foreach (var entity in args.HitEntities)
|
||||
{
|
||||
if (!TryComp<FlammableComponent>(entity, out var flammable))
|
||||
continue;
|
||||
|
||||
AdjustFireStacks(entity, component.FireStacks, flammable);
|
||||
if (component.FireStacks >= 0)
|
||||
AdjustFireStacks(entity, fireStacks, flammable); // WD EDIT
|
||||
if (fireStacks >= 0) // WD EDIT
|
||||
Ignite(entity, args.Weapon, flammable, args.User);
|
||||
}
|
||||
}
|
||||
@@ -203,8 +211,15 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
if (!flammable.OnFire && !otherFlammable.OnFire)
|
||||
return; // Neither are on fire
|
||||
|
||||
// WD START
|
||||
var weHold = _spellBlade.IsHoldingItemWithComponent<FireAspectComponent>(uid);
|
||||
var theyHold = _spellBlade.IsHoldingItemWithComponent<FireAspectComponent>(otherUid);
|
||||
// WD END
|
||||
|
||||
if (flammable.OnFire && otherFlammable.OnFire)
|
||||
{
|
||||
if (weHold && !theyHold || theyHold && !weHold) // WD
|
||||
return;
|
||||
// Both are on fire -> equalize fire stacks.
|
||||
var avg = (flammable.FireStacks + otherFlammable.FireStacks) / 2;
|
||||
flammable.FireStacks = flammable.CanExtinguish ? avg : Math.Max(flammable.FireStacks, avg);
|
||||
@@ -217,6 +232,8 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
// Only one is on fire -> attempt to spread the fire.
|
||||
if (flammable.OnFire)
|
||||
{
|
||||
if (theyHold) // WD
|
||||
return;
|
||||
otherFlammable.FireStacks += flammable.FireStacks / 2;
|
||||
Ignite(otherUid, uid, otherFlammable);
|
||||
if (flammable.CanExtinguish)
|
||||
@@ -227,6 +244,8 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
}
|
||||
else
|
||||
{
|
||||
if (weHold) // WD
|
||||
return;
|
||||
flammable.FireStacks += otherFlammable.FireStacks / 2;
|
||||
Ignite(uid, otherUid, flammable);
|
||||
if (otherFlammable.CanExtinguish)
|
||||
@@ -436,7 +455,8 @@ namespace Content.Server.Atmos.EntitySystems
|
||||
if (TryComp(uid, out TemperatureComponent? temp))
|
||||
_temperatureSystem.ChangeHeat(uid, 12500 * damageScale, false, temp);
|
||||
|
||||
_damageableSystem.TryChangeDamage(uid, flammable.Damage * damageScale, interruptsDoAfters: false);
|
||||
if (!_spellBlade.IsHoldingItemWithComponent<FireAspectComponent>(uid)) // WD EDIT
|
||||
_damageableSystem.TryChangeDamage(uid, flammable.Damage * damageScale, interruptsDoAfters: false);
|
||||
|
||||
AdjustFireStacks(uid, flammable.FirestackFade * (flammable.Resisting ? 10f : 1f), flammable);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using Content.Server._White.Wizard.SpellBlade;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
@@ -22,6 +23,7 @@ public sealed class TemperatureSystem : EntitySystem
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphere = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly SpellBladeSystem _spellBlade = default!; // WD
|
||||
|
||||
/// <summary>
|
||||
/// All the components that will have their damage updated at the end of the tick.
|
||||
@@ -266,6 +268,17 @@ public sealed class TemperatureSystem : EntitySystem
|
||||
|
||||
if (temperature.CurrentTemperature >= heatDamageThreshold)
|
||||
{
|
||||
// WD START
|
||||
if (_spellBlade.IsHoldingItemWithComponent<FireAspectComponent>(uid))
|
||||
{
|
||||
if (!temperature.TakingDamage)
|
||||
return;
|
||||
_adminLogger.Add(LogType.Temperature,
|
||||
$"{ToPrettyString(uid):entity} stopped taking temperature damage");
|
||||
temperature.TakingDamage = false;
|
||||
return;
|
||||
}
|
||||
// WD END
|
||||
if (!temperature.TakingDamage)
|
||||
{
|
||||
_adminLogger.Add(LogType.Temperature, $"{ToPrettyString(uid):entity} started taking high temperature damage");
|
||||
@@ -278,7 +291,8 @@ public sealed class TemperatureSystem : EntitySystem
|
||||
}
|
||||
else if (temperature.CurrentTemperature <= coldDamageThreshold)
|
||||
{
|
||||
if (TryComp(uid, out VoidAdaptationComponent? voidAdaptation)) // WD
|
||||
// WD START
|
||||
if (TryComp(uid, out VoidAdaptationComponent? voidAdaptation))
|
||||
{
|
||||
if (temperature.TakingDamage)
|
||||
{
|
||||
@@ -291,6 +305,17 @@ public sealed class TemperatureSystem : EntitySystem
|
||||
return;
|
||||
}
|
||||
|
||||
if (_spellBlade.IsHoldingItemWithComponent<FrostAspectComponent>(uid))
|
||||
{
|
||||
if (!temperature.TakingDamage)
|
||||
return;
|
||||
_adminLogger.Add(LogType.Temperature,
|
||||
$"{ToPrettyString(uid):entity} stopped taking temperature damage");
|
||||
temperature.TakingDamage = false;
|
||||
return;
|
||||
}
|
||||
// WD END
|
||||
|
||||
if (!temperature.TakingDamage)
|
||||
{
|
||||
_adminLogger.Add(LogType.Temperature, $"{ToPrettyString(uid):entity} started taking low temperature damage");
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Server._White.Wizard.SpellBlade;
|
||||
using Content.Server.Temperature.Components;
|
||||
using Content.Server.Temperature.Systems;
|
||||
using Content.Shared.Changeling;
|
||||
@@ -10,6 +11,7 @@ namespace Content.Server._White.ChangeTemperatureOnCollide;
|
||||
public sealed class LowTemperatureSlowdownSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifierSystem = default!;
|
||||
[Dependency] private readonly SpellBladeSystem _spellBlade = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -22,7 +24,8 @@ public sealed class LowTemperatureSlowdownSystem : EntitySystem
|
||||
private void OnMoveSpeedRefresh(EntityUid uid, TemperatureComponent component,
|
||||
RefreshMovementSpeedModifiersEvent args)
|
||||
{
|
||||
var modifier = HasComp<GodmodeComponent>(uid) || HasComp<VoidAdaptationComponent>(uid) || !component.Slowdown
|
||||
var modifier = _spellBlade.IsHoldingItemWithComponent<FrostAspectComponent>(uid) ||
|
||||
HasComp<GodmodeComponent>(uid) || HasComp<VoidAdaptationComponent>(uid) || !component.Slowdown
|
||||
? 1f
|
||||
: GetSpeedModifier(component.CurrentTemperature);
|
||||
args.ModifySpeed(modifier, modifier);
|
||||
@@ -32,7 +35,7 @@ public sealed class LowTemperatureSlowdownSystem : EntitySystem
|
||||
OnTemperatureChangeEvent args)
|
||||
{
|
||||
// ReSharper disable once CompareOfFloatsByEqualityOperator
|
||||
if(GetSpeedModifier(args.LastTemperature) == GetSpeedModifier(args.CurrentTemperature))
|
||||
if (GetSpeedModifier(args.LastTemperature) == GetSpeedModifier(args.CurrentTemperature))
|
||||
return;
|
||||
|
||||
_movementSpeedModifierSystem.RefreshMovementSpeedModifiers(uid, component);
|
||||
|
||||
@@ -148,7 +148,7 @@ public partial class CultSystem
|
||||
|
||||
_bloodstreamSystem.TryModifyBloodLevel(uid, -5, bloodstream, createPuddle: false);
|
||||
|
||||
var eui = new TeleportSpellEui(args.Performer, args.Target);
|
||||
var eui = new CultTeleportSpellEui(args.Performer, args.Target);
|
||||
_euiManager.OpenEui(eui, actor.PlayerSession);
|
||||
eui.StateDirty();
|
||||
|
||||
|
||||
@@ -631,6 +631,18 @@ public sealed partial class CultSystem : EntitySystem
|
||||
}
|
||||
|
||||
private bool Teleport(EntityUid rune, EntityUid user, List<EntityUid>? victims = null)
|
||||
{
|
||||
if (!OpenTeleportUi(user, rune))
|
||||
return false;
|
||||
|
||||
_entityManager.EnsureComponent<CultTeleportRuneProviderComponent>(user, out var providerComponent);
|
||||
providerComponent.Targets = victims;
|
||||
providerComponent.BaseRune = rune;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool OpenTeleportUi(EntityUid user, EntityUid? exceptRune = null)
|
||||
{
|
||||
var runesQuery = EntityQueryEnumerator<CultRuneTeleportComponent>();
|
||||
var list = new List<int>();
|
||||
@@ -641,7 +653,7 @@ public sealed partial class CultSystem : EntitySystem
|
||||
if (teleportComponent.Label == null)
|
||||
continue;
|
||||
|
||||
if (runeUid == rune)
|
||||
if (runeUid == exceptRune)
|
||||
continue;
|
||||
|
||||
if (!int.TryParse(runeUid.ToString(), out var intValue))
|
||||
@@ -665,10 +677,6 @@ public sealed partial class CultSystem : EntitySystem
|
||||
return false;
|
||||
}
|
||||
|
||||
_entityManager.EnsureComponent<CultTeleportRuneProviderComponent>(user, out var providerComponent);
|
||||
providerComponent.Targets = victims;
|
||||
providerComponent.BaseRune = rune;
|
||||
|
||||
_ui.SetUiState(ui, new TeleportRunesListWindowBUIState(list, labels));
|
||||
|
||||
if (_ui.IsUiOpen(user, ui.UiKey))
|
||||
|
||||
@@ -10,7 +10,7 @@ using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._White.Cult.UI;
|
||||
|
||||
public sealed class TeleportSpellEui : BaseEui
|
||||
public sealed class CultTeleportSpellEui : BaseEui
|
||||
{
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
private readonly SharedTransformSystem _transformSystem;
|
||||
@@ -22,7 +22,7 @@ public sealed class TeleportSpellEui : BaseEui
|
||||
|
||||
private bool _used;
|
||||
|
||||
public TeleportSpellEui(EntityUid performer, EntityUid target)
|
||||
public CultTeleportSpellEui(EntityUid performer, EntityUid target)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
@@ -39,7 +39,7 @@ public sealed class TeleportSpellEui : BaseEui
|
||||
public override EuiStateBase GetNewState()
|
||||
{
|
||||
var runesQuery = _entityManager.EntityQueryEnumerator<CultRuneTeleportComponent>();
|
||||
var state = new TeleportSpellEuiState();
|
||||
var state = new CultTeleportSpellEuiState();
|
||||
|
||||
while (runesQuery.MoveNext(out var runeUid, out var rune))
|
||||
{
|
||||
@@ -110,4 +110,4 @@ public sealed class TeleportSpellEui : BaseEui
|
||||
_transformSystem.SetCoordinates(_target, runeTransform.Coordinates);
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,7 +105,7 @@ public sealed class WizardSpellsSystem : EntitySystem
|
||||
if (!TryComp(msg.Performer, out ActorComponent? actor))
|
||||
return;
|
||||
|
||||
var eui = new TeleportSpellEui(msg.Performer);
|
||||
var eui = new WizardTeleportSpellEui(msg.Performer);
|
||||
_euiManager.OpenEui(eui, actor.PlayerSession);
|
||||
eui.StateDirty();
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Content.Server._White.Wizard.SpellBlade;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class FireAspectComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Content.Shared.Atmos;
|
||||
|
||||
namespace Content.Server._White.Wizard.SpellBlade;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class FrostAspectComponent : Component
|
||||
{
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public float TemperatureOnHit = 100;
|
||||
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public float MinTemperature = Atmospherics.TCMB;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace Content.Server._White.Wizard.SpellBlade;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class LightningAspectComponent : Component
|
||||
{
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public float Range = 2f;
|
||||
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public int BoltCount = 3;
|
||||
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public string LightningPrototype = "WeakWizardLightning";
|
||||
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public int ArcDepth = 2;
|
||||
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan ShockRate = TimeSpan.FromSeconds(10);
|
||||
|
||||
public TimeSpan NextShock;
|
||||
}
|
||||
79
Content.Server/_White/Wizard/SpellBlade/SpellBladeSystem.cs
Normal file
79
Content.Server/_White/Wizard/SpellBlade/SpellBladeSystem.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Lightning;
|
||||
using Content.Server.Temperature.Components;
|
||||
using Content.Server.Temperature.Systems;
|
||||
using Content.Shared._White.Wizard.SpellBlade;
|
||||
using Content.Shared.Weapons.Melee.Events;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._White.Wizard.SpellBlade;
|
||||
|
||||
public sealed class SpellBladeSystem : SharedSpellBladeSystem
|
||||
{
|
||||
[Dependency] private readonly TemperatureSystem _temperature = default!;
|
||||
[Dependency] private readonly LightningSystem _lightning = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<FrostAspectComponent, MeleeHitEvent>(OnFrostMeleeHit);
|
||||
SubscribeLocalEvent<LightningAspectComponent, MeleeHitEvent>(OnLightningMeleeHit);
|
||||
}
|
||||
|
||||
private void OnLightningMeleeHit(Entity<LightningAspectComponent> ent, ref MeleeHitEvent args)
|
||||
{
|
||||
if (args.Direction != null || args.HitEntities.Count != 1)
|
||||
return;
|
||||
|
||||
if (ent.Comp.NextShock > _timing.CurTime)
|
||||
return;
|
||||
|
||||
ent.Comp.NextShock = _timing.CurTime + ent.Comp.ShockRate;
|
||||
|
||||
_lightning.ShootRandomLightnings(args.HitEntities[0], ent.Comp.Range, ent.Comp.BoltCount,
|
||||
ent.Comp.LightningPrototype, ent.Comp.ArcDepth, false, args.User);
|
||||
}
|
||||
|
||||
private void OnFrostMeleeHit(Entity<FrostAspectComponent> ent, ref MeleeHitEvent args)
|
||||
{
|
||||
var temp = ent.Comp.TemperatureOnHit;
|
||||
if (args.Direction != null) // Heavy attack
|
||||
temp *= 0.5f;
|
||||
|
||||
foreach (var entity in args.HitEntities)
|
||||
{
|
||||
if (!TryComp<TemperatureComponent>(entity, out var temperature))
|
||||
continue;
|
||||
|
||||
var curTemp = temperature.CurrentTemperature;
|
||||
var newTemp = curTemp - temp;
|
||||
|
||||
newTemp = curTemp < ent.Comp.MinTemperature
|
||||
? MathF.Min(curTemp, newTemp)
|
||||
: Math.Max(newTemp, ent.Comp.MinTemperature);
|
||||
|
||||
_temperature.ForceChangeTemperature(entity, newTemp, temperature);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ApplyFireAspect(EntityUid uid)
|
||||
{
|
||||
var ignite = EnsureComp<IgniteOnMeleeHitComponent>(uid);
|
||||
ignite.FireStacks = 2f;
|
||||
EnsureComp<FireAspectComponent>(uid);
|
||||
}
|
||||
|
||||
protected override void ApplyFrostAspect(EntityUid uid)
|
||||
{
|
||||
var ignite = EnsureComp<IgniteOnMeleeHitComponent>(uid);
|
||||
ignite.FireStacks = -5f;
|
||||
EnsureComp<FrostAspectComponent>(uid);
|
||||
}
|
||||
|
||||
protected override void ApplyLightningAspect(EntityUid uid)
|
||||
{
|
||||
EnsureComp<LightningAspectComponent>(uid);
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
using System.Linq;
|
||||
using Content.Server.EUI;
|
||||
using Content.Server.EUI;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared._White.Wizard.Teleport;
|
||||
using Content.Shared.Eui;
|
||||
using Robust.Shared.Timing;
|
||||
using TeleportSpellEuiState = Content.Shared._White.Wizard.Teleport.TeleportSpellEuiState;
|
||||
|
||||
namespace Content.Server._White.Wizard.Teleport;
|
||||
|
||||
public sealed class TeleportSpellEui : BaseEui
|
||||
public sealed class WizardTeleportSpellEui : BaseEui
|
||||
{
|
||||
[Dependency] private readonly EntityManager _entityManager = default!;
|
||||
private readonly SharedTransformSystem _transformSystem;
|
||||
@@ -19,7 +17,7 @@ public sealed class TeleportSpellEui : BaseEui
|
||||
|
||||
private bool _used;
|
||||
|
||||
public TeleportSpellEui(EntityUid performer)
|
||||
public WizardTeleportSpellEui(EntityUid performer)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
@@ -29,13 +27,13 @@ public sealed class TeleportSpellEui : BaseEui
|
||||
|
||||
_performer = performer;
|
||||
|
||||
Timer.Spawn(TimeSpan.FromSeconds(10), Close);
|
||||
Timer.Spawn(TimeSpan.FromSeconds(60), Close);
|
||||
}
|
||||
|
||||
public override EuiStateBase GetNewState()
|
||||
{
|
||||
var locationQuery = _entityManager.EntityQueryEnumerator<TeleportLocationComponent, TransformComponent>();
|
||||
var state = new TeleportSpellEuiState();
|
||||
var state = new WizardTeleportSpellEuiState();
|
||||
|
||||
while (locationQuery.MoveNext(out var locationUid, out var locationComponent, out var transformComponent))
|
||||
{
|
||||
@@ -533,6 +533,11 @@ public abstract partial class SharedGunSystem : EntitySystem
|
||||
Dirty(gun);
|
||||
}
|
||||
// WD EDIT
|
||||
public void SetUseKey(GunComponent gun, bool useKey)
|
||||
{
|
||||
gun.UseKey = useKey;
|
||||
}
|
||||
|
||||
public void SetProjectileSpeed(EntityUid weapon, float projectileSpeed)
|
||||
{
|
||||
if(!TryComp<GunComponent>(weapon, out var gunComponent))
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using System.Numerics;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._White.BetrayalDagger;
|
||||
|
||||
[RegisterComponent]
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class BlinkComponent : Component
|
||||
{
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
|
||||
@@ -4,7 +4,7 @@ using Robust.Shared.Serialization;
|
||||
namespace Content.Shared._White.Cult.UI;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class TeleportSpellEuiState : EuiStateBase
|
||||
public sealed class CultTeleportSpellEuiState : EuiStateBase
|
||||
{
|
||||
public Dictionary<int, string> Runes = new();
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
using System.Linq;
|
||||
using Content.Shared._White.BetrayalDagger;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.UserInterface;
|
||||
using Content.Shared.Weapons.Ranged.Components;
|
||||
using Content.Shared.Weapons.Ranged.Systems;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._White.Wizard.SpellBlade;
|
||||
|
||||
public abstract class SharedSpellBladeSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedGunSystem _gun = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<SpellBladeComponent, SpellBladeSystemMessage>(OnMessage);
|
||||
SubscribeLocalEvent<SpellBladeComponent, ActivatableUIOpenAttemptEvent>(OnOpenAttempt);
|
||||
SubscribeLocalEvent<SpellBladeComponent, ExaminedEvent>(OnExamined);
|
||||
}
|
||||
|
||||
private void OnExamined(Entity<SpellBladeComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
if (ent.Comp.ChosenAspect == string.Empty)
|
||||
{
|
||||
args.PushMarkup("Аспект не выбран.");
|
||||
return;
|
||||
}
|
||||
|
||||
var proto = _prototypeManager.Index(ent.Comp.ChosenAspect);
|
||||
|
||||
args.PushMarkup($"Выбранный аспект: {proto.Name}");
|
||||
}
|
||||
|
||||
private void OnOpenAttempt(Entity<SpellBladeComponent> ent, ref ActivatableUIOpenAttemptEvent args)
|
||||
{
|
||||
if (ent.Comp.ChosenAspect == string.Empty)
|
||||
return;
|
||||
|
||||
_popup.PopupEntity("Аспект уже выбран.", args.User, args.User);
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnMessage(Entity<SpellBladeComponent> ent, ref SpellBladeSystemMessage args)
|
||||
{
|
||||
if (ent.Comp.ChosenAspect != string.Empty)
|
||||
return;
|
||||
|
||||
switch (args.ProtoId)
|
||||
{
|
||||
case "AspectFire":
|
||||
ApplyFireAspect(ent);
|
||||
break;
|
||||
case "AspectFrost":
|
||||
ApplyFrostAspect(ent);
|
||||
break;
|
||||
case "AspectLightning":
|
||||
ApplyLightningAspect(ent);
|
||||
break;
|
||||
case "AspectBluespace":
|
||||
ApplyBluespaceAspect(ent);
|
||||
break;
|
||||
case "AspectMagicMissile":
|
||||
ApplyMagicMissileAspect(ent);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
ent.Comp.ChosenAspect = args.ProtoId;
|
||||
|
||||
_audio.PlayPvs(ent.Comp.AspectChosenSound, ent);
|
||||
|
||||
|
||||
Dirty(ent);
|
||||
}
|
||||
|
||||
protected virtual void ApplyFireAspect(EntityUid uid) { }
|
||||
|
||||
protected virtual void ApplyFrostAspect(EntityUid uid) { }
|
||||
|
||||
protected virtual void ApplyLightningAspect(EntityUid uid) { }
|
||||
|
||||
private void ApplyBluespaceAspect(EntityUid uid)
|
||||
{
|
||||
var blink = EnsureComp<BlinkComponent>(uid);
|
||||
blink.Distance = 15f;
|
||||
blink.BlinkRate = 1f;
|
||||
}
|
||||
|
||||
private void ApplyMagicMissileAspect(EntityUid uid)
|
||||
{
|
||||
var gun = EnsureComp<GunComponent>(uid);
|
||||
_gun.SetUseKey(gun, false);
|
||||
_gun.SetSound(uid, new SoundPathSpecifier("/Audio/Weapons/Guns/Gunshots/Magic/staff_healing.ogg"));
|
||||
_gun.SetFireRate(uid, 1.2f);
|
||||
var ammoProvider = EnsureComp<BasicEntityAmmoProviderComponent>(uid);
|
||||
ammoProvider.Proto = "ProjectileMagicMissile";
|
||||
}
|
||||
|
||||
public bool IsHoldingItemWithComponent<T>(EntityUid uid) where T : Component
|
||||
{
|
||||
return _hands.EnumerateHeld(uid).Any(HasComp<T>);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._White.Wizard.SpellBlade;
|
||||
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
public sealed partial class SpellBladeComponent : Component
|
||||
{
|
||||
[ViewVariables, AutoNetworkedField]
|
||||
public string ChosenAspect = string.Empty;
|
||||
|
||||
[DataField]
|
||||
public List<EntProtoId> Aspects = new()
|
||||
{
|
||||
"AspectFire",
|
||||
"AspectFrost",
|
||||
"AspectLightning",
|
||||
"AspectBluespace",
|
||||
"AspectMagicMissile"
|
||||
};
|
||||
|
||||
[DataField, ViewVariables(VVAccess.ReadWrite)]
|
||||
public SoundSpecifier AspectChosenSound = new SoundPathSpecifier("/Audio/White/Magic/spellblade-aspect.ogg");
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SpellBladeSystemMessage(EntProtoId protoId) : BoundUserInterfaceMessage
|
||||
{
|
||||
public EntProtoId ProtoId = protoId;
|
||||
}
|
||||
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum SpellBladeUiKey : byte
|
||||
{
|
||||
Key
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using Robust.Shared.Serialization;
|
||||
namespace Content.Shared._White.Wizard.Teleport;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class TeleportSpellEuiState : EuiStateBase
|
||||
public sealed class WizardTeleportSpellEuiState : EuiStateBase
|
||||
{
|
||||
public Dictionary<int, string> Locations = new();
|
||||
}
|
||||
BIN
Resources/Audio/White/Magic/spellblade-aspect.ogg
Normal file
BIN
Resources/Audio/White/Magic/spellblade-aspect.ogg
Normal file
Binary file not shown.
@@ -176,3 +176,16 @@
|
||||
- type: Lightning
|
||||
canArc: true
|
||||
lightningPrototype: WizardLightning
|
||||
|
||||
- type: entity
|
||||
name: wizard lightning
|
||||
id: WeakWizardLightning
|
||||
parent: BaseLightning
|
||||
noSpawn: true
|
||||
components:
|
||||
- type: Electrified
|
||||
requirePower: false
|
||||
ignoreInsulation: true
|
||||
- type: Lightning
|
||||
canArc: true
|
||||
lightningPrototype: WeakWizardLightning
|
||||
|
||||
@@ -236,3 +236,44 @@
|
||||
stunAmount: 2
|
||||
knockdownAmount: 2
|
||||
- type: TeslaProjectile
|
||||
|
||||
- type: entity
|
||||
id: ProjectileMagicMissile
|
||||
name: magic missile
|
||||
description: asdf
|
||||
parent: BaseBullet
|
||||
noSpawn: true
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Weapons/Guns/Projectiles/magic.rsi
|
||||
layers:
|
||||
- state: spell
|
||||
color: pink
|
||||
- type: Projectile
|
||||
damage:
|
||||
groups:
|
||||
Burn: 0
|
||||
- type: StaminaDamageOnCollide
|
||||
damage: 60
|
||||
- type: Ammo
|
||||
muzzleFlash: null
|
||||
- type: Trail
|
||||
splineIteratorType: CatmullRom
|
||||
splineRendererType: Continuous
|
||||
creationMethod: OnMove
|
||||
lengthStep: 0.1
|
||||
scale: 0.05, 0.0
|
||||
lifetime: 1
|
||||
randomWalk: 0.1, 0.001
|
||||
gravity: 0.0, 0.0
|
||||
texturePath: /Textures/White/Effects/Trails/Continuous/trail.png
|
||||
gradientIteratorType: Linear
|
||||
gradient:
|
||||
- 1, 0, 0, 1
|
||||
- 1, 1, 0, 0.85
|
||||
- 0, 1, 0, 0.7
|
||||
- 0, 1, 1, 0.55
|
||||
- 0, 0, 1, 0.4
|
||||
- 1, 0, 1, 0.25
|
||||
- 1, 0, 0, 0.1
|
||||
optionsConcealable: true
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
- HolyKatana
|
||||
- MultiverseBlade
|
||||
- VorpalScythe
|
||||
- SpellBlade
|
||||
- PossessedBlade
|
||||
- ChainsawHand
|
||||
- HolyWhip
|
||||
@@ -195,31 +194,6 @@
|
||||
sprite: White/Objects/Weapons/Chaplain/scythe-inhands.rsi
|
||||
- type: HolyWeapon
|
||||
|
||||
- type: entity
|
||||
name: клинок заклинаний
|
||||
parent: HolyKatana
|
||||
id: SpellBlade
|
||||
description: Клинок, с шансом 20% наносящий критический удар.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: White/Objects/Weapons/Chaplain/spellblade.rsi
|
||||
- type: MeleeWeapon
|
||||
wideAnimationRotation: 135
|
||||
damage:
|
||||
types:
|
||||
Slash: 18
|
||||
- type: Clothing
|
||||
sprite: White/Objects/Weapons/Chaplain/spellblade.rsi
|
||||
slots:
|
||||
- back
|
||||
- suitStorage
|
||||
- type: Crit
|
||||
critChance: 20
|
||||
critMultiplier: 2.5
|
||||
- type: Item
|
||||
sprite: White/Objects/Weapons/Chaplain/spellblade.rsi
|
||||
- type: HolyWeapon
|
||||
|
||||
- type: entity
|
||||
name: одержимый клинок
|
||||
parent: HolyKatana
|
||||
|
||||
@@ -21,3 +21,33 @@
|
||||
reflectProb: 0.4
|
||||
- type: Item
|
||||
sprite: White/Objects/Weapons/Chaplain/hfrequency.rsi
|
||||
|
||||
- type: entity
|
||||
name: клинок заклинаний
|
||||
parent: Katana
|
||||
id: SpellBlade
|
||||
description: Магический клинок, наделяемый силой одного из пяти аспектов.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: White/Objects/Weapons/Chaplain/spellblade.rsi
|
||||
- type: MeleeWeapon
|
||||
wideAnimationRotation: 135
|
||||
damage:
|
||||
types:
|
||||
Slash: 30
|
||||
- type: Clothing
|
||||
sprite: White/Objects/Weapons/Chaplain/spellblade.rsi
|
||||
slots:
|
||||
- back
|
||||
- suitStorage
|
||||
- type: Item
|
||||
sprite: White/Objects/Weapons/Chaplain/spellblade.rsi
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
- key: enum.SpellBladeUiKey.Key
|
||||
type: SpellBladeBUI
|
||||
- type: ActivatableUI
|
||||
key: enum.SpellBladeUiKey.Key
|
||||
inHandsOnly: true
|
||||
closeOnHandDeselect: true
|
||||
- type: SpellBlade
|
||||
|
||||
49
Resources/Prototypes/_White/Wizard/spellblade.yml
Normal file
49
Resources/Prototypes/_White/Wizard/spellblade.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
- type: entity
|
||||
name: Огонь
|
||||
description: Клинок заклинаний наделяется способностью поджигать врагов. И тот, кто удерживает клинок в руках, становится неуязвимым к огню и высокой температуре.
|
||||
id: AspectFire
|
||||
noSpawn: true
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Magic/magicactions.rsi
|
||||
state: fireball
|
||||
|
||||
- type: entity
|
||||
name: Холод
|
||||
description: Клинок заклинаний наделяется замораживать врагов. И тот, кто удерживает клинок в руках, становится неуязвимым к низкой температуре.
|
||||
id: AspectFrost
|
||||
noSpawn: true
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Magic/magicactions.rsi
|
||||
state: icebeam_active
|
||||
|
||||
- type: entity
|
||||
name: Молния
|
||||
description: Клинок заклинаний наделяется способностью каждые 10 секунд при ударе излучать шоковый заряд, поражающий ближайшие цели.
|
||||
id: AspectLightning
|
||||
noSpawn: true
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Magic/magicactions.rsi
|
||||
state: thunder
|
||||
|
||||
- type: entity
|
||||
name: Блюспейс
|
||||
description: Клинок заклинаний наделяется способностью телепортации на далёкое расстояние.
|
||||
id: AspectBluespace
|
||||
noSpawn: true
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Magic/magicactions.rsi
|
||||
state: blink
|
||||
|
||||
- type: entity
|
||||
name: Магическая Стрела
|
||||
description: Клинок заклинаний наделяется способностью стрелять оглушающей магической стрелой.
|
||||
id: AspectMagicMissile
|
||||
noSpawn: true
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Objects/Magic/magicactions.rsi
|
||||
state: magicmissile
|
||||
@@ -247,3 +247,16 @@
|
||||
conditions:
|
||||
- !type:ListingLimitedStockCondition
|
||||
stock: 1
|
||||
|
||||
- type: listing
|
||||
id: SpellBookSpellBlade
|
||||
name: spellbook-spellblade-name
|
||||
description: spellbook-spellblade-desc
|
||||
productEntity: SpellBlade
|
||||
cost:
|
||||
SpellPoint: 2
|
||||
categories:
|
||||
- MagicItems
|
||||
conditions:
|
||||
- !type:ListingLimitedStockCondition
|
||||
stock: 1
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 294 B |
@@ -54,6 +54,9 @@
|
||||
},
|
||||
{
|
||||
"name": "teleport"
|
||||
},
|
||||
{
|
||||
"name": "icebeam_active"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user