Cherrypick "Shoot Over Bodies" And Related PRs (#479)

# Description
This is a manual cherry-pick of the following PRs:
https://github.com/space-wizards/space-station-14/pull/27905
https://github.com/space-wizards/space-station-14/pull/28072
https://github.com/space-wizards/space-station-14/pull/28571

I REQUIRE these for my work in PR #11 , and cannot complete said PR
without these cherry-picks. This set of PRs from Wizden adds a feature
where entities can selectively opt-out of being shot at unless a player
intentionally targets them, which I can use as a simple and elegant
solution to one of the largest glaring issues for Segmented Entities. I
could simply give Lamia segments the new
RequireProjectileTargetComponent, which adds them to the system. Future
segmented entities such as the hypothetical "Heretic Worm" may or may
not use this feature, depending on their intended implementation.

---------

Co-authored-by: Danger Revolution! <142105406+DangerRevolution@users.noreply.github.com>
This commit is contained in:
VMSolidus
2024-06-23 01:00:32 -04:00
committed by GitHub
parent 287f33cc3e
commit 40d411bbbc
34 changed files with 167 additions and 22 deletions

View File

@@ -1,4 +1,5 @@
using System.Numerics;
using Content.Client.Gameplay;
using Content.Client.Items;
using Content.Client.Weapons.Ranged.Components;
using Content.Shared.Camera;
@@ -12,6 +13,7 @@ using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.Player;
using Robust.Client.State;
using Robust.Shared.Animations;
using Robust.Shared.Input;
using Robust.Shared.Map;
@@ -27,6 +29,7 @@ public sealed partial class GunSystem : SharedGunSystem
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IStateManager _state = default!;
[Dependency] private readonly AnimationPlayerSystem _animPlayer = default!;
[Dependency] private readonly InputSystem _inputSystem = default!;
[Dependency] private readonly SharedCameraRecoilSystem _recoil = default!;
@@ -171,10 +174,15 @@ public sealed partial class GunSystem : SharedGunSystem
// Define target coordinates relative to gun entity, so that network latency on moving grids doesn't fuck up the target location.
var coordinates = EntityCoordinates.FromMap(entity, mousePos, TransformSystem, EntityManager);
NetEntity? target = null;
if (_state.CurrentState is GameplayStateBase screen)
target = GetNetEntity(screen.GetClickedEntity(mousePos));
Log.Debug($"Sending shoot request tick {Timing.CurTick} / {Timing.CurTime}");
EntityManager.RaisePredictiveEvent(new RequestShootEvent
{
Target = target,
Coordinates = GetNetCoordinates(coordinates),
Gun = GetNetEntity(gunUid),
});

View File

@@ -280,6 +280,13 @@ public sealed partial class GunSystem : SharedGunSystem
private void ShootOrThrow(EntityUid uid, Vector2 mapDirection, Vector2 gunVelocity, GunComponent gun, EntityUid gunUid, EntityUid? user)
{
if (gun.Target is { } target && !TerminatingOrDeleted(target))
{
var targeted = EnsureComp<TargetedProjectileComponent>(uid);
targeted.Target = target;
Dirty(uid, targeted);
}
// Do a throw
if (!HasComp<ProjectileComponent>(uid))
{

View File

@@ -0,0 +1,14 @@
using Robust.Shared.GameStates;
namespace Content.Shared.Damage.Components;
/// <summary>
/// Prevent the object from getting hit by projetiles unless you target the object.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
[Access(typeof(RequireProjectileTargetSystem))]
public sealed partial class RequireProjectileTargetComponent : Component
{
[DataField, AutoNetworkedField]
public bool Active = true;
}

View File

@@ -0,0 +1,51 @@
using Content.Shared.Projectiles;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Standing;
using Robust.Shared.Physics.Events;
namespace Content.Shared.Damage.Components;
public sealed class RequireProjectileTargetSystem : EntitySystem
{
public override void Initialize()
{
SubscribeLocalEvent<RequireProjectileTargetComponent, PreventCollideEvent>(PreventCollide);
SubscribeLocalEvent<RequireProjectileTargetComponent, StoodEvent>(StandingBulletHit);
SubscribeLocalEvent<RequireProjectileTargetComponent, DownedEvent>(LayingBulletPass);
}
private void PreventCollide(Entity<RequireProjectileTargetComponent> ent, ref PreventCollideEvent args)
{
if (args.Cancelled)
return;
if (!ent.Comp.Active)
return;
var other = args.OtherEntity;
if (HasComp<ProjectileComponent>(other) &&
CompOrNull<TargetedProjectileComponent>(other)?.Target != ent)
{
args.Cancelled = true;
}
}
private void SetActive(Entity<RequireProjectileTargetComponent> ent, bool value)
{
if (ent.Comp.Active == value)
return;
ent.Comp.Active = value;
Dirty(ent);
}
private void StandingBulletHit(Entity<RequireProjectileTargetComponent> ent, ref StoodEvent args)
{
SetActive(ent, false);
}
private void LayingBulletPass(Entity<RequireProjectileTargetComponent> ent, ref DownedEvent args)
{
SetActive(ent, true);
}
}

View File

@@ -10,12 +10,15 @@ using Content.Shared.Item;
using Content.Shared.Mobs.Components;
using Content.Shared.Movement.Events;
using Content.Shared.Pointing;
using Content.Shared.Projectiles;
using Content.Shared.Pulling.Events;
using Content.Shared.Speech;
using Content.Shared.Standing;
using Content.Shared.Strip.Components;
using Content.Shared.Throwing;
using Content.Shared.Weapons.Ranged.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Events;
namespace Content.Shared.Mobs.Systems;

View File

@@ -140,6 +140,12 @@ public sealed partial class GunComponent : Component
[ViewVariables]
public EntityCoordinates? ShootCoordinates = null;
/// <summary>
/// Who the gun is being requested to shoot at directly.
/// </summary>
[ViewVariables]
public EntityUid? Target = null;
/// <summary>
/// The base value for how many shots to fire per burst.
/// </summary>

View File

@@ -0,0 +1,12 @@
using Content.Shared.Weapons.Ranged.Systems;
using Robust.Shared.GameStates;
namespace Content.Shared.Weapons.Ranged.Components;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
[Access(typeof(SharedGunSystem))]
public sealed partial class TargetedProjectileComponent : Component
{
[DataField, AutoNetworkedField]
public EntityUid Target;
}

View File

@@ -11,4 +11,5 @@ public sealed class RequestShootEvent : EntityEventArgs
{
public NetEntity Gun;
public NetCoordinates Coordinates;
public NetEntity? Target;
}

View File

@@ -139,6 +139,7 @@ public abstract partial class SharedGunSystem : EntitySystem
gun.ShootCoordinates = GetCoordinates(msg.Coordinates);
Log.Debug($"Set shoot coordinates to {gun.ShootCoordinates}");
gun.Target = GetEntity(msg.Target);
AttemptShoot(user.Value, ent, gun);
}
@@ -200,6 +201,7 @@ public abstract partial class SharedGunSystem : EntitySystem
Log.Debug($"Stopped shooting {ToPrettyString(uid)}");
gun.ShotCounter = 0;
gun.ShootCoordinates = null;
gun.Target = null;
Dirty(uid, gun);
}

View File

@@ -1,4 +1,4 @@
# The progenitor. This should only container the most basic components possible.
# The progenitor. This should only container the most basic components possible.
# Only put things on here if every mob *must* have it. This includes ghosts.
- type: entity
save: false
@@ -43,6 +43,8 @@
- type: MovementSpeedModifier
- type: Polymorphable
- type: StatusIcon
- type: RequireProjectileTarget
active: False
# Used for mobs that have health and can take damage.
- type: entity

View File

@@ -1,4 +1,4 @@
- type: entity
- type: entity
abstract: true
parent: BaseItem
id: BaseHandheldInstrument
@@ -71,6 +71,7 @@
- BulletImpassable
- type: StaticPrice
price: 300
- type: RequireProjectileTarget
- type: entity
parent: BasePlaceableInstrument

View File

@@ -1,7 +1,7 @@
- type: entity
abstract: true
id: ReagentDispenserBase
parent: ConstructibleMachine
parent: SmallConstructibleMachine
placement:
mode: SnapgridCenter
components:

View File

@@ -60,3 +60,4 @@
ents: []
- type: LightningTarget
priority: 1
- type: RequireProjectileTarget

View File

@@ -1,6 +1,6 @@
- type: entity
id: BaseTabletopChemicalMachine
parent: [ BaseMachinePowered, ConstructibleMachine ]
parent: [ BaseMachinePowered, SmallConstructibleMachine ]
abstract: true
components:
- type: Transform

View File

@@ -1,6 +1,6 @@
- type: entity
id: DiseaseDiagnoser
parent: [ BaseMachinePowered, ConstructibleMachine ]
parent: [ BaseMachinePowered, SmallConstructibleMachine ]
name: Disease Diagnoser Delta Extreme
description: A machine that analyzes disease samples.
placement:
@@ -43,5 +43,3 @@
contentMargin: 12.0, 0.0, 12.0, 0.0
# This is a narrow piece of paper
maxWritableArea: 128.0, 0.0

View File

@@ -24,3 +24,4 @@
containers:
machine_board: !type:Container
machine_parts: !type:Container
- type: RequireProjectileTarget

View File

@@ -1,6 +1,6 @@
- type: entity
id: MachineArtifactAnalyzer
parent: [ BaseMachinePowered, ConstructibleMachine ]
parent: [ BaseMachinePowered, SmallConstructibleMachine ]
name: artifact analyzer
description: A platform capable of performing analysis on various types of artifacts.
components:
@@ -35,6 +35,7 @@
- Impassable
- MidImpassable
- LowImpassable
- BulletImpassable
hard: False
- type: Transform
anchored: true

View File

@@ -70,3 +70,10 @@
- machine_board
- type: LightningTarget
priority: 1
- type: entity
abstract: true
parent: ConstructibleMachine
id: SmallConstructibleMachine
components:
- type: RequireProjectileTarget

View File

@@ -65,6 +65,7 @@
deviceNetId: Wireless
receiveFrequencyId: Fax
transmitFrequencyId: Fax
- type: RequireProjectileTarget
# Special
- type: entity

View File

@@ -518,6 +518,7 @@
- Sheet
- RawMaterial
- Ingot
- type: RequireProjectileTarget
- type: entity
id: ExosuitFabricator

View File

@@ -1,6 +1,6 @@
- type: entity
- type: entity
id: KitchenMicrowave
parent: [ BaseMachinePowered, ConstructibleMachine ]
parent: [ BaseMachinePowered, SmallConstructibleMachine ]
name: microwave
description: It's magic.
components:

View File

@@ -1,6 +1,6 @@
- type: entity
id: KitchenReagentGrinder
parent: [ BaseMachinePowered, ConstructibleMachine ]
parent: [ BaseMachinePowered, SmallConstructibleMachine ]
name: reagent grinder
description: From BlenderTech. Will It Blend? Let's find out!
suffix: grinder/juicer

View File

@@ -1,6 +1,6 @@
- type: entity
abstract: true
parent: [ BaseStructureDynamic, ConstructibleMachine ]
parent: [ BaseStructureDynamic, SmallConstructibleMachine ]
id: SurveillanceWirelessCameraBase
name: wireless camera
description: A camera. It's watching you. Kinda.
@@ -23,6 +23,8 @@
density: 80
mask:
- MachineMask
layer:
- BulletImpassable
- type: SurveillanceCameraMicrophone
blacklist:
components:

View File

@@ -1,6 +1,6 @@
- type: entity
id: PortableScrubber
parent: [BaseMachinePowered, ConstructibleMachine]
parent: [BaseMachinePowered, SmallConstructibleMachine]
name: portable scrubber
description: It scrubs, portably!
components:
@@ -120,7 +120,7 @@
layer:
- MachineLayer
- type: ApcPowerReceiver
powerDisabled: true #starts off
powerDisabled: true #starts off
- type: Sprite
sprite: Structures/Piping/Atmospherics/Portable/portable_sheater.rsi
noRot: true
@@ -195,4 +195,4 @@
suffix: Anchored, Enabled
components:
- type: ApcPowerReceiver
powerDisabled: false
powerDisabled: false

View File

@@ -390,7 +390,7 @@
board: HellfireHeaterMachineCircuitBoard
- type: entity
parent: [ BaseMachinePowered, ConstructibleMachine ]
parent: [ BaseMachinePowered, SmallConstructibleMachine ]
id: BaseGasCondenser
name: condenser
description: Condenses gases into liquids. Now we just need some plumbing.

View File

@@ -91,6 +91,7 @@
- key: enum.DisposalUnitUiKey.Key
type: DisposalUnitBoundUserInterface
- type: RatKingRummageable
- type: RequireProjectileTarget
- type: entity
id: MailingUnit

View File

@@ -1,7 +1,7 @@
- type: entity
id: Emitter
name: emitter
parent: ConstructibleMachine
parent: SmallConstructibleMachine
description: A heavy duty industrial laser. Shoots non-stop when turned on.
placement:
mode: SnapgridCenter

View File

@@ -1,4 +1,4 @@
#
#
# You can use this Desmos sheet to calculate fuel burn rate values:
# https://www.desmos.com/calculator/qcektq5dqs
#
@@ -6,7 +6,7 @@
- type: entity
abstract: true
id: PortableGeneratorBase
parent: [ BaseMachine, ConstructibleMachine ]
parent: [ BaseMachine, SmallConstructibleMachine]
components:
# Basic properties
- type: Transform

View File

@@ -49,6 +49,7 @@
onBump: false
requirePower: true
highVoltageNode: output
- type: RequireProjectileTarget
- type: entity
id: SolarPanel
@@ -157,6 +158,7 @@
graph: SolarPanel
node: solarassembly
defaultTarget: solarpanel
- type: RequireProjectileTarget
- type: entity
id: SolarTracker
@@ -201,3 +203,4 @@
- type: Construction
graph: SolarPanel
node: solartracker
- type: RequireProjectileTarget

View File

@@ -58,12 +58,15 @@
density: 500
mask:
- TabletopMachineMask
layer:
- BulletImpassable
- type: PowerChargerVisuals
- type: ContainerContainer
containers:
charger_slot: !type:ContainerSlot
machine_board: !type:Container
machine_parts: !type:Container
- type: RequireProjectileTarget
- type: entity
parent: BaseItemRecharger

View File

@@ -74,6 +74,7 @@
node: crategenericsteel
containers:
- entity_storage
- type: RequireProjectileTarget
- type: entity
parent: CrateGeneric

View File

@@ -156,6 +156,7 @@
node: chestDrawer
- type: StaticPrice
price: 15
- type: RequireProjectileTarget
- type: entity
abstract: true

View File

@@ -69,7 +69,7 @@
acts: [ "Destruction" ]
- type: Climbable
delay: 2.5
- type: RequireProjectileTarget
#High
- type: entity
@@ -93,8 +93,10 @@
mask:
- FullTileMask
layer:
- Opaque
- MidImpassable
- LowImpassable
- BulletImpassable
- type: Construction
graph: FenceWood
node: straight
@@ -120,8 +122,10 @@
mask:
- FullTileMask
layer:
- Opaque
- MidImpassable
- LowImpassable
- BulletImpassable
- type: Construction
graph: FenceWood
node: end
@@ -156,8 +160,10 @@
mask:
- TableMask
layer:
- Opaque
- MidImpassable
- LowImpassable
- BulletImpassable
- type: Construction
graph: FenceWood
node: corner
@@ -192,8 +198,10 @@
mask:
- TableMask
layer:
- Opaque
- MidImpassable
- LowImpassable
- BulletImpassable
- type: Construction
graph: FenceWood
node: tjunction
@@ -218,8 +226,10 @@
mask:
- FullTileMask
layer:
- Opaque
- MidImpassable
- LowImpassable
- BulletImpassable
- type: InteractionOutline
- type: Door
openSpriteState: door_opened
@@ -268,6 +278,7 @@
layer:
- MidImpassable
- LowImpassable
- BulletImpassable
- type: Construction
graph: FenceWood
node: straight_small
@@ -295,6 +306,7 @@
layer:
- MidImpassable
- LowImpassable
- BulletImpassable
- type: Construction
graph: FenceWood
node: end_small
@@ -331,6 +343,7 @@
layer:
- MidImpassable
- LowImpassable
- BulletImpassable
- type: Construction
graph: FenceWood
node: corner_small
@@ -367,6 +380,7 @@
layer:
- MidImpassable
- LowImpassable
- BulletImpassable
- type: Construction
graph: FenceWood
node: tjunction_small
@@ -393,6 +407,7 @@
layer:
- MidImpassable
- LowImpassable
- BulletImpassable
- type: InteractionOutline
- type: Door
openSpriteState: door_opened_small
@@ -415,4 +430,4 @@
path: /Audio/Effects/door_close.ogg
- type: Construction
graph: FenceWood
node: gate_small
node: gate_small

View File

@@ -1,6 +1,6 @@
- type: entity
name: hydroponics tray
parent: [ hydroponicsSoil, ConstructibleMachine]
parent: [ hydroponicsSoil, SmallConstructibleMachine]
id: hydroponicsTray
description: An interstellar-grade space farmplot allowing for rapid growth and selective breeding of crops. Just... keep in mind the space weeds.
components:
@@ -14,6 +14,8 @@
hard: true
mask:
- MachineMask
layer:
- BulletImpassable
- type: Anchorable
- type: Pullable
- type: Sprite