Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Weapon Reflection Movement Mechanic #27219

Merged
merged 8 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Content.Shared/Weapons/Reflect/ReflectComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,25 @@ public sealed partial class ReflectComponent : Component

[DataField("soundOnReflect")]
public SoundSpecifier? SoundOnReflect = new SoundPathSpecifier("/Audio/Weapons/Guns/Hits/laser_sear_wall.ogg");

/// <summary>
/// Is the deflection an innate power or something actively maintained? If true, this component grants a flat
/// deflection chance rather than a chance that degrades when moving/weightless/stunned/etc.
/// </summary>
[DataField]
public bool Innate = false;

/// <summary>
/// The multiplier used when moving.
/// </summary>
[DataField]
public float MovingProbMultiplier = 0.66f;

/// <summary>
/// The multiplier used when sprinting or when otherwise compromised (e.g. weightless)
/// </summary>
[DataField]
public float SprintingProbMultiplier = 0.33f;
}

[Flags]
Expand Down
41 changes: 39 additions & 2 deletions Content.Shared/Weapons/Reflect/ReflectSystem.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using Content.Shared.ActionBlocker;
using Content.Shared.Administration.Logs;
using Content.Shared.Audio;
using Content.Shared.Damage.Components;
using Content.Shared.Damage.Systems;
using Content.Shared.Database;
using Content.Shared.Gravity;
using Content.Shared.Hands;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
using Content.Shared.Item.ItemToggle.Components;
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Systems;
using Content.Shared.Popups;
using Content.Shared.Projectiles;
using Content.Shared.Standing;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Events;
using Robust.Shared.Audio;
Expand All @@ -35,6 +42,9 @@ public sealed class ReflectSystem : EntitySystem
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly SharedGravitySystem _gravity = default!;
[Dependency] private readonly StandingStateSystem _standing = default!;
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;

