Skip to content

Commit

Permalink
Merge pull request space-wizards#225 from ss14Starlight/Shooting_2.0
Browse files Browse the repository at this point in the history
Shooting 2.0
  • Loading branch information
Rinary1 authored Jan 10, 2025
2 parents 7683ff3 + cc846b0 commit 9f639af
Show file tree
Hide file tree
Showing 55 changed files with 1,314 additions and 340 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/yaml-linter.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
- name: Setup .NET Core
uses: actions/[email protected]
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: Install dependencies
run: dotnet restore
- name: Build
Expand Down
187 changes: 162 additions & 25 deletions Content.Client/Weapons/Ranged/Systems/GunSystem.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
using System;
using System.Diagnostics;
using System.Numerics;
using System.Threading.Tasks;
using Content.Client.Animations;
using Content.Client.DisplacementMap;
using Content.Client.Gameplay;
using Content.Client.Items;
using Content.Client.Weapons.Ranged.Components;
using Content.Shared._Starlight.Effects;
using Content.Shared._Starlight.Weapon.Components;
using Content.Shared.Camera;
using Content.Shared.CombatMode;
using Content.Shared.DisplacementMap;
using Content.Shared.Mech.Components;
using Content.Shared.Weapons.Ranged;
using Content.Shared.Weapons.Ranged.Components;
Expand All @@ -21,7 +28,9 @@
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using static Content.Shared.Fax.AdminFaxEuiMsg;
using SharedGunSystem = Content.Shared.Weapons.Ranged.Systems.SharedGunSystem;
using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent;

Expand All @@ -34,13 +43,17 @@ public sealed partial class GunSystem : SharedGunSystem
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IStateManager _state = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly AnimationPlayerSystem _animPlayer = default!;
[Dependency] private readonly InputSystem _inputSystem = default!;
[Dependency] private readonly SharedCameraRecoilSystem _recoil = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;
[Dependency] private readonly DisplacementMapSystem _displacement = default!;

[ValidatePrototypeId<EntityPrototype>]
public const string HitscanProto = "HitscanEffect";
public const string ImpactProto = "ImpactEffect";
private DisplacementEffect _displacementEffect = null!;

public bool SpreadOverlay
{
Expand Down Expand Up @@ -86,6 +99,8 @@ public override void Initialize()

InitializeMagazineVisuals();
InitializeSpentAmmo();

_displacementEffect = _proto.Index<DisplacementEffect>("displacementEffect");
}

private void OnUpdateClientAmmo(EntityUid uid, AmmoCounterComponent ammoComp, ref UpdateClientAmmoEvent args)
Expand All @@ -102,45 +117,159 @@ private void OnMuzzleFlash(MuzzleFlashEvent args)

private void OnHitscan(HitscanEvent ev)
{
// ALL I WANT IS AN ANIMATED EFFECT
foreach (var a in ev.Sprites)
if (ev.MuzzleFlash is not null)
RenderFlash(ev.MuzzleFlash.Value.coordinates, ev.MuzzleFlash.Value.angle, ev.MuzzleFlash.Value.Sprite, ev.MuzzleFlash.Value.Distance, false, false);
if (ev.Bullet is not null)
RenderBullet(ev.Bullet.Value.coordinates, ev.Bullet.Value.angle, ev.Bullet.Value.Sprite, ev.Bullet.Value.Distance);
if (ev.TravelFlash is not null)
RenderFlash(ev.TravelFlash.Value.coordinates, ev.TravelFlash.Value.angle, ev.TravelFlash.Value.Sprite, ev.TravelFlash.Value.Distance, true, false);
if (ev.ImpactFlash is not null || ev.Impact is not null)
Timer.Spawn(100, () =>
{
if (ev.ImpactFlash is not null)
RenderFlash(ev.ImpactFlash.Value.coordinates, ev.ImpactFlash.Value.angle, ev.ImpactFlash.Value.Sprite, ev.ImpactFlash.Value.Distance, false, true);
if (ev.Impact is not null && GetEntity(ev.Impact.Value.target) is EntityUid target)
RenderDisplacementImpact(GetCoordinates(ev.Impact.Value.coordinates), ev.Impact.Value.angle, target);
});
}
private void RenderDisplacementImpact(EntityCoordinates coords, Angle angle, EntityUid target)
{
if (!TryComp<SpriteComponent>(target, out var sprite))
return;

if (Deleted(coords.EntityId))
return;

if (!sprite!.AllLayers.TryFirstOrDefault(x => (x.ActualRsi ?? x.Rsi) != null && x.RsiState != null, out var layer))
return;

if (layer.PixelSize.X != 32 || layer.PixelSize.Y != 32)
return;

var ent = Spawn(ImpactProto, coords);
var spriteComp = Comp<SpriteComponent>(ent);
var xform = Transform(ent);
xform.LocalRotation = angle;
spriteComp.LayerSetRSI("unshaded", (layer!.ActualRsi ?? layer.Rsi)!);
spriteComp.LayerSetState("unshaded", layer.RsiState);
spriteComp["unshaded"].Visible = true;
_displacement.TryAddDisplacement(_displacementEffect.Displacement, spriteComp, 0, "unshaded", new HashSet<string>());
}
private void RenderBullet(NetCoordinates coordinates, Angle angle, SpriteSpecifier sprite, float distance)
{
if (sprite is not SpriteSpecifier.Rsi rsi)
return;

var coords = GetCoordinates(coordinates);

if (Deleted(coords.EntityId))
return;

var ent = Spawn(HitscanProto, coords);
var spriteComp = Comp<SpriteComponent>(ent);
var xform = Transform(ent);
xform.LocalRotation = angle;
spriteComp[EffectLayers.Unshaded].AutoAnimated = false;
spriteComp.LayerSetSprite(EffectLayers.Unshaded, rsi);
spriteComp.LayerSetState(EffectLayers.Unshaded, rsi.RsiState);
spriteComp.Offset = new Vector2(1f, 0f);
spriteComp.Rotation = 1.5708f;
spriteComp[EffectLayers.Unshaded].Visible = true;

var anim = new Animation()
{
if (a.Sprite is not SpriteSpecifier.Rsi rsi)
continue;
Length = TimeSpan.FromSeconds(0.15f),
AnimationTracks =
{
new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Offset),
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(new Vector2(1f, 0f), 0),
new AnimationTrackProperty.KeyFrame(new Vector2(distance + 1.0f, 0f), 0.09f),
},
InterpolationMode = AnimationInterpolationMode.Cubic
}
}
};

