Предательский нож (#112)

* - add: Add betrayal knife.

* - tweak: Small size.
This commit is contained in:
Aviu00
2024-02-24 07:59:03 +09:00
committed by GitHub
parent 9d31a42880
commit 382188d2d2
13 changed files with 264 additions and 2 deletions

View File

@@ -1,5 +1,6 @@
using System.Linq;
using Content.Client.Gameplay;
using Content.Shared._White.BetrayalDagger;
using Content.Shared.CombatMode;
using Content.Shared.Effects;
using Content.Shared.Hands.Components;
@@ -129,6 +130,28 @@ public sealed partial class MeleeWeaponSystem : SharedMeleeWeaponSystem
return;
}
// WD START
if (HasComp<BlinkComponent>(weaponUid))
{
if (!_xformQuery.TryGetComponent(entity, out var userXform) ||
!Timing.IsFirstTimePredicted)
{
return;
}
var targetMap = coordinates.ToMap(EntityManager, TransformSystem);
if (targetMap.MapId != userXform.MapID)
return;
var userPos = TransformSystem.GetWorldPosition(userXform);
var direction = targetMap.Position - userPos;
RaiseNetworkEvent(new BlinkEvent(GetNetEntity(weaponUid), direction));
return;
}
// WD END
ClientHeavyAttack(entity, coordinates, weaponUid, weapon);
return;
}

View File

@@ -66,6 +66,8 @@ public sealed class MeleeHitEvent : HandledEntityEventArgs
/// </remarks>
public bool IsHit = true;
public bool PenetrateArmor = false;
public MeleeHitEvent(List<EntityUid> hitEntities, EntityUid user, EntityUid weapon, DamageSpecifier baseDamage, Vector2? direction)
{
HitEntities = hitEntities;

View File

@@ -530,7 +530,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
RaiseLocalEvent(target.Value, attackedEvent);
var modifiedDamage = DamageSpecifier.ApplyModifierSets(damage + hitEvent.BonusDamage + attackedEvent.BonusDamage, hitEvent.ModifiersList);
var damageResult = Damageable.TryChangeDamage(target, modifiedDamage, component.IgnoreResistances, origin:user); // WD EDIT
var damageResult = Damageable.TryChangeDamage(target, modifiedDamage, component.IgnoreResistances || hitEvent.PenetrateArmor, origin:user); // WD EDIT
if (damageResult != null && damageResult.Any())
{
@@ -687,7 +687,7 @@ public abstract class SharedMeleeWeaponSystem : EntitySystem
RaiseLocalEvent(entity, attackedEvent);
var modifiedDamage = DamageSpecifier.ApplyModifierSets(damage + hitEvent.BonusDamage + attackedEvent.BonusDamage, hitEvent.ModifiersList);
var damageResult = Damageable.TryChangeDamage(entity, modifiedDamage, component.IgnoreResistances, origin:user); // WD EDIT
var damageResult = Damageable.TryChangeDamage(entity, modifiedDamage, component.IgnoreResistances || hitEvent.PenetrateArmor, origin:user); // WD EDIT
if (damageResult != null && damageResult.GetTotal() > FixedPoint2.Zero)
{

View File

@@ -0,0 +1,14 @@
namespace Content.Shared._White.BetrayalDagger;
[RegisterComponent]
public sealed partial class BackstabComponent : Component
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float DamageMultiplier = 2f;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public bool PenetrateArmor = true;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public Angle Tolerance = Angle.FromDegrees(45d);
}

View File

@@ -0,0 +1,56 @@
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Examine;
using Content.Shared.Mobs.Components;
using Content.Shared.Popups;
using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
namespace Content.Shared._White.BetrayalDagger;
public sealed class BackstabSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BackstabComponent, MeleeHitEvent>(HandleHit);
}
private void HandleHit(Entity<BackstabComponent> ent, ref MeleeHitEvent args)
{
if (args.HitEntities.Count != 1)
return;
var target = args.HitEntities[0];
if (target == args.User || !HasComp<MobStateComponent>(target) ||
!TryComp(target, out TransformComponent? xform))
return;
var rot1 = _transform.GetWorldRotation(args.User).FlipPositive();
var rot2 = _transform.GetWorldRotation(xform).FlipPositive();
var tol = ent.Comp.Tolerance;
if (!MathHelper.CloseTo(rot1, rot2, tol) &&
!MathHelper.CloseTo(rot1, rot2 + MathHelper.TwoPi, tol) &&
!MathHelper.CloseTo(rot1 + MathHelper.TwoPi, rot2, tol))
return;
var damage = args.BaseDamage.GetTotal() * ent.Comp.DamageMultiplier;
args.BonusDamage = new DamageSpecifier(_prototypeManager.Index<DamageTypePrototype>("Slash"),
damage - args.BaseDamage.GetTotal());
args.PenetrateArmor = ent.Comp.PenetrateArmor;
if (_net.IsServer)
_popup.PopupEntity($@"Backstab! {damage}", args.User, PopupType.MediumCaution);
}
}