public override void Initialize()
{
Expand Down Expand Up @@ -91,16 +101,43 @@ private void OnReflectCollide(EntityUid uid, ReflectComponent component, ref Pro

private bool TryReflectProjectile(EntityUid user, EntityUid reflector, EntityUid projectile, ProjectileComponent? projectileComp = null, ReflectComponent? reflect = null)
{
// Do we have the components needed to try a reflect at all?
if (!Resolve(reflector, ref reflect, false) ||
!reflect.Enabled ||
!TryComp<ReflectiveComponent>(projectile, out var reflective) ||
(reflect.Reflects & reflective.Reflective) == 0x0 ||
!_random.Prob(reflect.ReflectProb) ||
!TryComp<PhysicsComponent>(projectile, out var physics))
{
return false;

var reflectChance = reflect.ReflectProb;

/*
* The rules of deflection are as follows:
* If you innately reflect things via magic, biology etc, you always have a full chance.
* If you are standing up and standing still, you're prepared to deflect and have full chance.
* If you are moving at all, your chance is multiplied by the movingProbMultiplier.
* If you are recklessly sprinting, your chance is instead multiplied by the sprintingProbMultiplier.
* If you floating, your chance is instead multiplied by the sprintingProbMultiplier.
* You cannot deflect if you are knocked down or stunned.
*/

if (!reflect.Innate)
{
if (TryComp<StaminaComponent>(reflector, out var staminaComponent) && staminaComponent.Critical)
return false;

if (_standing.IsDown(reflector))
return false;

if (_gravity.IsWeightless(reflector))
reflectChance *= reflect.SprintingProbMultiplier;
else if (TryComp<InputMoverComponent>(reflector, out var mover) && (mover.HeldMoveButtons & MoveButtons.AnyDirection) == MoveButtons.AnyDirection)
FairlySadPanda marked this conversation as resolved.
Show resolved Hide resolved
reflectChance *= mover.Sprinting ? reflect.SprintingProbMultiplier : reflect.MovingProbMultiplier;
}

if (!_random.Prob(reflectChance))
return false;

var rotation = _random.NextAngle(-reflect.Spread / 2, reflect.Spread / 2).Opposite();
var existingVelocity = _physics.GetMapLinearVelocity(projectile, component: physics);
var relativeVelocity = existingVelocity - _physics.GetMapLinearVelocity(user);
Expand Down
1 change: 1 addition & 0 deletions Resources/Prototypes/Anomaly/behaviours.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
description: anomaly-behavior-reflect
components:
- type: Reflect
innate: true
reflectProb: 0.5
reflects:
- Energy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
Heat: 0.4 # this technically means it protects against fires pretty well? -heat is just for lasers and stuff, not atmos temperature
- type: Reflect
reflectProb: 1
innate: true # armor grants a passive shield that does not require concentration to maintain
reflects:
- Energy

Expand Down
1 change: 1 addition & 0 deletions Resources/Prototypes/Entities/Mobs/NPCs/hellspawn.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
- type: Perishable
- type: Reflect
reflectProb: 0.7
innate: true
reflects:
- Energy
- type: Fixtures
Expand Down
6 changes: 3 additions & 3 deletions Resources/Prototypes/Entities/Objects/Shields/shields.yml
Original file line number Diff line number Diff line change
Expand Up @@ -313,14 +313,14 @@
name: mirror shield
parent: BaseShield
id: MirrorShield
description: Eerily glows red... you hear the geometer whispering
description: Eerily glows red. You hear the geometer whispering...
components:
- type: Sprite
state: mirror-icon
- type: Item
heldPrefix: mirror
- type: Reflect
reflectProb: 0.95
reflectProb: 0.95 # 0.63 when moving, 0.31 when sprinting
reflects:
- Energy
- type: Blocking #Mirror shield reflects heat/laser, but is relatively weak to everything else.
Expand Down Expand Up @@ -407,7 +407,7 @@
color: blue
- type: Reflect
enabled: false
reflectProb: 0.95
reflectProb: 0.95 # 0.63 when moving, 0.31 when sprinting
reflects:
- Energy
- type: Blocking
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
malus: 0
- type: Reflect
enabled: false
reflectProb: 0.3 # 0.2 when moving, 0.1 when sprinting
- type: IgnitionSource
temperature: 700

Expand Down Expand Up @@ -218,7 +219,7 @@
name: double-bladed energy sword
parent: EnergySword
id: EnergySwordDouble
description: Syndicate Command Interns thought that having one blade on the energy sword was not enough. This can be stored in pockets.
description: Syndicate Command's intern thought that having only one blade on energy swords was not cool enough. This can be stored in pockets.
components:
- type: EnergySword
- type: ItemToggle
Expand Down Expand Up @@ -269,7 +270,7 @@
size: Small
sprite: Objects/Weapons/Melee/e_sword_double-inhands.rsi
- type: Reflect
reflectProb: .75
reflectProb: .75 # 0.5 when moving, 0.25 when sprinting.
spread: 75
- type: UseDelay
delay: 1
Expand Down
13 changes: 8 additions & 5 deletions Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
attackRate: 1.5
damage:
types:
Slash: 17 #cmon, it has to be at least BETTER than the rest.
Slash: 15
soundHit:
path: /Audio/Weapons/bladeslice.ogg
- type: Reflect
enabled: true
reflectProb: .1
reflectProb: .3 # 0.2 when moving, 0.1 when sprinting.
spread: 90
- type: Item
size: Normal
Expand Down Expand Up @@ -83,6 +83,9 @@
- Back
- Belt
- type: Reflect
reflectProb: 0.3
movingProbMultiplier: 1.0 # don't punish ninjas for being ninjas
sprintingProbMultiplier: 1.0 # it's a ninja weapon. you run around and slice bullets in half

- type: entity
name: machete
Expand Down Expand Up @@ -152,7 +155,7 @@
wideAnimationRotation: -135
damage:
types:
Slash: 16
Slash: 15
soundHit:
path: /Audio/Weapons/bladeslice.ogg
- type: Item
Expand All @@ -164,7 +167,7 @@
name: The Throngler
parent: BaseItem
id: Throngler
description: Why would you make this?
description: Why would someone make this?
components:
- type: Sharp
- type: Sprite
Expand All @@ -185,7 +188,7 @@
path: /Audio/Effects/explosion_small1.ogg
- type: Reflect
enabled: true
reflectProb: .25
reflectProb: .3 # 0.2 when moving, 0.1 when sprinting
spread: 90
- type: Item
size: Ginormous
Expand Down
Loading