var coords = GetCoordinates(a.coordinates);
_animPlayer.Play(ent, anim, "hitscan-effect");
}
private void RenderFlash(NetCoordinates coordinates, Angle angle, SpriteSpecifier sprite, float distance, bool travel, bool end)
{
if (sprite is not SpriteSpecifier.Rsi rsi)
return;

if (Deleted(coords.EntityId))
continue;
var coords = GetCoordinates(coordinates);

var ent = Spawn(HitscanProto, coords);
var sprite = Comp<SpriteComponent>(ent);
var xform = Transform(ent);
xform.LocalRotation = a.angle;
sprite[EffectLayers.Unshaded].AutoAnimated = false;
sprite.LayerSetSprite(EffectLayers.Unshaded, rsi);
sprite.LayerSetState(EffectLayers.Unshaded, rsi.RsiState);
sprite.Scale = new Vector2(a.Distance, 1f);
sprite[EffectLayers.Unshaded].Visible = true;

var anim = new Animation()
{
Length = TimeSpan.FromSeconds(0.48f),
AnimationTracks =
if (Deleted(coords.EntityId))
return;

var ent = Spawn(HitscanProto, coords);
var spriteComp = Comp<SpriteComponent>(ent);
var xform = Transform(ent);
xform.LocalRotation = angle;
spriteComp[EffectLayers.Unshaded].AutoAnimated = false;
spriteComp.LayerSetSprite(EffectLayers.Unshaded, rsi);
spriteComp.LayerSetState(EffectLayers.Unshaded, rsi.RsiState);
if (travel)
{
spriteComp.Scale = new Vector2(0.05f, 0.5f);
spriteComp.Offset = new Vector2(distance * -0.5f, 0f);
}
else
spriteComp.Scale = new Vector2(1f, 0.5f);

spriteComp[EffectLayers.Unshaded].Visible = true;

var anim = new Animation()
{
Length = end ? TimeSpan.FromSeconds(0.05f)
: TimeSpan.FromSeconds(0.15f),
AnimationTracks =
{
new AnimationTrackSpriteFlick()
{
LayerKey = EffectLayers.Unshaded,
KeyFrames =
{
new AnimationTrackSpriteFlick.KeyFrame(rsi.RsiState, 0f),
new AnimationTrackSpriteFlick.KeyFrame(rsi.RsiState, end? 0f: 0.10f),
}
}
}
};
};

_animPlayer.Play(ent, anim, "hitscan-effect");
if (travel)
{
anim.AnimationTracks.Add(new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Scale),
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(new Vector2(0.05f, 0.5f), 0),
new AnimationTrackProperty.KeyFrame(new Vector2(distance, 0.5f), 0.10f),
new AnimationTrackProperty.KeyFrame(new Vector2(distance, 0.5f), 0.15f),
},
InterpolationMode = AnimationInterpolationMode.Cubic
});
anim.AnimationTracks.Add(new AnimationTrackComponentProperty()
{
ComponentType = typeof(SpriteComponent),
Property = nameof(SpriteComponent.Offset),
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(new Vector2(distance * -0.5f, 0f), 0),
new AnimationTrackProperty.KeyFrame(new Vector2(0, 0f), 0.10f),
new AnimationTrackProperty.KeyFrame(new Vector2(0, 0f), 0.15f),
},
InterpolationMode = AnimationInterpolationMode.Cubic
});
}

