More magic (#338)

* - tweak: Magic tweaks.

* - add: Rework some spells.

* - fix: Some bugfixes.

* - tweak: Less requirements.

* - add: Loc.
This commit is contained in:
Aviu00
2024-06-08 13:01:49 +00:00
committed by GitHub
parent 4fde7aedee
commit c1fe31b63b
13 changed files with 168 additions and 84 deletions

View File

@@ -2,6 +2,8 @@
using Content.Shared._White.Wizard; using Content.Shared._White.Wizard;
using Content.Shared._White.Wizard.Charging; using Content.Shared._White.Wizard.Charging;
using Content.Shared.Actions; using Content.Shared.Actions;
using Content.Shared.Mobs.Systems;
using Content.Shared.StatusEffect;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.Input; using Robust.Client.Input;
@@ -24,6 +26,8 @@ public sealed class ChargeActionSystem : SharedChargingSystem
[Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!; [Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
private ActionUIController? _controller; private ActionUIController? _controller;
@@ -55,6 +59,9 @@ public sealed class ChargeActionSystem : SharedChargingSystem
if (_playerManager.LocalEntity is not { } user) if (_playerManager.LocalEntity is not { } user)
return; return;
if (!_mobState.IsAlive(user) || _statusEffects.HasStatusEffect(user, "Incorporeal"))
return;
if (!_timing.IsFirstTimePredicted || _controller == null || _controller.SelectingTargetFor is not { } actionId) if (!_timing.IsFirstTimePredicted || _controller == null || _controller.SelectingTargetFor is not { } actionId)
return; return;

View File

@@ -1,5 +1,6 @@
using System.Numerics; using System.Numerics;
using Content.Server.Beam.Components; using Content.Server.Beam.Components;
using Content.Server.Electrocution;
using Content.Shared.Beam; using Content.Shared.Beam;
using Content.Shared.Beam.Components; using Content.Shared.Beam.Components;
using Content.Shared.Physics; using Content.Shared.Physics;
@@ -65,7 +66,7 @@ public sealed class BeamSystem : SharedBeamSystem
/// <param name="controller"> The virtual beam controller that this beam will use. If one doesn't exist it will be created here.</param> /// <param name="controller"> The virtual beam controller that this beam will use. If one doesn't exist it will be created here.</param>
/// <param name="bodyState">Optional sprite state for the <see cref="prototype"/> if it needs a dynamic one</param> /// <param name="bodyState">Optional sprite state for the <see cref="prototype"/> if it needs a dynamic one</param>
/// <param name="shader">Optional shader for the <see cref="prototype"/> and <see cref="bodyState"/> if it needs something other than default</param> /// <param name="shader">Optional shader for the <see cref="prototype"/> and <see cref="bodyState"/> if it needs something other than default</param>
private void CreateBeam(string prototype, private IEnumerable<EntityUid> CreateBeam(string prototype,
Angle userAngle, Angle userAngle,
Vector2 calculatedDistance, Vector2 calculatedDistance,
MapCoordinates beamStartPos, MapCoordinates beamStartPos,
@@ -78,8 +79,10 @@ public sealed class BeamSystem : SharedBeamSystem
var ent = Spawn(prototype, beamSpawnPos); var ent = Spawn(prototype, beamSpawnPos);
var shape = new EdgeShape(distanceCorrection, new Vector2(0,0)); var shape = new EdgeShape(distanceCorrection, new Vector2(0,0));
yield return ent;
if (!TryComp<PhysicsComponent>(ent, out var physics) || !TryComp<BeamComponent>(ent, out var beam)) if (!TryComp<PhysicsComponent>(ent, out var physics) || !TryComp<BeamComponent>(ent, out var beam))
return; yield break;
FixturesComponent? manager = null; FixturesComponent? manager = null;
_fixture.TryCreateFixture( _fixture.TryCreateFixture(
@@ -120,6 +123,7 @@ public sealed class BeamSystem : SharedBeamSystem
{ {
beamSpawnPos = beamSpawnPos.Offset(calculatedDistance.Normalized()); beamSpawnPos = beamSpawnPos.Offset(calculatedDistance.Normalized());
var newEnt = Spawn(prototype, beamSpawnPos); var newEnt = Spawn(prototype, beamSpawnPos);
yield return newEnt;
var ev = new BeamVisualizerEvent(GetNetEntity(newEnt), distanceLength, userAngle, bodyState, shader); var ev = new BeamVisualizerEvent(GetNetEntity(newEnt), distanceLength, userAngle, bodyState, shader);
RaiseNetworkEvent(ev); RaiseNetworkEvent(ev);
@@ -139,10 +143,10 @@ public sealed class BeamSystem : SharedBeamSystem
/// <param name="bodyState">Optional sprite state for the <see cref="bodyPrototype"/> if a default one is not given</param> /// <param name="bodyState">Optional sprite state for the <see cref="bodyPrototype"/> if a default one is not given</param>
/// <param name="shader">Optional shader for the <see cref="bodyPrototype"/> if a default one is not given</param> /// <param name="shader">Optional shader for the <see cref="bodyPrototype"/> if a default one is not given</param>
/// <param name="controller"></param> /// <param name="controller"></param>
public void TryCreateBeam(EntityUid user, EntityUid target, string bodyPrototype, string? bodyState = null, string shader = "unshaded", EntityUid? controller = null) public IEnumerable<EntityUid> TryCreateBeam(EntityUid user, EntityUid target, string bodyPrototype, string? bodyState = null, string shader = "unshaded", EntityUid? controller = null)
{ {
if (Deleted(user) || Deleted(target)) if (Deleted(user) || Deleted(target))
return; yield break;
var userMapPos = Transform(user).MapPosition; var userMapPos = Transform(user).MapPosition;
var targetMapPos = Transform(target).MapPosition; var targetMapPos = Transform(target).MapPosition;
@@ -152,14 +156,14 @@ public sealed class BeamSystem : SharedBeamSystem
var userAngle = calculatedDistance.ToWorldAngle(); var userAngle = calculatedDistance.ToWorldAngle();
if (userMapPos.MapId != targetMapPos.MapId) if (userMapPos.MapId != targetMapPos.MapId)
return; yield break;
//Where the start of the beam will spawn //Where the start of the beam will spawn
var beamStartPos = userMapPos.Offset(calculatedDistance.Normalized()); var beamStartPos = userMapPos.Offset(calculatedDistance.Normalized());
//Don't divide by zero //Don't divide by zero
if (calculatedDistance.Length() == 0) if (calculatedDistance.Length() == 0)
return; yield break;
if (controller != null && TryComp<BeamComponent>(controller, out var controllerBeamComp)) if (controller != null && TryComp<BeamComponent>(controller, out var controllerBeamComp))
{ {
@@ -169,7 +173,12 @@ public sealed class BeamSystem : SharedBeamSystem
var distanceCorrection = calculatedDistance - calculatedDistance.Normalized(); var distanceCorrection = calculatedDistance - calculatedDistance.Normalized();
CreateBeam(bodyPrototype, userAngle, calculatedDistance, beamStartPos, distanceCorrection, controller, bodyState, shader); var ents = CreateBeam(bodyPrototype, userAngle, calculatedDistance, beamStartPos, distanceCorrection, controller, bodyState, shader);
foreach (var ent in ents)
{
yield return ent;
}
var ev = new CreateBeamSuccessEvent(user, target); var ev = new CreateBeamSuccessEvent(user, target);
RaiseLocalEvent(user, ev); RaiseLocalEvent(user, ev);

View File

@@ -85,4 +85,11 @@ public sealed partial class ElectrifiedComponent : Component
[DataField("shockVolume")] [DataField("shockVolume")]
public float ShockVolume = 20; public float ShockVolume = 20;
// WD EDIT START
[DataField]
public bool IgnoreInsulation;
public EntityUid? Caster;
// WD EDIT END
} }

View File

@@ -219,7 +219,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
_appearance.SetData(uid, ElectrifiedVisuals.IsPowered, true); _appearance.SetData(uid, ElectrifiedVisuals.IsPowered, true);
siemens *= electrified.SiemensCoefficient; siemens *= electrified.SiemensCoefficient;
if (!DoCommonElectrocutionAttempt(targetUid, uid, ref siemens) || siemens <= 0) if (targetUid != electrified.Caster && !DoCommonElectrocutionAttempt(targetUid, uid, ref siemens, electrified.IgnoreInsulation) || siemens <= 0) // WD EDIT
return false; // If electrocution would fail, do nothing. return false; // If electrocution would fail, do nothing.
var targets = new List<(EntityUid entity, int depth)>(); var targets = new List<(EntityUid entity, int depth)>();
@@ -230,13 +230,19 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
for (var i = targets.Count - 1; i >= 0; i--) for (var i = targets.Count - 1; i >= 0; i--)
{ {
var (entity, depth) = targets[i]; var (entity, depth) = targets[i];
if (entity == electrified.Caster) // WD
continue;
lastRet = TryDoElectrocution( lastRet = TryDoElectrocution(
entity, entity,
uid, uid,
(int) (electrified.ShockDamage * MathF.Pow(RecursiveDamageMultiplier, depth)), (int) (electrified.ShockDamage * MathF.Pow(RecursiveDamageMultiplier, depth)),
TimeSpan.FromSeconds(electrified.ShockTime * MathF.Pow(RecursiveTimeMultiplier, depth)), TimeSpan.FromSeconds(electrified.ShockTime * MathF.Pow(RecursiveTimeMultiplier, depth)),
true, true,
electrified.SiemensCoefficient electrified.SiemensCoefficient,
null, // WD EDIT START
electrified.IgnoreInsulation // WD EDIT END
); );
} }
@@ -518,4 +524,4 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem
_audio.PlayPvs(electrified.ShockNoises, targetUid, AudioParams.Default.WithVolume(electrified.ShockVolume)); _audio.PlayPvs(electrified.ShockNoises, targetUid, AudioParams.Default.WithVolume(electrified.ShockVolume));
} }
} }

View File

@@ -1,6 +1,7 @@
using System.Linq; using System.Linq;
using Content.Server.Beam; using Content.Server.Beam;
using Content.Server.Beam.Components; using Content.Server.Beam.Components;
using Content.Server.Electrocution;
using Content.Server.Lightning.Components; using Content.Server.Lightning.Components;
using Content.Shared.Lightning; using Content.Shared.Lightning;
using Robust.Shared.Random; using Robust.Shared.Random;
@@ -45,10 +46,16 @@ public sealed class LightningSystem : SharedLightningSystem
/// <param name="target">Where the lightning fires to</param> /// <param name="target">Where the lightning fires to</param>
/// <param name="lightningPrototype">The prototype for the lightning to be created</param> /// <param name="lightningPrototype">The prototype for the lightning to be created</param>
/// <param name="triggerLightningEvents">if the lightnings being fired should trigger lightning events.</param> /// <param name="triggerLightningEvents">if the lightnings being fired should trigger lightning events.</param>
public void ShootLightning(EntityUid user, EntityUid target, string lightningPrototype = "Lightning", bool triggerLightningEvents = true) public void ShootLightning(EntityUid user, EntityUid target, string lightningPrototype = "Lightning", bool triggerLightningEvents = true, EntityUid? caster = null) // WD EDIT
{ {
var spriteState = LightningRandomizer(); var spriteState = LightningRandomizer();
_beam.TryCreateBeam(user, target, lightningPrototype, spriteState); var ents = _beam.TryCreateBeam(user, target, lightningPrototype, spriteState); // WD EDIT START
foreach (var ent in ents)
{
if (TryComp(ent, out ElectrifiedComponent? electrified))
electrified.Caster = caster;
}
// WD EDIT END
if (triggerLightningEvents) // we don't want certain prototypes to trigger lightning level events if (triggerLightningEvents) // we don't want certain prototypes to trigger lightning level events
{ {
@@ -66,7 +73,7 @@ public sealed class LightningSystem : SharedLightningSystem
/// <param name="lightningPrototype">The prototype for the lightning to be created</param> /// <param name="lightningPrototype">The prototype for the lightning to be created</param>
/// <param name="arcDepth">how many times to recursively fire lightning bolts from the target points of the first shot.</param> /// <param name="arcDepth">how many times to recursively fire lightning bolts from the target points of the first shot.</param>
/// <param name="triggerLightningEvents">if the lightnings being fired should trigger lightning events.</param> /// <param name="triggerLightningEvents">if the lightnings being fired should trigger lightning events.</param>
public void ShootRandomLightnings(EntityUid user, float range, int boltCount, string lightningPrototype = "Lightning", int arcDepth = 0, bool triggerLightningEvents = true) public void ShootRandomLightnings(EntityUid user, float range, int boltCount, string lightningPrototype = "Lightning", int arcDepth = 0, bool triggerLightningEvents = true, EntityUid? caster = null) // WD EDIT
{ {
//To Do: add support to different priority target tablem for different lightning types //To Do: add support to different priority target tablem for different lightning types
//To Do: Remove Hardcode LightningTargetComponent (this should be a parameter of the SharedLightningComponent) //To Do: Remove Hardcode LightningTargetComponent (this should be a parameter of the SharedLightningComponent)
@@ -89,10 +96,10 @@ public sealed class LightningSystem : SharedLightningSystem
if (!_random.Prob(curTarget.HitProbability)) //Chance to ignore target if (!_random.Prob(curTarget.HitProbability)) //Chance to ignore target
continue; continue;
ShootLightning(user, targets[count].Owner, lightningPrototype, triggerLightningEvents); ShootLightning(user, targets[count].Owner, lightningPrototype, triggerLightningEvents, caster); // WD EDIT
if (arcDepth - targets[count].LightningResistance > 0) if (arcDepth - targets[count].LightningResistance > 0)
{ {
ShootRandomLightnings(targets[count].Owner, range, 1, lightningPrototype, arcDepth - targets[count].LightningResistance, triggerLightningEvents); ShootRandomLightnings(targets[count].Owner, range, 1, lightningPrototype, arcDepth - targets[count].LightningResistance, triggerLightningEvents, caster); // WD EDIT
} }
shootCount++; shootCount++;
} }

View File

@@ -1,5 +1,6 @@
using Content.Server.Atmos.Components; using Content.Server.Atmos.Components;
using Content.Server.Singularity.Components; using Content.Server.Singularity.Components;
using Content.Server.Stunnable;
using Content.Shared.Ghost; using Content.Shared.Ghost;
using Content.Shared.Singularity.EntitySystems; using Content.Shared.Singularity.EntitySystems;
using Robust.Shared.Map; using Robust.Shared.Map;
@@ -24,6 +25,7 @@ public sealed class GravityWellSystem : SharedGravityWellSystem
[Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly StunSystem _stun = default!; // WD EDIT
#endregion Dependencies #endregion Dependencies
/// <summary> /// <summary>
@@ -141,10 +143,10 @@ public sealed class GravityWellSystem : SharedGravityWellSystem
/// <param name="baseRadialDeltaV">The base radial velocity that will be added to entities within range towards the center of the gravitational pulse.</param> /// <param name="baseRadialDeltaV">The base radial velocity that will be added to entities within range towards the center of the gravitational pulse.</param>
/// <param name="baseTangentialDeltaV">The base tangential velocity that will be added to entities within countrclockwise around the center of the gravitational pulse.</param> /// <param name="baseTangentialDeltaV">The base tangential velocity that will be added to entities within countrclockwise around the center of the gravitational pulse.</param>
/// <param name="xform">(optional) The transform of the entity at the epicenter of the gravitational pulse.</param> /// <param name="xform">(optional) The transform of the entity at the epicenter of the gravitational pulse.</param>
public void GravPulse(EntityUid uid, float maxRange, float minRange, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f, TransformComponent? xform = null) public void GravPulse(EntityUid uid, float maxRange, float minRange, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f, TransformComponent? xform = null, float stunTime = 0f, List<EntityUid>? ignore = null)
{ {
if (Resolve(uid, ref xform)) if (Resolve(uid, ref xform))
GravPulse(xform.Coordinates, maxRange, minRange, baseRadialDeltaV, baseTangentialDeltaV); GravPulse(xform.Coordinates, maxRange, minRange, baseRadialDeltaV, baseTangentialDeltaV, stunTime, ignore);
} }
/// <summary> /// <summary>
@@ -165,8 +167,8 @@ public sealed class GravityWellSystem : SharedGravityWellSystem
/// <param name="minRange">The minimum distance at which entities can be affected by the gravity pulse.</param> /// <param name="minRange">The minimum distance at which entities can be affected by the gravity pulse.</param>
/// <param name="baseRadialDeltaV">The base radial velocity that will be added to entities within range towards the center of the gravitational pulse.</param> /// <param name="baseRadialDeltaV">The base radial velocity that will be added to entities within range towards the center of the gravitational pulse.</param>
/// <param name="baseTangentialDeltaV">The base tangential velocity that will be added to entities within countrclockwise around the center of the gravitational pulse.</param> /// <param name="baseTangentialDeltaV">The base tangential velocity that will be added to entities within countrclockwise around the center of the gravitational pulse.</param>
public void GravPulse(EntityCoordinates entityPos, float maxRange, float minRange, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f) public void GravPulse(EntityCoordinates entityPos, float maxRange, float minRange, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f, float stunTime = 0f, List<EntityUid>? ignore = null)
=> GravPulse(entityPos.ToMap(EntityManager, _transform), maxRange, minRange, baseRadialDeltaV, baseTangentialDeltaV); => GravPulse(entityPos.ToMap(EntityManager, _transform), maxRange, minRange, baseRadialDeltaV, baseTangentialDeltaV, stunTime, ignore);
/// <summary> /// <summary>
/// Causes a gravitational pulse, shoving around all entities within some distance of an epicenter. /// Causes a gravitational pulse, shoving around all entities within some distance of an epicenter.
@@ -175,7 +177,7 @@ public sealed class GravityWellSystem : SharedGravityWellSystem
/// <param name="maxRange">The maximum distance at which entities can be affected by the gravity pulse.</param> /// <param name="maxRange">The maximum distance at which entities can be affected by the gravity pulse.</param>
/// <param name="minRange">The minimum distance at which entities can be affected by the gravity pulse. Exists to prevent div/0 errors.</param> /// <param name="minRange">The minimum distance at which entities can be affected by the gravity pulse. Exists to prevent div/0 errors.</param>
/// <param name="baseMatrixDeltaV">The base velocity added to any entities within affected by the gravity pulse scaled by the displacement of those entities from the epicenter.</param> /// <param name="baseMatrixDeltaV">The base velocity added to any entities within affected by the gravity pulse scaled by the displacement of those entities from the epicenter.</param>
public void GravPulse(MapCoordinates mapPos, float maxRange, float minRange, in Matrix3 baseMatrixDeltaV) public void GravPulse(MapCoordinates mapPos, float maxRange, float minRange, in Matrix3 baseMatrixDeltaV, float stunTime = 0f, List<EntityUid>? ignore = null)
{ {
if (mapPos == MapCoordinates.Nullspace) if (mapPos == MapCoordinates.Nullspace)
return; // No gravpulses in nullspace please. return; // No gravpulses in nullspace please.
@@ -187,6 +189,9 @@ public sealed class GravityWellSystem : SharedGravityWellSystem
foreach(var entity in _lookup.GetEntitiesInRange(mapPos.MapId, epicenter, maxRange, flags: LookupFlags.Dynamic | LookupFlags.Sundries)) foreach(var entity in _lookup.GetEntitiesInRange(mapPos.MapId, epicenter, maxRange, flags: LookupFlags.Dynamic | LookupFlags.Sundries))
{ {
if (ignore?.Contains(entity) is true)
continue;
if (!bodyQuery.TryGetComponent(entity, out var physics) if (!bodyQuery.TryGetComponent(entity, out var physics)
|| physics.BodyType == BodyType.Static) || physics.BodyType == BodyType.Static)
{ {
@@ -206,6 +211,8 @@ public sealed class GravityWellSystem : SharedGravityWellSystem
var scaling = (1f / distance2) * physics.Mass; // TODO: Variable falloff gradiants. var scaling = (1f / distance2) * physics.Mass; // TODO: Variable falloff gradiants.
_physics.ApplyLinearImpulse(entity, (displacement * baseMatrixDeltaV) * scaling, body: physics); _physics.ApplyLinearImpulse(entity, (displacement * baseMatrixDeltaV) * scaling, body: physics);
if (stunTime > 0f)
_stun.TryParalyze(entity, TimeSpan.FromSeconds(stunTime), true);
} }
} }
@@ -217,12 +224,12 @@ public sealed class GravityWellSystem : SharedGravityWellSystem
/// <param name="minRange">The minimum distance at which entities can be affected by the gravity pulse. Exists to prevent div/0 errors.</param> /// <param name="minRange">The minimum distance at which entities can be affected by the gravity pulse. Exists to prevent div/0 errors.</param>
/// <param name="baseRadialDeltaV">The base amount of velocity that will be added to entities in range towards the epicenter of the pulse.</param> /// <param name="baseRadialDeltaV">The base amount of velocity that will be added to entities in range towards the epicenter of the pulse.</param>
/// <param name="baseTangentialDeltaV">The base amount of velocity that will be added to entities in range counterclockwise relative to the epicenter of the pulse.</param> /// <param name="baseTangentialDeltaV">The base amount of velocity that will be added to entities in range counterclockwise relative to the epicenter of the pulse.</param>
public void GravPulse(MapCoordinates mapPos, float maxRange, float minRange = 0.0f, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f) public void GravPulse(MapCoordinates mapPos, float maxRange, float minRange = 0.0f, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f, float stunTime = 0f, List<EntityUid>? ignore = null)
=> GravPulse(mapPos, maxRange, minRange, new Matrix3( => GravPulse(mapPos, maxRange, minRange, new Matrix3(
baseRadialDeltaV, +baseTangentialDeltaV, 0.0f, baseRadialDeltaV, +baseTangentialDeltaV, 0.0f,
-baseTangentialDeltaV, baseRadialDeltaV, 0.0f, -baseTangentialDeltaV, baseRadialDeltaV, 0.0f,
0.0f, 0.0f, 1.0f 0.0f, 0.0f, 1.0f
)); ), stunTime, ignore);
#endregion GravPulse #endregion GravPulse

View File

@@ -1,4 +1,4 @@
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using Content.Server._White.IncorporealSystem; using Content.Server._White.IncorporealSystem;
using Content.Server._White.Wizard.Magic.Amaterasu; using Content.Server._White.Wizard.Magic.Amaterasu;
@@ -12,6 +12,7 @@ using Content.Server.Emp;
using Content.Server.Lightning; using Content.Server.Lightning;
using Content.Server.Magic; using Content.Server.Magic;
using Content.Server.Singularity.EntitySystems; using Content.Server.Singularity.EntitySystems;
using Content.Server.Standing;
using Content.Server.Weapons.Ranged.Systems; using Content.Server.Weapons.Ranged.Systems;
using Content.Shared._White.Wizard; using Content.Shared._White.Wizard;
using Content.Shared._White.Wizard.Magic; using Content.Shared._White.Wizard.Magic;
@@ -62,6 +63,7 @@ public sealed class WizardSpellsSystem : EntitySystem
[Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly EmpSystem _empSystem = default!; [Dependency] private readonly EmpSystem _empSystem = default!;
[Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly StandingStateSystem _standing = default!;
#endregion #endregion
@@ -89,7 +91,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnInstantRecallSpell(InstantRecallSpellEvent msg) private void OnInstantRecallSpell(InstantRecallSpellEvent msg)
{ {
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer)) if (!CanCast(msg))
return; return;
if (!TryComp<HandsComponent>(msg.Performer, out var handsComponent)) if (!TryComp<HandsComponent>(msg.Performer, out var handsComponent))
@@ -110,11 +112,13 @@ public sealed class WizardSpellsSystem : EntitySystem
} }
recallComponent.Item = handsComponent.ActiveHandEntity.Value; recallComponent.Item = handsComponent.ActiveHandEntity.Value;
_popupSystem.PopupEntity($"Сопряжено с {MetaData(handsComponent.ActiveHandEntity.Value).EntityName}", msg.Performer, msg.Performer); _popupSystem.PopupEntity($"Сопряжено с {MetaData(handsComponent.ActiveHandEntity.Value).EntityName}",
msg.Performer, msg.Performer);
return; return;
} }
if (handsComponent.ActiveHandEntity == null && recallComponent.Item != null) if (handsComponent.ActiveHandEntity == null && recallComponent.Item != null &&
Exists(recallComponent.Item.Value))
{ {
var coordsItem = Transform(recallComponent.Item.Value).Coordinates; var coordsItem = Transform(recallComponent.Item.Value).Coordinates;
var coordsPerformer = Transform(msg.Performer).Coordinates; var coordsPerformer = Transform(msg.Performer).Coordinates;
@@ -139,12 +143,12 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnMimeTouchSpell(MimeTouchSpellEvent msg) private void OnMimeTouchSpell(MimeTouchSpellEvent msg)
{ {
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer)) if (!CanCast(msg))
return; return;
if (!HasComp<HumanoidAppearanceComponent>(msg.Target)) if (!HasComp<HumanoidAppearanceComponent>(msg.Target))
{ {
_popupSystem.PopupEntity("Работает только на людях!", msg.Performer, msg.Performer); _popupSystem.PopupEntity("Работает только на людях!", msg.Performer, msg.Performer);
return; return;
} }
@@ -164,7 +168,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnBananaTouchSpell(BananaTouchSpellEvent msg) private void OnBananaTouchSpell(BananaTouchSpellEvent msg)
{ {
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer)) if (!CanCast(msg))
return; return;
if (!HasComp<HumanoidAppearanceComponent>(msg.Target)) if (!HasComp<HumanoidAppearanceComponent>(msg.Target))
@@ -188,7 +192,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnCluwneCurseSpell(CluwneCurseSpellEvent msg) private void OnCluwneCurseSpell(CluwneCurseSpellEvent msg)
{ {
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer)) if (!CanCast(msg))
return; return;
if (!HasComp<HumanoidAppearanceComponent>(msg.Target)) if (!HasComp<HumanoidAppearanceComponent>(msg.Target))
@@ -197,8 +201,7 @@ public sealed class WizardSpellsSystem : EntitySystem
return; return;
} }
var cluwne = EnsureComp<CluwneComponent>(msg.Target); EnsureComp<CluwneComponent>(msg.Target);
cluwne.KnockChance = 0.2f;
Spawn("AdminInstantEffectSmoke3", Transform(msg.Target).Coordinates); Spawn("AdminInstantEffectSmoke3", Transform(msg.Target).Coordinates);
@@ -212,7 +215,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnEmpSpell(EmpSpellEvent msg) private void OnEmpSpell(EmpSpellEvent msg)
{ {
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer)) if (!CanCast(msg))
return; return;
var coords = _transformSystem.ToMapCoordinates(Transform(msg.Performer).Coordinates); var coords = _transformSystem.ToMapCoordinates(Transform(msg.Performer).Coordinates);
@@ -229,7 +232,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnJauntSpell(EtherealJauntSpellEvent msg) private void OnJauntSpell(EtherealJauntSpellEvent msg)
{ {
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer)) if (!CanCast(msg))
return; return;
if (_statusEffectsSystem.HasStatusEffect(msg.Performer, "Incorporeal")) if (_statusEffectsSystem.HasStatusEffect(msg.Performer, "Incorporeal"))
@@ -240,7 +243,8 @@ public sealed class WizardSpellsSystem : EntitySystem
Spawn("AdminInstantEffectSmoke10", Transform(msg.Performer).Coordinates); Spawn("AdminInstantEffectSmoke10", Transform(msg.Performer).Coordinates);
_statusEffectsSystem.TryAddStatusEffect<IncorporealComponent>(msg.Performer, "Incorporeal", TimeSpan.FromSeconds(10), false); _statusEffectsSystem.TryAddStatusEffect<IncorporealComponent>(msg.Performer, "Incorporeal",
TimeSpan.FromSeconds(10), false);
msg.Handled = true; msg.Handled = true;
Speak(msg); Speak(msg);
@@ -252,7 +256,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnBlinkSpell(BlinkSpellEvent msg) private void OnBlinkSpell(BlinkSpellEvent msg)
{ {
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer)) if (!CanCast(msg))
return; return;
var transform = Transform(msg.Performer); var transform = Transform(msg.Performer);
@@ -291,8 +295,8 @@ public sealed class WizardSpellsSystem : EntitySystem
_audio.PlayPvs("/Audio/White/Cult/veilin.ogg", coords); _audio.PlayPvs("/Audio/White/Cult/veilin.ogg", coords);
_audio.PlayPvs("/Audio/White/Cult/veilout.ogg", oldCoords); _audio.PlayPvs("/Audio/White/Cult/veilout.ogg", oldCoords);
Spawn("AdminInstantEffectSmoke10", oldCoords); Spawn("AdminInstantEffectSmoke3", oldCoords);
Spawn("AdminInstantEffectSmoke10", coords); Spawn("AdminInstantEffectSmoke3", coords);
msg.Handled = true; msg.Handled = true;
Speak(msg); Speak(msg);
@@ -304,7 +308,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnForcewallSpell(ForceWallSpellEvent msg) private void OnForcewallSpell(ForceWallSpellEvent msg)
{ {
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer)) if (!CanCast(msg))
return; return;
switch (msg.ActionUseType) switch (msg.ActionUseType)
@@ -372,7 +376,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnCardsSpell(CardsSpellEvent msg) private void OnCardsSpell(CardsSpellEvent msg)
{ {
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer)) if (!CanCast(msg))
return; return;
var result = true; var result = true;
@@ -413,7 +417,8 @@ public sealed class WizardSpellsSystem : EntitySystem
var ent = Spawn(msg.Prototype, spawnCoords); var ent = Spawn(msg.Prototype, spawnCoords);
var direction = msg.Target.ToMapPos(EntityManager, _transformSystem) - spawnCoords.ToMapPos(EntityManager, _transformSystem); var direction = msg.Target.ToMapPos(EntityManager, _transformSystem) -
spawnCoords.ToMapPos(EntityManager, _transformSystem);
var randomizedDirection = direction + new Vector2(_random.Next(-2, 2), _random.Next(-2, 2)); var randomizedDirection = direction + new Vector2(_random.Next(-2, 2), _random.Next(-2, 2));
_throwingSystem.TryThrow(ent, randomizedDirection, 60, msg.Performer); _throwingSystem.TryThrow(ent, randomizedDirection, 60, msg.Performer);
@@ -425,14 +430,15 @@ public sealed class WizardSpellsSystem : EntitySystem
{ {
var xform = Transform(msg.Performer); var xform = Transform(msg.Performer);
var count = 10 * msg.ChargeLevel; var count = 10 + 10 * msg.ChargeLevel;
var angleStep = 360f / count; var angleStep = 360f / count;
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
var angle = i * angleStep; var angle = i * angleStep;
var direction = new Vector2(MathF.Cos(MathHelper.DegreesToRadians(angle)), MathF.Sin(MathHelper.DegreesToRadians(angle))); var direction = new Vector2(MathF.Cos(MathHelper.DegreesToRadians(angle)),
MathF.Sin(MathHelper.DegreesToRadians(angle)));
foreach (var pos in _magicSystem.GetSpawnPositions(xform, msg.Pos)) foreach (var pos in _magicSystem.GetSpawnPositions(xform, msg.Pos))
{ {
@@ -453,7 +459,7 @@ public sealed class WizardSpellsSystem : EntitySystem
{ {
if (!HasComp<ItemComponent>(msg.TargetUid)) if (!HasComp<ItemComponent>(msg.TargetUid))
{ {
_popupSystem.PopupEntity("Работает только на предметах.", msg.Performer, msg.Performer); _popupSystem.PopupEntity("В карту можно превратить только предметы.", msg.Performer, msg.Performer);
return false; return false;
} }
@@ -470,7 +476,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnFireballSpell(FireballSpellEvent msg) private void OnFireballSpell(FireballSpellEvent msg)
{ {
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer)) if (!CanCast(msg))
return; return;
var result = true; var result = true;
@@ -513,7 +519,8 @@ public sealed class WizardSpellsSystem : EntitySystem
userVelocity = physics.LinearVelocity; userVelocity = physics.LinearVelocity;
var ent = Spawn(msg.Prototype, spawnCoords); var ent = Spawn(msg.Prototype, spawnCoords);
var direction = msg.Target.ToMapPos(EntityManager, _transformSystem) - spawnCoords.ToMapPos(EntityManager, _transformSystem); var direction = msg.Target.ToMapPos(EntityManager, _transformSystem) -
spawnCoords.ToMapPos(EntityManager, _transformSystem);
_gunSystem.ShootProjectile(ent, direction, userVelocity, msg.Performer, msg.Performer); _gunSystem.ShootProjectile(ent, direction, userVelocity, msg.Performer, msg.Performer);
} }
} }
@@ -554,9 +561,11 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnForceSpell(ForceSpellEvent msg) private void OnForceSpell(ForceSpellEvent msg)
{ {
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer)) if (!CanCast(msg))
return; return;
var result = true;
switch (msg.ActionUseType) switch (msg.ActionUseType)
{ {
case ActionUseType.Default: case ActionUseType.Default:
@@ -566,28 +575,41 @@ public sealed class WizardSpellsSystem : EntitySystem
ForceSpellCharge(msg); ForceSpellCharge(msg);
break; break;
case ActionUseType.AltUse: case ActionUseType.AltUse:
ForceSpellAlt(msg); result = ForceSpellAlt(msg);
break; break;
} }
if (!result)
return;
SetCooldown(msg.Action, msg.ActionUseType); SetCooldown(msg.Action, msg.ActionUseType);
msg.Handled = true; msg.Handled = true;
Speak(msg); Speak(msg);
} }
private void ForceSpellDefault(ForceSpellEvent msg) private bool ForceSpellAlt(ForceSpellEvent msg)
{ {
Spawn("AdminInstantEffectMinusGravityWell", msg.Target); if (!HasComp<TransformComponent>(msg.TargetUid) || !HasComp<PhysicsComponent>(msg.TargetUid))
{
_popupSystem.PopupEntity("Невозможно это притянуть!", msg.Performer, msg.Performer);
return false;
}
_throwingSystem.TryThrow(msg.TargetUid, Transform(msg.Performer).Coordinates, 5f);
_standing.TryLieDown(msg.TargetUid);
return true;
} }
private void ForceSpellCharge(ForceSpellEvent msg) private void ForceSpellCharge(ForceSpellEvent msg)
{ {
_gravityWell.GravPulse(msg.Performer, 15, 0, -80 * msg.ChargeLevel, -2 * msg.ChargeLevel); _gravityWell.GravPulse(msg.Performer, 15, 0, -80 * msg.ChargeLevel, -2 * msg.ChargeLevel, null, msg.ChargeLevel,
new() {msg.Performer});
} }
private void ForceSpellAlt(ForceSpellEvent msg) private void ForceSpellDefault(ForceSpellEvent msg)
{ {
_gravityWell.GravPulse(msg.Target, 10, 0, 200, 10); _gravityWell.GravPulse(msg.Target, 10, 0, 200, 10, 2f, new() {msg.Performer});
} }
#endregion #endregion
@@ -596,7 +618,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnArcSpell(ArcSpellEvent msg) private void OnArcSpell(ArcSpellEvent msg)
{ {
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer)) if (!CanCast(msg))
return; return;
var result = true; var result = true;
@@ -632,7 +654,7 @@ public sealed class WizardSpellsSystem : EntitySystem
var entityUids = entitiesToHit.ToList(); var entityUids = entitiesToHit.ToList();
foreach (var entity in entityUids) foreach (var entity in entityUids)
{ {
_lightning.ShootLightning(msg.Performer, entity); _lightning.ShootLightning(msg.Performer, entity, "WizardLightning", true, msg.Performer);
} }
return entityUids.Count != 0; return entityUids.Count != 0;
@@ -640,7 +662,8 @@ public sealed class WizardSpellsSystem : EntitySystem
private void ArcSpellCharge(ArcSpellEvent msg) private void ArcSpellCharge(ArcSpellEvent msg)
{ {
_lightning.ShootRandomLightnings(msg.Performer, 2 * msg.ChargeLevel, msg.ChargeLevel * 2, arcDepth: 2); _lightning.ShootRandomLightnings(msg.Performer, 2f * msg.ChargeLevel, msg.ChargeLevel * 2, "WizardLightning", 1,
caster: msg.Performer);
} }
private void ArcSpellAlt(ArcSpellEvent msg) private void ArcSpellAlt(ArcSpellEvent msg)
@@ -660,7 +683,8 @@ public sealed class WizardSpellsSystem : EntitySystem
userVelocity = physics.LinearVelocity; userVelocity = physics.LinearVelocity;
var ent = Spawn(msg.Prototype, spawnCoords); var ent = Spawn(msg.Prototype, spawnCoords);
var direction = msg.Target.ToMapPos(EntityManager, _transformSystem) - spawnCoords.ToMapPos(EntityManager, _transformSystem); var direction = msg.Target.ToMapPos(EntityManager, _transformSystem) -
spawnCoords.ToMapPos(EntityManager, _transformSystem);
_gunSystem.ShootProjectile(ent, direction, userVelocity, msg.Performer, msg.Performer); _gunSystem.ShootProjectile(ent, direction, userVelocity, msg.Performer, msg.Performer);
} }
} }
@@ -669,6 +693,12 @@ public sealed class WizardSpellsSystem : EntitySystem
#region Helpers #region Helpers
private bool CanCast(BaseActionEvent msg)
{
return !msg.Handled && CheckRequirements(msg.Action, msg.Performer) &&
!_statusEffectsSystem.HasStatusEffect(msg.Performer, "Incorporeal");
}
private void Speak(BaseActionEvent args) private void Speak(BaseActionEvent args)
{ {
if (args is not ISpeakSpell speak || string.IsNullOrWhiteSpace(speak.Speech)) if (args is not ISpeakSpell speak || string.IsNullOrWhiteSpace(speak.Speech))
@@ -743,7 +773,7 @@ public sealed class WizardSpellsSystem : EntitySystem
if (!hasReqs) if (!hasReqs)
{ {
args.Cancelled = true; args.Cancelled = true;
_popupSystem.PopupEntity("Missing Requirements! You need to wear your robe and hat!", args.Performer, args.Performer); _popupSystem.PopupEntity(Loc.GetString("magic-component-missing-req"), args.Performer, args.Performer);
} }
} }

View File

@@ -0,0 +1 @@
magic-component-missing-req = Missing Requirements! You need to wear your robe and hat!

View File

@@ -15,3 +15,5 @@ wizard-welcome = Вы - космический волшебник. Федера
wizard-no-more-threat-announcement-shuttle-call = Судя по данным наших датчиков дальнего действия, магическая угроза была устранена. Эвакуационный шаттл скоро прибудет. Время прибытия: {$time} {$units}. Вы можете отозвать его, чтобы продлить смену. wizard-no-more-threat-announcement-shuttle-call = Судя по данным наших датчиков дальнего действия, магическая угроза была устранена. Эвакуационный шаттл скоро прибудет. Время прибытия: {$time} {$units}. Вы можете отозвать его, чтобы продлить смену.
wizard-no-more-threat-announcement = Судя по данным наших датчиков дальнего действия, магическая угроза была устранена. Шаттл уже вызван. wizard-no-more-threat-announcement = Судя по данным наших датчиков дальнего действия, магическая угроза была устранена. Шаттл уже вызван.
magic-component-missing-req = Недостающие требования! Вам необходимо надеть мантию и шляпу!

View File

@@ -1,4 +1,4 @@
- type: entity - type: entity
name: lightning name: lightning
id: BaseLightning id: BaseLightning
abstract: true abstract: true
@@ -60,6 +60,9 @@
castShadows: false castShadows: false
- type: Lightning - type: Lightning
canArc: false canArc: false
- type: Electrified
requirePower: false
ignoreInsulation: true
shockDamage: 30 shockDamage: 30
- type: entity - type: entity
@@ -159,3 +162,17 @@
softness: 1 softness: 1
autoRot: true autoRot: true
castShadows: false castShadows: false
- type: entity
name: wizard lightning
id: WizardLightning
parent: BaseLightning
noSpawn: true
components:
- type: Electrified
requirePower: false
ignoreInsulation: true
shockDamage: 40
- type: Lightning
canArc: true
lightningPrototype: WizardLightning

View File

@@ -4,8 +4,10 @@
description: This spell opens nearby doors. description: This spell opens nearby doors.
noSpawn: true noSpawn: true
components: components:
- type: Magic
requiresClothes: false
- type: InstantAction - type: InstantAction
useDelay: 10 useDelay: 8
itemIconStyle: BigAction itemIconStyle: BigAction
checkCanInteract: false checkCanInteract: false
icon: icon:

View File

@@ -38,8 +38,6 @@
name: Force name: Force
noSpawn: true noSpawn: true
components: components:
- type: Magic
requiresClothes: true
- type: WorldTargetAction - type: WorldTargetAction
itemIconStyle: BigAction itemIconStyle: BigAction
useDelay: 60 useDelay: 60
@@ -63,8 +61,8 @@
speech: "EL DRITCH!" speech: "EL DRITCH!"
- type: VariableUseDelay - type: VariableUseDelay
useDelay: 6 useDelay: 6
altUseDelay: 12 altUseDelay: 2
chargeUseDelay: 40 chargeUseDelay: 20
- type: entity - type: entity
id: ActionFireballSpell id: ActionFireballSpell
@@ -93,8 +91,8 @@
posData: !type:TargetCasterPos posData: !type:TargetCasterPos
speech: action-speech-spell-fireball speech: action-speech-spell-fireball
- type: VariableUseDelay - type: VariableUseDelay
useDelay: 6 useDelay: 5
altUseDelay: 12 altUseDelay: 10
chargeUseDelay: 40 chargeUseDelay: 40
- type: entity - type: entity
@@ -102,8 +100,6 @@
name: Cards name: Cards
noSpawn: true noSpawn: true
components: components:
- type: Magic
requiresClothes: true
- type: WorldTargetAction - type: WorldTargetAction
itemIconStyle: BigAction itemIconStyle: BigAction
useDelay: 60 useDelay: 60
@@ -128,7 +124,7 @@
posData: !type:TargetCasterPos posData: !type:TargetCasterPos
speech: "SHIZO NERO!" speech: "SHIZO NERO!"
- type: VariableUseDelay - type: VariableUseDelay
useDelay: 6 useDelay: 4
altUseDelay: 1 altUseDelay: 1
chargeUseDelay: 40 chargeUseDelay: 40
@@ -220,12 +216,10 @@
name: Cluwne Curse name: Cluwne Curse
noSpawn: true noSpawn: true
components: components:
- type: Magic
requiresClothes: true
- type: EntityTargetAction - type: EntityTargetAction
canTargetSelf: false canTargetSelf: false
range: 2 range: 3
useDelay: 400 useDelay: 60
itemIconStyle: BigAction itemIconStyle: BigAction
icon: icon:
sprite: Objects/Magic/magicactions.rsi sprite: Objects/Magic/magicactions.rsi
@@ -238,12 +232,10 @@
name: Banana Touch name: Banana Touch
noSpawn: true noSpawn: true
components: components:
- type: Magic
requiresClothes: true
- type: EntityTargetAction - type: EntityTargetAction
canTargetSelf: false canTargetSelf: false
range: 2 range: 3
useDelay: 200 useDelay: 30
itemIconStyle: BigAction itemIconStyle: BigAction
icon: icon:
sprite: Objects/Magic/magicactions.rsi sprite: Objects/Magic/magicactions.rsi
@@ -256,12 +248,10 @@
name: Mime Touch name: Mime Touch
noSpawn: true noSpawn: true
components: components:
- type: Magic
requiresClothes: true
- type: EntityTargetAction - type: EntityTargetAction
canTargetSelf: false canTargetSelf: false
range: 2 range: 3
useDelay: 200 useDelay: 30
itemIconStyle: BigAction itemIconStyle: BigAction
icon: icon:
sprite: Objects/Magic/magicactions.rsi sprite: Objects/Magic/magicactions.rsi
@@ -275,8 +265,6 @@
noSpawn: true noSpawn: true
components: components:
- type: InstantRecall - type: InstantRecall
- type: Magic
requiresClothes: true
- type: InstantAction - type: InstantAction
useDelay: 10 useDelay: 10
itemIconStyle: BigAction itemIconStyle: BigAction

View File

@@ -1,4 +1,4 @@
- type: entity - type: entity
id: BaseScroll id: BaseScroll
parent: BaseItem parent: BaseItem
name: "Magic Scroll" name: "Magic Scroll"
@@ -11,6 +11,7 @@
layers: layers:
- state: scroll - state: scroll
- type: Scroll - type: Scroll
learnTime: 1
useSound: useSound:
path: /Audio/White/Items/scroll/use.ogg path: /Audio/White/Items/scroll/use.ogg
afterUseSound: afterUseSound: