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

View File

@@ -1,5 +1,6 @@
using System.Numerics;
using Content.Server.Beam.Components;
using Content.Server.Electrocution;
using Content.Shared.Beam;
using Content.Shared.Beam.Components;
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="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>
private void CreateBeam(string prototype,
private IEnumerable<EntityUid> CreateBeam(string prototype,
Angle userAngle,
Vector2 calculatedDistance,
MapCoordinates beamStartPos,
@@ -78,8 +79,10 @@ public sealed class BeamSystem : SharedBeamSystem
var ent = Spawn(prototype, beamSpawnPos);
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))
return;
yield break;
FixturesComponent? manager = null;
_fixture.TryCreateFixture(
@@ -120,6 +123,7 @@ public sealed class BeamSystem : SharedBeamSystem
{
beamSpawnPos = beamSpawnPos.Offset(calculatedDistance.Normalized());
var newEnt = Spawn(prototype, beamSpawnPos);
yield return newEnt;
var ev = new BeamVisualizerEvent(GetNetEntity(newEnt), distanceLength, userAngle, bodyState, shader);
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="shader">Optional shader for the <see cref="bodyPrototype"/> if a default one is not given</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))
return;
yield break;
var userMapPos = Transform(user).MapPosition;
var targetMapPos = Transform(target).MapPosition;
@@ -152,14 +156,14 @@ public sealed class BeamSystem : SharedBeamSystem
var userAngle = calculatedDistance.ToWorldAngle();
if (userMapPos.MapId != targetMapPos.MapId)
return;
yield break;
//Where the start of the beam will spawn
var beamStartPos = userMapPos.Offset(calculatedDistance.Normalized());
//Don't divide by zero
if (calculatedDistance.Length() == 0)
return;
yield break;
if (controller != null && TryComp<BeamComponent>(controller, out var controllerBeamComp))
{
@@ -169,7 +173,12 @@ public sealed class BeamSystem : SharedBeamSystem
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);
RaiseLocalEvent(user, ev);

View File

@@ -85,4 +85,11 @@ public sealed partial class ElectrifiedComponent : Component
[DataField("shockVolume")]
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);
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.
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--)
{
var (entity, depth) = targets[i];
if (entity == electrified.Caster) // WD
continue;
lastRet = TryDoElectrocution(
entity,
uid,
(int) (electrified.ShockDamage * MathF.Pow(RecursiveDamageMultiplier, depth)),
TimeSpan.FromSeconds(electrified.ShockTime * MathF.Pow(RecursiveTimeMultiplier, depth)),
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));
}
}
}

View File

@@ -1,6 +1,7 @@
using System.Linq;
using Content.Server.Beam;
using Content.Server.Beam.Components;
using Content.Server.Electrocution;
using Content.Server.Lightning.Components;
using Content.Shared.Lightning;
using Robust.Shared.Random;
@@ -45,10 +46,16 @@ public sealed class LightningSystem : SharedLightningSystem
/// <param name="target">Where the lightning fires to</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>
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();
_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
{
@@ -66,7 +73,7 @@ public sealed class LightningSystem : SharedLightningSystem
/// <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="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: 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
continue;
ShootLightning(user, targets[count].Owner, lightningPrototype, triggerLightningEvents);
ShootLightning(user, targets[count].Owner, lightningPrototype, triggerLightningEvents, caster); // WD EDIT
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++;
}

View File

@@ -1,5 +1,6 @@
using Content.Server.Atmos.Components;
using Content.Server.Singularity.Components;
using Content.Server.Stunnable;
using Content.Shared.Ghost;
using Content.Shared.Singularity.EntitySystems;
using Robust.Shared.Map;
@@ -24,6 +25,7 @@ public sealed class GravityWellSystem : SharedGravityWellSystem
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly StunSystem _stun = default!; // WD EDIT
#endregion Dependencies
/// <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="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>
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))
GravPulse(xform.Coordinates, maxRange, minRange, baseRadialDeltaV, baseTangentialDeltaV);
GravPulse(xform.Coordinates, maxRange, minRange, baseRadialDeltaV, baseTangentialDeltaV, stunTime, ignore);
}
/// <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="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>
public void GravPulse(EntityCoordinates entityPos, float maxRange, float minRange, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f)
=> GravPulse(entityPos.ToMap(EntityManager, _transform), maxRange, minRange, baseRadialDeltaV, baseTangentialDeltaV);
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, stunTime, ignore);
/// <summary>
/// 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="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>
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)
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))
{
if (ignore?.Contains(entity) is true)
continue;
if (!bodyQuery.TryGetComponent(entity, out var physics)
|| physics.BodyType == BodyType.Static)
{
@@ -206,6 +211,8 @@ public sealed class GravityWellSystem : SharedGravityWellSystem
var scaling = (1f / distance2) * physics.Mass; // TODO: Variable falloff gradiants.
_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="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>
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(
baseRadialDeltaV, +baseTangentialDeltaV, 0.0f,
-baseTangentialDeltaV, baseRadialDeltaV, 0.0f,
0.0f, 0.0f, 1.0f
));
), stunTime, ignore);
#endregion GravPulse