_animPlayer.Play(ent, anim, "hitscan-effect");
}

public override void Update(float frameTime)
Expand Down Expand Up @@ -231,6 +360,14 @@ public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid?

switch (shootable)
{
//🌟Starlight🌟
case HitScanCartridgeAmmoComponent cartridge:
SetCartridgeSpent(ent!.Value, cartridge, true);
MuzzleFlash(gunUid, cartridge, worldAngle, user);
Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user);
Recoil(user, direction, gun.CameraRecoilScalarModified);
break;

case CartridgeAmmoComponent cartridge:
if (!cartridge.Spent)
{
Expand Down Expand Up @@ -354,7 +491,7 @@ protected override void CreateEffect(EntityUid gunUid, MuzzleFlashEvent message,
_animPlayer.Play(ent, anim, "muzzle-flash");
if (!TryComp(gunUid, out PointLightComponent? light))
{
light = (PointLightComponent) _factory.GetComponent(typeof(PointLightComponent));
light = (PointLightComponent)_factory.GetComponent(typeof(PointLightComponent));
light.NetSyncEnabled = false;
AddComp(gunUid, light);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ await server.WaitAssertion(() =>
{
playerUid = serverPlayerManager.Sessions.Single().AttachedEntity.GetValueOrDefault();
#pragma warning disable NUnit2045 // Interdependent assertions.
Assert.That(playerUid, Is.Not.EqualTo(default));
Assert.That(playerUid, Is.Not.EqualTo(default(EntityUid)));
// Making sure it exists
Assert.That(entManager.HasComponent<AlertsComponent>(playerUid));
#pragma warning restore NUnit2045
Expand Down
1 change: 0 additions & 1 deletion Content.IntegrationTests/Tests/PostMapInitTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
using Robust.Shared.Map.Components;
using Robust.Shared.Prototypes;
using Content.Shared.Station.Components;
using FastAccessors;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,5 @@ public sealed partial class ReagentProducerAnomalyComponent : Component
/// <summary>
/// Solution where the substance is generated
/// </summary>
[DataField("solutionRef")]
public Entity<SolutionComponent>? Solution = null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ public sealed partial class GasCondenserComponent : Component
/// <summary>
/// The solution that gases are condensed into.
/// </summary>
[DataField]
public Entity<SolutionComponent>? Solution = null;

/// <summary>
Expand Down
3 changes: 0 additions & 3 deletions Content.Server/Body/Components/BloodstreamComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,21 +157,18 @@ public sealed partial class BloodstreamComponent : Component
/// <summary>
/// Internal solution for blood storage
/// </summary>
[DataField]
public Entity<SolutionComponent>? BloodSolution = null;

/// <summary>
/// Internal solution for reagent storage
/// </summary>
[DataField]
public Entity<SolutionComponent>? ChemicalSolution = null;

/// <summary>
/// Temporary blood solution.
/// When blood is lost, it goes to this solution, and when this
/// solution hits a certain cap, the blood is actually spilled as a puddle.
/// </summary>
[DataField]
public Entity<SolutionComponent>? TemporarySolution = null;

/// <summary>
Expand Down
1 change: 0 additions & 1 deletion Content.Server/Body/Components/LungComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ public sealed partial class LungComponent : Component
/// <summary>
/// The solution on this entity that these lungs act on.
/// </summary>
[DataField]
public Entity<SolutionComponent>? Solution = null;

/// <summary>
Expand Down
1 change: 0 additions & 1 deletion Content.Server/Body/Components/StomachComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ public sealed partial class StomachComponent : Component
/// <summary>
/// The solution inside of this stomach this transfers reagents to the body.
/// </summary>
[DataField]
public Entity<SolutionComponent>? Solution = null;

/// <summary>
Expand Down
1 change: 0 additions & 1 deletion Content.Server/Botany/Components/PlantHolderComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,5 @@ public sealed partial class PlantHolderComponent : Component
[DataField]
public string SoilSolutionName = "soil";

[DataField]
public Entity<SolutionComponent>? SoilSolution = null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public sealed partial class SolutionRegenerationComponent : Component
/// <summary>
/// The solution to add reagents to.
/// </summary>
[DataField]
public Entity<SolutionComponent>? SolutionRef = null;

/// <summary>
Expand Down
Loading

0 comments on commit 9f639af

Please sign in to comment.