using System.Linq;
using Content.Shared.Contests;
using Content.Shared._Shitmed.Targeting;
using Content.Shared.Actions.Events;
using Content.Shared.Climbing.Components;
using Content.Shared.CombatMode;
using Content.Shared.Coordinates;
using Content.Shared.Damage;
using Content.Shared.Damage.Events;
using Content.Shared.Damage.Systems;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction;
using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Movement.Pulling.Systems;
using Content.Shared.Standing;
using Content.Shared.StatusEffect;
using Content.Shared.Stunnable;
using Content.Shared.Throwing;
using Content.Shared.Weapons.Melee;
using Content.Shared.Weapons.Melee.Events;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Events;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Shared._Goobstation.TableSlam;
///
/// This handles...
///
public sealed class TableSlamSystem : EntitySystem
{
[Dependency] private readonly PullingSystem _pullingSystem = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly StandingStateSystem _standing = default!;
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly StaminaSystem _staminaSystem = default!;
[Dependency] private readonly SharedStunSystem _stunSystem = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly ContestsSystem _contestsSystem = default!;
[Dependency] private readonly IRobustRandom _random = default!;
///
public override void Initialize()
{
SubscribeLocalEvent(OnMeleeHit);
SubscribeLocalEvent(OnStartCollide);
SubscribeLocalEvent(OnDisarmAttemptEvent);
}
private void OnDisarmAttemptEvent(Entity ent, ref DisarmAttemptEvent args)
{
if(!_random.Prob(ent.Comp.ParalyzeChance))
return;
_stunSystem.TryParalyze(ent, TimeSpan.FromSeconds(3), false);
RemComp(ent);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var tabledQuery = EntityQueryEnumerator();
while (tabledQuery.MoveNext(out var uid, out var comp))
{
if (_gameTiming.CurTime >= comp.PostTabledShovableTime)
RemComp(uid);
}
}
private void OnMeleeHit(Entity ent, ref MeleeHitEvent args)
{
if (ent.Comp.GrabStage < GrabStage.Suffocate
|| ent.Comp.Pulling == null)
return;
if(!TryComp(ent.Comp.Pulling, out var pullableComponent))
return;
if (args.Direction != null)
return;
if (args.HitEntities.Count is > 1 or 0)
return;
var target = args.HitEntities.ElementAt(0);
if (!HasComp(target)) // checks if its a table.
return;
var massContest = _contestsSystem.MassContest(ent, ent.Comp.Pulling.Value);
var attemptChance = Math.Clamp(1 * massContest, 0, 1);
var attemptRoundedToNearestQuarter = Math.Round(attemptChance * 4, MidpointRounding.ToEven) / 4;
if(_random.Prob((float) attemptRoundedToNearestQuarter)) // base chance to table slam someone is 1 if your mass ratio is less than 1 then your going to have a harder time slamming somebody.
TryTableSlam((ent.Comp.Pulling.Value, pullableComponent), ent, target);
}
public void TryTableSlam(Entity ent, Entity pullerEnt, EntityUid tableUid)
{
if(!_transformSystem.InRange(ent.Owner.ToCoordinates(), tableUid.ToCoordinates(), 2f ))
return;
_standing.Down(ent);
_pullingSystem.TryStopPull(ent, ent.Comp, pullerEnt, ignoreGrab: true);
_throwingSystem.TryThrow(ent, tableUid.ToCoordinates() , ent.Comp.BasedTabledForceSpeed, animated: false, doSpin: false);
pullerEnt.Comp.NextStageChange = _gameTiming.CurTime.Add(TimeSpan.FromSeconds(3)); // prevent table slamming spam
if (TryComp(ent, out var tableableComp)) // Checks that the entity being tabled has the TableableComponent
{
tableableComp.BeingTabled = true;
}
else
{
tableableComp = EnsureComp(ent); // Adds the Tableable Component if it doesn't exist
tableableComp.BeingTabled = true; // This shit is so code :skull:
}
}
private void OnStartCollide(Entity ent, ref StartCollideEvent args)
{
if(!ent.Comp.BeingTabled)
return;
if (!HasComp(args.OtherEntity))
return;
var modifierOnGlassBreak = 1;
if (TryComp(args.OtherEntity, out var glassTableComponent))
{
_damageableSystem.TryChangeDamage(args.OtherEntity, glassTableComponent.TableDamage, origin: ent, targetPart: TargetBodyPart.Torso);
_damageableSystem.TryChangeDamage(args.OtherEntity, glassTableComponent.ClimberDamage, origin: ent);
modifierOnGlassBreak = 2;
}
else
{
_damageableSystem.TryChangeDamage(ent,
new DamageSpecifier()
{
DamageDict = new Dictionary { { "Blunt", ent.Comp.TabledDamage } },
},
targetPart: TargetBodyPart.Torso);
_damageableSystem.TryChangeDamage(ent,
new DamageSpecifier()
{
DamageDict = new Dictionary { { "Blunt", ent.Comp.TabledDamage } },
});
}
_staminaSystem.TakeStaminaDamage(ent, ent.Comp.TabledStaminaDamage);
_stunSystem.TryKnockdown(ent, TimeSpan.FromSeconds(3 * modifierOnGlassBreak), false);
var postTabledComponent = EnsureComp(ent);
postTabledComponent.PostTabledShovableTime = _gameTiming.CurTime.Add(TimeSpan.FromSeconds(3));
ent.Comp.BeingTabled = false;
//_audioSystem.PlayPvs("/Audio/Effects/thudswoosh.ogg", uid);
}
}