Files
crystall-punk-14/Content.Server/Beam/BeamSystem.cs
Red ecadfb3ea5 Big content update (#1484)
* Add investigator's cloak entity and sprites

Introduced a new investigator's cloak for senior investigators, including its entity definition and associated sprites. Also updated helmet sprites for the guard role.

* Add Investigator job to CP14 roles and assets

Introduces the Investigator job, including English and Russian localization, job prototype, loadout, play time tracker, and status icon. Updates department and role loadout configurations to include the new job. Enables setPreference for Guard and Guard Commander jobs. Adds Investigator job icon and updates related metadata.

* Rebalance mana splitting spell parameters

Reduced mana cost from 15 to 10, adjusted mana change effect, and updated spell event to use a toggleable action with new cast time and distance threshold. Also changed visual effect colors for the spell impact.

* job spawner

* remove mana splitting from mana glove

* Update tools.yml

* reduce memory points to 0.5 for tier magics

* Add CP14 spell to create beams and extend beam system

Introduces CP14SpellCreateBeam, a new spell effect for creating beams using the shared beam system. Adds a virtual TryCreateBeam method to SharedBeamSystem and overrides it in BeamSystem to support shared spell functionality.

* athletic branch refactor

* second wind skill

* minor fixes

* remove skeletons specific spells

* small magic splitting

* Update migration.yml

* clear references

* guidebook species update, -0.5 people memory, innate athletic to carcat, nerf night vision

* disable guards again
2025-06-29 00:02:04 +03:00

180 lines
7.6 KiB
C#

using System.Numerics;
using Content.Server.Beam.Components;
using Content.Shared.Beam;
using Content.Shared.Beam.Components;
using Content.Shared.Physics;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Collision.Shapes;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
namespace Content.Server.Beam;
public sealed class BeamSystem : SharedBeamSystem
{
[Dependency] private readonly FixtureSystem _fixture = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedBroadphaseSystem _broadphase = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BeamComponent, CreateBeamSuccessEvent>(OnBeamCreationSuccess);
SubscribeLocalEvent<BeamComponent, BeamControllerCreatedEvent>(OnControllerCreated);
SubscribeLocalEvent<BeamComponent, BeamFiredEvent>(OnBeamFired);
SubscribeLocalEvent<BeamComponent, ComponentRemove>(OnRemove);
}
private void OnBeamCreationSuccess(EntityUid uid, BeamComponent component, CreateBeamSuccessEvent args)
{
component.BeamShooter = args.User;
}
private void OnControllerCreated(EntityUid uid, BeamComponent component, BeamControllerCreatedEvent args)
{
component.OriginBeam = args.OriginBeam;
}
private void OnBeamFired(EntityUid uid, BeamComponent component, BeamFiredEvent args)
{
component.CreatedBeams.Add(args.CreatedBeam);
}
private void OnRemove(EntityUid uid, BeamComponent component, ComponentRemove args)
{
if (component.VirtualBeamController == null)
return;
if (component.CreatedBeams.Count == 0 && component.VirtualBeamController.Value.Valid)
QueueDel(component.VirtualBeamController.Value);
}
/// <summary>
/// If <see cref="TryCreateBeam"/> is successful, it spawns a beam from the user to the target.
/// </summary>
/// <param name="prototype">The prototype used to make the beam</param>
/// <param name="userAngle">Angle of the user firing the beam</param>
/// <param name="calculatedDistance">The calculated distance from the user to the target.</param>
/// <param name="beamStartPos">Where the beam will spawn in</param>
/// <param name="distanceCorrection">Calculated correction so the <see cref="EdgeShape"/> can be properly dynamically created</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="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,
Angle userAngle,
Vector2 calculatedDistance,
MapCoordinates beamStartPos,
Vector2 distanceCorrection,
EntityUid? controller,
string? bodyState = null,
string shader = "unshaded")
{
var beamSpawnPos = beamStartPos;
var ent = Spawn(prototype, beamSpawnPos);
var shape = new EdgeShape(distanceCorrection, new Vector2(0,0));
if (!TryComp<PhysicsComponent>(ent, out var physics) || !TryComp<BeamComponent>(ent, out var beam))
return;
FixturesComponent? manager = null;
_fixture.TryCreateFixture(
ent,
shape,
"BeamBody",
hard: false,
collisionMask: (int)CollisionGroup.ItemMask,
collisionLayer: (int)CollisionGroup.MobLayer,
manager: manager,
body: physics);
_physics.SetBodyType(ent, BodyType.Dynamic, manager: manager, body: physics);
_physics.SetCanCollide(ent, true, manager: manager, body: physics);
_broadphase.RegenerateContacts((ent, physics, manager));
var distanceLength = distanceCorrection.Length();
var beamVisualizerEvent = new BeamVisualizerEvent(GetNetEntity(ent), distanceLength, userAngle, bodyState, shader);
RaiseNetworkEvent(beamVisualizerEvent);
if (controller != null)
beam.VirtualBeamController = controller;
else
{
var controllerEnt = Spawn("VirtualBeamEntityController", beamSpawnPos);
beam.VirtualBeamController = controllerEnt;
_audio.PlayPvs(beam.Sound, ent);
var beamControllerCreatedEvent = new BeamControllerCreatedEvent(ent, controllerEnt);
RaiseLocalEvent(controllerEnt, beamControllerCreatedEvent);
}
//Create the rest of the beam, sprites handled through the BeamVisualizerEvent
for (var i = 0; i < distanceLength-1; i++)
{
beamSpawnPos = beamSpawnPos.Offset(calculatedDistance.Normalized());
var newEnt = Spawn(prototype, beamSpawnPos);
var ev = new BeamVisualizerEvent(GetNetEntity(newEnt), distanceLength, userAngle, bodyState, shader);
RaiseNetworkEvent(ev);
}
var beamFiredEvent = new BeamFiredEvent(ent);
RaiseLocalEvent(beam.VirtualBeamController.Value, beamFiredEvent);
}
/// <summary>
/// Called where you want an entity to create a beam from one target to another.
/// Tries to create the beam and does calculations like the distance, angle, and offset.
/// </summary>
/// <param name="user">The entity that's firing off the beam</param>
/// <param name="target">The entity that's being targeted by the user</param>
/// <param name="bodyPrototype">The prototype spawned when this beam is created</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="controller"></param>
public override void TryCreateBeam(EntityUid user, EntityUid target, string bodyPrototype, string? bodyState = null, string shader = "unshaded", EntityUid? controller = null) //CP14 override virtual shared method
{
if (Deleted(user) || Deleted(target))
return;
var userMapPos = _transform.GetMapCoordinates(user);
var targetMapPos = _transform.GetMapCoordinates(target);
//The distance between the target and the user.
var calculatedDistance = targetMapPos.Position - userMapPos.Position;
var userAngle = calculatedDistance.ToWorldAngle();
if (userMapPos.MapId != targetMapPos.MapId)
return;
//Where the start of the beam will spawn
var beamStartPos = userMapPos.Offset(calculatedDistance.Normalized());
//Don't divide by zero
if (calculatedDistance.Length() == 0)
return;
if (controller != null && TryComp<BeamComponent>(controller, out var controllerBeamComp))
{
controllerBeamComp.HitTargets.Add(user);
controllerBeamComp.HitTargets.Add(target);
}
var distanceCorrection = calculatedDistance - calculatedDistance.Normalized();
CreateBeam(bodyPrototype, userAngle, calculatedDistance, beamStartPos, distanceCorrection, controller, bodyState, shader);
var ev = new CreateBeamSuccessEvent(user, target);
RaiseLocalEvent(user, ev);
}
}