View File

@@ -1,4 +1,4 @@
using System.Linq;
using System.Linq;
using System.Numerics;
using Content.Server._White.IncorporealSystem;
using Content.Server._White.Wizard.Magic.Amaterasu;
@@ -12,6 +12,7 @@ using Content.Server.Emp;
using Content.Server.Lightning;
using Content.Server.Magic;
using Content.Server.Singularity.EntitySystems;
using Content.Server.Standing;
using Content.Server.Weapons.Ranged.Systems;
using Content.Shared._White.Wizard;
using Content.Shared._White.Wizard.Magic;
@@ -62,6 +63,7 @@ public sealed class WizardSpellsSystem : EntitySystem
[Dependency] private readonly InventorySystem _inventory = default!;
[Dependency] private readonly EmpSystem _empSystem = default!;
[Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly StandingStateSystem _standing = default!;
#endregion
@@ -89,7 +91,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnInstantRecallSpell(InstantRecallSpellEvent msg)
{
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
if (!CanCast(msg))
return;
if (!TryComp<HandsComponent>(msg.Performer, out var handsComponent))
@@ -110,11 +112,13 @@ public sealed class WizardSpellsSystem : EntitySystem
}
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;
}
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 coordsPerformer = Transform(msg.Performer).Coordinates;
@@ -139,12 +143,12 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnMimeTouchSpell(MimeTouchSpellEvent msg)
{
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
if (!CanCast(msg))
return;
if (!HasComp<HumanoidAppearanceComponent>(msg.Target))
{
_popupSystem.PopupEntity("Работает только на людях!", msg.Performer, msg.Performer);
_popupSystem.PopupEntity("Работает только на людях!", msg.Performer, msg.Performer);
return;
}
@@ -164,7 +168,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnBananaTouchSpell(BananaTouchSpellEvent msg)
{
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
if (!CanCast(msg))
return;
if (!HasComp<HumanoidAppearanceComponent>(msg.Target))
@@ -188,7 +192,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnCluwneCurseSpell(CluwneCurseSpellEvent msg)
{
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
if (!CanCast(msg))
return;
if (!HasComp<HumanoidAppearanceComponent>(msg.Target))
@@ -197,8 +201,7 @@ public sealed class WizardSpellsSystem : EntitySystem
return;
}
var cluwne = EnsureComp<CluwneComponent>(msg.Target);
cluwne.KnockChance = 0.2f;
EnsureComp<CluwneComponent>(msg.Target);
Spawn("AdminInstantEffectSmoke3", Transform(msg.Target).Coordinates);
@@ -212,7 +215,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnEmpSpell(EmpSpellEvent msg)
{
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
if (!CanCast(msg))
return;
var coords = _transformSystem.ToMapCoordinates(Transform(msg.Performer).Coordinates);
@@ -229,7 +232,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnJauntSpell(EtherealJauntSpellEvent msg)
{
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
if (!CanCast(msg))
return;
if (_statusEffectsSystem.HasStatusEffect(msg.Performer, "Incorporeal"))
@@ -240,7 +243,8 @@ public sealed class WizardSpellsSystem : EntitySystem
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;
Speak(msg);
@@ -252,7 +256,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnBlinkSpell(BlinkSpellEvent msg)
{
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
if (!CanCast(msg))
return;
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/veilout.ogg", oldCoords);
Spawn("AdminInstantEffectSmoke10", oldCoords);
Spawn("AdminInstantEffectSmoke10", coords);
Spawn("AdminInstantEffectSmoke3", oldCoords);
Spawn("AdminInstantEffectSmoke3", coords);
msg.Handled = true;
Speak(msg);
@@ -304,7 +308,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnForcewallSpell(ForceWallSpellEvent msg)
{
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
if (!CanCast(msg))
return;
switch (msg.ActionUseType)
@@ -372,7 +376,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnCardsSpell(CardsSpellEvent msg)
{
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
if (!CanCast(msg))
return;
var result = true;
@@ -413,7 +417,8 @@ public sealed class WizardSpellsSystem : EntitySystem
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));
_throwingSystem.TryThrow(ent, randomizedDirection, 60, msg.Performer);
@@ -425,14 +430,15 @@ public sealed class WizardSpellsSystem : EntitySystem
{
var xform = Transform(msg.Performer);
var count = 10 * msg.ChargeLevel;
var count = 10 + 10 * msg.ChargeLevel;
var angleStep = 360f / count;
for (var i = 0; i < count; i++)
{
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))
{
@@ -453,7 +459,7 @@ public sealed class WizardSpellsSystem : EntitySystem
{
if (!HasComp<ItemComponent>(msg.TargetUid))
{
_popupSystem.PopupEntity("Работает только на предметах.", msg.Performer, msg.Performer);
_popupSystem.PopupEntity("В карту можно превратить только предметы.", msg.Performer, msg.Performer);
return false;
}
@@ -470,7 +476,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnFireballSpell(FireballSpellEvent msg)
{
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
if (!CanCast(msg))
return;
var result = true;
@@ -513,7 +519,8 @@ public sealed class WizardSpellsSystem : EntitySystem
userVelocity = physics.LinearVelocity;
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);
}
}
@@ -554,9 +561,11 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnForceSpell(ForceSpellEvent msg)
{
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
if (!CanCast(msg))
return;
var result = true;
switch (msg.ActionUseType)
{
case ActionUseType.Default:
@@ -566,28 +575,41 @@ public sealed class WizardSpellsSystem : EntitySystem
ForceSpellCharge(msg);
break;
case ActionUseType.AltUse:
ForceSpellAlt(msg);
result = ForceSpellAlt(msg);
break;
}
if (!result)
return;
SetCooldown(msg.Action, msg.ActionUseType);
msg.Handled = true;
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)
{
_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
@@ -596,7 +618,7 @@ public sealed class WizardSpellsSystem : EntitySystem
private void OnArcSpell(ArcSpellEvent msg)
{
if (msg.Handled || !CheckRequirements(msg.Action, msg.Performer))
if (!CanCast(msg))
return;
var result = true;
@@ -632,7 +654,7 @@ public sealed class WizardSpellsSystem : EntitySystem
var entityUids = entitiesToHit.ToList();
foreach (var entity in entityUids)
{
_lightning.ShootLightning(msg.Performer, entity);
_lightning.ShootLightning(msg.Performer, entity, "WizardLightning", true, msg.Performer);
}
return entityUids.Count != 0;
@@ -640,7 +662,8 @@ public sealed class WizardSpellsSystem : EntitySystem
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)
@@ -660,7 +683,8 @@ public sealed class WizardSpellsSystem : EntitySystem
userVelocity = physics.LinearVelocity;
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);
}
}
@@ -669,6 +693,12 @@ public sealed class WizardSpellsSystem : EntitySystem
#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)
{
if (args is not ISpeakSpell speak || string.IsNullOrWhiteSpace(speak.Speech))
@@ -743,7 +773,7 @@ public sealed class WizardSpellsSystem : EntitySystem
if (!hasReqs)
{
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 = Судя по данным наших датчиков дальнего действия, магическая угроза была устранена. Шаттл уже вызван.
magic-component-missing-req = Недостающие требования! Вам необходимо надеть мантию и шляпу!

View File

@@ -1,4 +1,4 @@
- type: entity
- type: entity
name: lightning
id: BaseLightning
abstract: true
@@ -60,6 +60,9 @@
castShadows: false
- type: Lightning
canArc: false
- type: Electrified
requirePower: false
ignoreInsulation: true
shockDamage: 30
- type: entity
@@ -159,3 +162,17 @@
softness: 1
autoRot: true
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.
noSpawn: true
components:
- type: Magic
requiresClothes: false
- type: InstantAction
useDelay: 10
useDelay: 8
itemIconStyle: BigAction
checkCanInteract: false
icon:

View File

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

View File

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