View File

@@ -0,0 +1,21 @@
using Robust.Shared.Audio;
namespace Content.Shared._White.BetrayalDagger;
[RegisterComponent]
public sealed partial class BlinkComponent : Component
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float Distance = 5f;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float BlinkRate = 1f;
public TimeSpan NextBlink;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public SoundSpecifier BlinkSound = new SoundPathSpecifier("/Audio/Magic/blink.ogg")
{
Params = AudioParams.Default.WithVolume(5f)
};
}

View File

@@ -0,0 +1,81 @@
using System.Numerics;
using Content.Shared.Mobs.Components;
using Content.Shared.Physics;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Serialization;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Shared._White.BetrayalDagger;
public sealed class BlinkSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
public override void Initialize()
{
base.Initialize();
SubscribeAllEvent<BlinkEvent>(OnBlink);
}
private void OnBlink(BlinkEvent msg, EntitySessionEventArgs args)
{
if (args.SenderSession.AttachedEntity == null)
return;
var user = args.SenderSession.AttachedEntity.Value;
if (!TryComp(user, out TransformComponent? xform))
return;
if (!TryComp(GetEntity(msg.Weapon), out BlinkComponent? blink))
return;
if (blink.NextBlink > _timing.CurTime)
return;
var blinkRate = TimeSpan.FromSeconds(1f / blink.BlinkRate);
blink.NextBlink = _timing.CurTime + blinkRate;
var coords = _transform.GetWorldPosition(xform);
var dir = msg.Direction.Normalized();
var range = blink.Distance;
var ray = new CollisionRay(coords, dir, (int) CollisionGroup.Opaque);
var rayResults = _physics.IntersectRayWithPredicate(xform.MapID, ray, range,
x => x == user || !HasComp<OccluderComponent>(x)).FirstOrNull();
Vector2 targetPos;
if (rayResults != null)
{
targetPos = rayResults.Value.HitPos - dir;
}
else
{
targetPos = coords + (msg.Direction.Length() > range ? dir * range : msg.Direction);
}
_transform.SetWorldPosition(user, targetPos);
_audio.PlayPvs(blink.BlinkSound, user);
}
}
[Serializable, NetSerializable]
public sealed class BlinkEvent : EntityEventArgs
{
public readonly NetEntity Weapon;
public readonly Vector2 Direction;
public BlinkEvent(NetEntity weapon, Vector2 direction)
{
Weapon = weapon;
Direction = direction;
}
}

View File

@@ -8,6 +8,8 @@
sprite: Objects/Weapons/Melee/blood_dagger.rsi
state: icon
- type: MeleeWeapon
wideAnimationRotation: 135
swingLeft: true
attackRate: 1.3
damage:
types:
@@ -25,3 +27,27 @@
critChance: 40
critMultiplier: 2
isBloodDagger: true
- type: entity
name: предательский нож
description: Берегите спину.
parent: BaseItem
id: BetrayalKnife
components:
- type: Sharp
- type: Sprite
sprite: White/Objects/Weapons/betrayal_knife.rsi
state: icon
- type: MeleeWeapon
wideAnimationRotation: 180
attackRate: 1
damage:
types:
Slash: 30
soundHit:
path: /Audio/Weapons/bladeslice.ogg
- type: Item
size: Small
- type: DisarmMalus
- type: Backstab
- type: Blink

View File

@@ -112,6 +112,23 @@
# - UplinkWeapons
# saleLimit: 1
- type: listing
id: UplinkBetrayalKnife
name: Предательский нож
description: Предательский нож позволяет пользователю телепортироваться на короткое расстояние, а также наносит значительные повреждения, пробивая броню противника, при ударе в спину.
icon: { sprite: /Textures/White/Objects/Weapons/betrayal_knife.rsi, state: icon }
productEntity: BetrayalKnife
cost:
Telecrystal: 10
categories:
- UplinkWeapons
conditions:
- !type:StoreWhitelistCondition
blacklist:
tags:
- NukeOpsUplink
saleLimit: 1
- type: listing
id: UplinkMagazineShotgun
name: uplink-magazine-bulldog-name

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

View File

@@ -0,0 +1,22 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/pull/49264/commits/d0dffe7ca643db2624424fdcebf45863f85c0448",
"size": {
"x": 32,
"y": 32
},
"states": [
{
"name": "icon"
},
{
"name": "inhand-left",
"directions": 4
},
{
"name": "inhand-right",
"directions": 4
}
]
}