Files
wwdpublic/Content.Client/Weapons/Ranged/GunSpreadOverlay.cs
RedFoxIV af21168537 Fuselage rust (#551)
* the definition of insanity

* the definition of insanity

* the definition of insanity

* we have hullrot at home

* maybe the real hullrot was the friends we made along the way

* john hullrot

* i am going to hullroooooot

* it's hullrotver

* we're so hullback

* we're rotting the hull with this one

* hullmerge

* the hullrot is leaking

* never gonna rot you up

* hullfresh

* john starsector

* god i wish we had grid collision damage
2025-06-11 11:04:48 +03:00

243 lines
10 KiB
C#

using System.Numerics;
using Content.Client.Resources;
using Content.Client.Stylesheets;
using Content.Client.Viewport;
using Content.Client.Weapons.Ranged.Systems;
using Content.Shared.CombatMode;
using Content.Shared.Contests;
using Content.Shared.Weapons.Ranged.Components;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.Player;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.Utility;
using Robust.Shared.ContentPack;
using Robust.Shared.Enums;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.Weapons.Ranged;
// WWDP EDIT START
// so much shit was tossed around and changed, it's easier to assume
// the entire file is changed.
[Virtual]
public class GunSpreadOverlay : Overlay
{
public override OverlaySpace Space => OverlaySpace.WorldSpace;
protected IEntityManager _entManager;
protected readonly IEyeManager _eye;
protected readonly IGameTiming _timing;
protected readonly IInputManager _input;
protected readonly IPlayerManager _player;
protected readonly IUserInterfaceManager _userInterface;
protected readonly GunSystem _guns;
protected readonly SharedTransformSystem _transform;
protected readonly ContestsSystem _contest;
public GunSpreadOverlay(IEntityManager entManager, IEyeManager eyeManager, IGameTiming timing, IInputManager input, IPlayerManager player, IUserInterfaceManager userInterface, GunSystem system, SharedTransformSystem transform, ContestsSystem contest)
{
_entManager = entManager;
_eye = eyeManager;
_input = input;
_timing = timing;
_player = player;
_userInterface = userInterface;
_guns = system;
_transform = transform;
_contest = contest;
}
protected override void Draw(in OverlayDrawArgs args)
{
var worldHandle = args.WorldHandle;
var player = _player.LocalEntity;
if(player is null)
{
Reset();
return;
}
if(!_entManager.TryGetComponent<CombatModeComponent>(player, out var combatMode) || !combatMode.IsInCombatMode)
{
Reset();
return;
}
if (player == null ||
!_entManager.TryGetComponent<TransformComponent>(player, out var xform))
{
Reset();
return;
}
var mapPos = _transform.GetMapCoordinates(player.Value, xform: xform);
if (mapPos.MapId == MapId.Nullspace)
{
Reset();
return;
}
if (!_guns.TryGetGun(player.Value, out var gunUid, out var gun))
{
Reset();
return;
}
var contest = 1 / _contest.MassContest(player);
var mouseScreenPos = _input.MouseScreenPosition;
var mousePos = _eye.PixelToMap(mouseScreenPos);
if (mapPos.MapId != mousePos.MapId)
{
Reset();
return;
}
// (☞゚ヮ゚)☞
double timeSinceLastFire = (_timing.CurTime - gun.CurrentAngleLastUpdate).TotalSeconds;
double timeSinceLastBonusUpdate = (_timing.CurTime - gun.BonusAngleLastUpdate).TotalSeconds;
double maxBonusSpread = gun.MaxBonusAngleModified * contest / 2;
double minSpread = Math.Max(gun.MinAngleModified, 0) * contest / 2;
double maxSpread = gun.MaxAngleModified * contest / 2;
double bonusSpread = new Angle(MathHelper.Clamp((gun.BonusAngle - gun.BonusAngleDecayModified * timeSinceLastBonusUpdate) / 2,
0, maxBonusSpread)) * contest;
double currentAngle = new Angle(MathHelper.Clamp((gun.CurrentAngle.Theta - gun.AngleDecayModified.Theta * timeSinceLastFire) / 2,
minSpread, maxSpread)) * contest;
var direction = (mousePos.Position - mapPos.Position);
Vector2 from = mapPos.Position;
if (_guns.IsRestrictedFire(gunUid, player.Value))
direction = new Angle(_transform.GetWorldRotation(gunUid) - direction.ToWorldAngle()).RotateVec(direction);
DrawSpread(worldHandle, gun, from, direction, timeSinceLastFire, maxBonusSpread, bonusSpread, maxSpread, minSpread, currentAngle);
}
protected virtual void DrawCone(DrawingHandleWorld handle, Vector2 from, Vector2 direction, Angle angle, Color color, float lerp = 1f)
{
var dir1 = angle.RotateVec(direction);
var dir2 = (-angle).RotateVec(direction);
handle.DrawLine(from + dir1 * (1 - lerp), from + dir1 * (1 + lerp), color);
handle.DrawLine(from + dir2 * (1 - lerp), from + dir2 * (1 + lerp), color);
}
protected virtual void DrawSpread(DrawingHandleWorld worldHandle, GunComponent gun, Vector2 from, Vector2 direction, double timeSinceLastFire, Angle maxBonusSpread, Angle bonusSpread, Angle maxSpread, Angle minSpread, Angle currentAngle)
{
worldHandle.DrawLine(from, from + direction*2, Color.Orange);
// Show max spread either side
DrawCone(worldHandle, from, direction, maxSpread + bonusSpread, Color.Red);
// Show min spread either side
DrawCone(worldHandle, from, direction, minSpread + bonusSpread, Color.Green);
// Show current angle
DrawCone(worldHandle, from, direction, currentAngle + bonusSpread, Color.Yellow);
DrawCone(worldHandle, from, direction, maxBonusSpread, Color.BetterViolet);
DrawCone(worldHandle, from, direction, bonusSpread, Color.Violet);
var oldTheta = MathHelper.Clamp(gun.CurrentAngle - gun.AngleDecayModified * timeSinceLastFire, gun.MinAngleModified, gun.MaxAngleModified);
var newTheta = MathHelper.Clamp(oldTheta + gun.AngleIncreaseModified.Theta, gun.MinAngleModified.Theta, gun.MaxAngleModified.Theta);
var fullSpread = new Angle(newTheta + bonusSpread);
DrawCone(worldHandle, from, direction, fullSpread, Color.Gray);
}
protected virtual void Reset() { }
}
public sealed class PartialGunSpreadOverlay : GunSpreadOverlay
{
private SpriteSystem _sprite;
private GunComponent? _lastGun;
private double SmoothedCurrentAngle;
private double SmoothedBonusSpread;
private Texture _textureS;
private Texture _textureL;
public PartialGunSpreadOverlay(IEntityManager entManager, IEyeManager eyeManager, IGameTiming timing, IInputManager input, IPlayerManager player, IUserInterfaceManager userInterface, GunSystem system, SharedTransformSystem transform, ContestsSystem contest, SpriteSystem sprite) : base(entManager, eyeManager, timing, input, player, userInterface, system, transform, contest)
{
_sprite = sprite;
_textureS = _sprite.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/_White/Interface/gun-spread-marker-s.png")));
_textureL = _sprite.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/_White/Interface/gun-spread-marker-l.png")));
}
protected override void Reset() { _lastGun = null; }
protected override void DrawSpread(DrawingHandleWorld worldHandle, GunComponent gun, Vector2 from, Vector2 direction, double timeSinceLastFire, Angle maxBonusSpread, Angle bonusSpread, Angle maxSpread, Angle minSpread, Angle currentAngle)
{
if (_lastGun != gun)
{
_lastGun = gun;
SmoothedCurrentAngle = currentAngle;
SmoothedBonusSpread = bonusSpread;
}
else
{
SmoothedCurrentAngle = Double.Lerp(SmoothedCurrentAngle, currentAngle, 0.7);
SmoothedBonusSpread = Double.Lerp(SmoothedBonusSpread, bonusSpread, 0.35);
}
Color color = _userInterface.CurrentTheme.ResolveColorOrSpecified("slotSelectedGold", Color.White);
DrawCone(worldHandle, from, direction, SmoothedCurrentAngle + SmoothedBonusSpread, color, 0.15f);
//DrawCone(worldHandle, from, direction, SmoothedCurrentAngle, color.WithAlpha(0.33f), 0.15f); // no duplicate line, only current
}
protected override void DrawCone(DrawingHandleWorld handle, Vector2 from, Vector2 direction, Angle angle, Color color, float lineLerp = 1f)
{
var mpp = 1f / EyeManager.PixelsPerMeter;
var dir1 = angle.RotateVec(direction);
var dir2 = (-angle).RotateVec(direction);
Angle negRot = -_eye.CurrentEye.Rotation;
handle.SetTransform(from, 0);
Angle ang1 = dir1.ToAngle();
Angle ang2 = dir2.ToAngle();
handle.DrawTextureCentered(_textureL, dir1 * 0.76f, ang1, color);
handle.DrawTextureCentered(_textureL, dir2 * 0.76f, ang2, color);
handle.DrawTextureCentered(_textureS, dir1 * 0.88f, ang1, color);
handle.DrawTextureCentered(_textureS, dir2 * 0.88f, ang2, color);
handle.DrawTextureCentered(_textureL, dir1 * 1f, ang1, color);
handle.DrawTextureCentered(_textureL, dir2 * 1f, ang2, color);
handle.DrawTextureCentered(_textureS, dir1 * 1.12f, ang1, color);
handle.DrawTextureCentered(_textureS, dir2 * 1.12f, ang2, color);
handle.DrawTextureCentered(_textureL, dir1 * 1.24f, ang1, color);
handle.DrawTextureCentered(_textureL, dir2 * 1.24f, ang2, color);
}
}
public static class DrawingHandleWorldExt
{
public static void DrawTextureCentered(this DrawingHandleWorld handle, Texture tex, Vector2 position, Color? color = null) =>
handle.DrawTextureRect(tex, Box2.CenteredAround(position, tex.Size / (float) EyeManager.PixelsPerMeter), color);
public static void DrawTextureCentered(this DrawingHandleWorld handle, Texture tex, Vector2 position, Angle angle, Color? color = null) =>
handle.DrawTextureRect(tex, new Box2Rotated(Box2.CenteredAround(position, tex.Size / (float) EyeManager.PixelsPerMeter), angle, position), color);
public static void DrawRectCentered(this DrawingHandleWorld handle, Vector2 position, Vector2 size, Color color, bool filled = false) =>
handle.DrawRect(Box2.CenteredAround(position, size), color, filled);
public static void DrawRectCentered(this DrawingHandleWorld handle, Vector2 position, Vector2 size, Angle rot, Color color, bool filled = false) =>
handle.DrawRect(new Box2Rotated(Box2.CenteredAround(position, size), rot, position), color, filled);
}