Доработка прыжков и сальто

This commit is contained in:
Vigers Ray 2024-12-26 05:42:35 +03:00
parent f21a912ba9
commit eab23ce60f
34 changed files with 649 additions and 162 deletions

View file

@ -26,6 +26,7 @@
<ui:OptionSlider Name="SliderTtsRadio" Title="{Loc 'ui-options-tts-radio-volume'}" />
<ui:OptionSlider Name="SliderTtsAnnounce" Title="{Loc 'ui-options-tts-announce-volume'}" />
<CheckBox Name="TapePlayerClientCheckBox" Text="{Loc 'ui-options-tape-player-enabled'}" />
<CheckBox Name="JumpEnabledSoundCheckBox" Text="{Loc 'ui-options-jump-sound-enabled'}" />
<!-- Graphics -->
<Label Text="{Loc 'ui-options-sunrise-general-graphics'}" StyleClasses="LabelKeyText"/>

View file

@ -39,6 +39,7 @@ public sealed partial class SunriseTab : Control
Control.AddOptionCheckBox(SunriseCCVars.TTSClientEnabled, TtsClientCheckBox);
Control.AddOptionCheckBox(SunriseCCVars.TapePlayerClientEnabled, TapePlayerClientCheckBox);
Control.AddOptionCheckBox(SunriseCCVars.JumpSoundEnabled, JumpEnabledSoundCheckBox);
_cfg.OnValueChanged(SunriseCCVars.LobbyBackgroundType, OnLobbyBackgroundTypeChanged, true);

View file

@ -1,17 +1,9 @@
using System.Numerics;
using Content.Shared._Sunrise.Animations;
using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Input;
using Content.Shared.Standing;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
using Robust.Shared.Animations;
using Robust.Shared.GameStates;
using Robust.Shared.Input.Binding;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Client._Sunrise.Animations;
@ -28,7 +20,7 @@ public sealed class EmoteAnimationSystem : EntitySystem
{
SubscribeLocalEvent<EmoteAnimationComponent, ComponentHandleState>(OnHandleState);
_emoteList.Add("EmoteFlip", uid =>
_emoteList.Add("Flip", uid =>
{
if (_animationSystem.HasRunningAnimation(uid, AnimationKey))
return;
@ -63,7 +55,7 @@ public sealed class EmoteAnimationSystem : EntitySystem
_animationSystem.Play(uid, animation, AnimationKey);
});
_emoteList.Add("EmoteJump", uid =>
_emoteList.Add("Jump", uid =>
{
if (_animationSystem.HasRunningAnimation(uid, AnimationKey))
return;
@ -93,7 +85,7 @@ public sealed class EmoteAnimationSystem : EntitySystem
_animationSystem.Play(uid, animation, AnimationKey);
});
_emoteList.Add("EmoteTurn", uid =>
_emoteList.Add("Dance", uid =>
{
if (_animationSystem.HasRunningAnimation(uid, AnimationKeyTurn))
return;

View file

@ -1,28 +1,46 @@
using Content.Shared._Sunrise.Jump;
using Content.Shared._Sunrise.SunriseCCVars;
using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Input;
using Robust.Shared.Configuration;
using Robust.Shared.Input.Binding;
using Robust.Shared.Player;
using Robust.Shared.Timing;
namespace Content.Client._Sunrise.Jump;
public sealed class JumpSystem : SharedJumpSystem
public sealed partial class JumpSystem : SharedJumpSystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
private TimeSpan _lastJumpTime;
private static readonly TimeSpan JumpCooldown = TimeSpan.FromSeconds(1);
private static readonly TimeSpan JumpCooldown = TimeSpan.FromSeconds(0.600);
[ValidatePrototypeId<EmotePrototype>]
private const string EmoteJumpProto = "EmoteJump";
private const string EmoteJumpProto = "Jump";
public override void Initialize()
{
base.Initialize();
CommandBinds.Builder
.Bind(ContentKeyFunctions.Jump, InputCmdHandler.FromDelegate(Jump, handle: false, outsidePrediction: false))
.Register<JumpSystem>();
_cfg.OnValueChanged(SunriseCCVars.JumpSoundEnabled, OnJumpSoundEnabledOptionChanged, true);
}
public override void Shutdown()
{
base.Shutdown();
_cfg.UnsubValueChanged(SunriseCCVars.JumpSoundEnabled, OnJumpSoundEnabledOptionChanged);
}
private void OnJumpSoundEnabledOptionChanged(bool option)
{
RaiseNetworkEvent(new ClientOptionJumpSoundEvent(option));
}
private void Jump(ICommonSession? session)

View file

@ -22,7 +22,7 @@ public sealed partial class EmotesTabControl : BaseTabControl
[Dependency] private readonly IGameTiming _gameTiming = default!;
private TimeSpan _lastEmoteTime;
private static readonly TimeSpan EmoteCooldown = TimeSpan.FromSeconds(3);
private static readonly TimeSpan EmoteCooldown = TimeSpan.FromSeconds(2f);
public EmotesTabControl()
{

View file

@ -22,7 +22,7 @@ public sealed partial class VerbsTabControl : BaseTabControl
[Dependency] private readonly IGameTiming _gameTiming = default!;
private TimeSpan _lastVerbTime;
private static readonly TimeSpan VerbCooldown = TimeSpan.FromSeconds(0.5f);
private static readonly TimeSpan VerbCooldown = TimeSpan.FromSeconds(2f);
public VerbsTabControl()
{

View file

@ -1,5 +1,7 @@
using System.Collections.Frozen;
using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Emoting;
using Content.Shared.Speech;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
@ -88,6 +90,16 @@ public partial class ChatSystem
if (!forceEmote && !AllowedToUseEmote(source, emote))
return;
// Sunrise-Start
if (emote.Animation)
{
var ev = new AnimationEmoteAttemptEvent(source, emote);
RaiseLocalEvent(source, ev, true);
if (ev.Cancelled)
return;
}
// Sunrise-End
// check if proto has valid message for chat
if (emote.ChatMessages.Count != 0)
{

View file

@ -25,6 +25,6 @@ public sealed partial class EmotesMenuSystem : EntitySystem
if (!_prototypeManager.TryIndex(msg.ProtoId, out var proto))
return;
_chat.TryEmoteWithChat(player.Value, msg.ProtoId);
_chat.TryEmoteWithChat(player.Value, proto.ID);
}
}

View file

@ -1,19 +1,15 @@
using Content.Server.Chat.Systems;
using Content.Server.Popups;
using Content.Shared._Sunrise.Animations;
using Content.Shared._Sunrise.Flip;
using Content.Shared._Sunrise.Jump;
using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Damage.Systems;
using Content.Shared.Gravity;
using Content.Shared.Standing;
using Content.Shared.StatusEffect;
using Robust.Server.Audio;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server._Sunrise.Animations;
@ -21,20 +17,25 @@ public sealed class EmoteAnimationSystem : EntitySystem
{
[Dependency] private readonly SharedStandingStateSystem _sharedStanding = default!;
[Dependency] private readonly SharedGravitySystem _gravity = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
[Dependency] private readonly StaminaSystem _staminaSystem = default!;
[Dependency] private readonly AudioSystem _audioSystem = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedJumpSystem _jumpSystem = default!;
[Dependency] private readonly SharedFlipSystem _flipSystem = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public static string JumpStatusEffectKey = "Jump";
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly ChatSystem _chat = default!;
public override void Initialize()
{
SubscribeLocalEvent<EmoteAnimationComponent, ComponentGetState>(OnGetState);
SubscribeLocalEvent<EmoteAnimationComponent, EmoteEvent>(OnEmote);
SubscribeLocalEvent<EmoteAnimationComponent, PlayEmoteMessage>(OnPlayEmote);
}
private void OnPlayEmote(EntityUid uid, EmoteAnimationComponent component, PlayEmoteMessage args)
{
if (!_prototypeManager.TryIndex(args.ProtoId, out var proto))
return;
_chat.TryEmoteWithChat(uid, proto.ID);
}
private void OnGetState(EntityUid uid, EmoteAnimationComponent component, ref ComponentGetState args)
@ -52,7 +53,7 @@ public sealed class EmoteAnimationSystem : EntitySystem
public void PlayEmoteAnimation(EntityUid uid, EmoteAnimationComponent component, string emoteId)
{
if (emoteId == "EmoteLay")
if (emoteId == "Lay")
{
if (_gravity.IsWeightless(uid))
return;
@ -65,38 +66,20 @@ public sealed class EmoteAnimationSystem : EntitySystem
return;
}
if (emoteId == "EmoteJump")
if (emoteId == "Jump")
{
if (_gravity.IsWeightless(uid))
return;
// Мейби в будущем
//_staminaSystem.TakeStaminaDamage(uid, 10);
// Временная ржомба
_audioSystem.PlayEntity("/Audio/_Sunrise/jump_mario.ogg", Filter.Pvs(uid), uid, true, AudioParams.Default);
if (_random.Prob(0.001f))
{
_popupSystem.PopupEntity("Неудачно приземляется на шею.", uid);
var damage = new DamageSpecifier(_prototypeManager.Index<DamageTypePrototype>("Blunt"), 200);
_damageableSystem.TryChangeDamage(uid, damage, true, useVariance: false, useModifier: false);
}
_statusEffects.TryAddStatusEffect<JumpComponent>(uid,
JumpStatusEffectKey,
TimeSpan.FromMilliseconds(500),
false);
_jumpSystem.TryJump(uid);
}
if (emoteId == "EmoteFlip")
if (emoteId == "Flip")
{
if (_random.Prob(0.001f))
{
_popupSystem.PopupEntity("Неудачно приземляется на шею.", uid);
var damage = new DamageSpecifier(_prototypeManager.Index<DamageTypePrototype>("Blunt"), 200);
_damageableSystem.TryChangeDamage(uid, damage, true, useVariance: false, useModifier: false);
}
_flipSystem.TryFlip(uid);
}
if (emoteId == "FallOnNeck")
{
var damage = new DamageSpecifier(_prototypeManager.Index<DamageTypePrototype>("Blunt"), 200);
_damageableSystem.TryChangeDamage(uid, damage, true, useVariance: false, useModifier: false);
}
component.AnimationId = emoteId;

View file

@ -0,0 +1,40 @@
using Content.Server.Chat.Systems;
using Content.Shared._Sunrise.Flip;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Mobs.Components;
using Content.Shared.Weapons.Melee.Events;
namespace Content.Server._Sunrise.Flip;
public sealed class FlipSystem : SharedFlipSystem
{
[Dependency] private readonly ChatSystem _chat = default!;
[ValidatePrototypeId<EmotePrototype>]
private const string EmoteFlipProto = "Flip";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FlipOnAttackComponent, MeleeHitEvent>(OnFlipOnAttack);
}
private void OnFlipOnAttack(EntityUid uid, FlipOnAttackComponent component, MeleeHitEvent args)
{
Logger.Info("OnFlipOnAttack");
foreach (var entity in args.HitEntities)
{
if (!HasComp<MobStateComponent>(entity))
continue;
PlayEmoteFlip(args.User);
return;
}
}
private void PlayEmoteFlip(EntityUid uid)
{
_chat.TryEmoteWithChat(uid, EmoteFlipProto);
}
}

View file

@ -0,0 +1,12 @@
using Content.Shared._Sunrise.Jump;
namespace Content.Server._Sunrise.Jump;
public sealed class JumpSystem : SharedJumpSystem
{
public override void Initialize()
{
base.Initialize();
}
}

View file

@ -68,6 +68,9 @@ public sealed partial class EmotePrototype : IPrototype
/// </summary>
[DataField]
public HashSet<string> ChatTriggers = new();
[DataField]
public bool Animation;
}
/// <summary>

View file

@ -1,4 +1,6 @@
namespace Content.Shared.Emoting
using Content.Shared.Chat.Prototypes;
namespace Content.Shared.Emoting
{
public sealed class EmoteAttemptEvent : CancellableEntityEventArgs
{
@ -9,4 +11,18 @@
public EntityUid Uid { get; }
}
public sealed class AnimationEmoteAttemptEvent : CancellableEntityEventArgs
{
public AnimationEmoteAttemptEvent(EntityUid uid, EmotePrototype emote)
{
Uid = uid;
Emote = emote;
}
public EntityUid Uid { get; }
[ViewVariables, DataField("emote", readOnly: true, required: true)]
public EmotePrototype Emote = default!;
}
}

View file

@ -1,8 +1,10 @@
using Content.Shared._Sunrise.Jump;
using Content.Shared.ActionBlocker;
using Content.Shared.Buckle;
using Content.Shared.Buckle.Components;
using Content.Shared.Damage.Systems;
using Content.Shared.DoAfter;
using Content.Shared.Emoting;
using Content.Shared.Hands.Components;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Systems;
@ -35,6 +37,7 @@ public abstract class SharedStandingStateSystem : EntitySystem
[Dependency] private readonly SharedStunSystem _stun = default!;
[Dependency] private readonly ThrowingSystem _throwing = default!;
[Dependency] private readonly ActionBlockerSystem _blocker = default!;
[Dependency] private readonly SharedJumpSystem _jumpSystem = default!;
private const int StandingCollisionLayer = (int) CollisionGroup.MidImpassable;
@ -46,8 +49,21 @@ public abstract class SharedStandingStateSystem : EntitySystem
SubscribeLocalEvent<StandingStateComponent, DownDoAfterEvent>(OnDownDoAfter);
SubscribeLocalEvent<StandingStateComponent, MoveEvent>(OnMove);
SubscribeLocalEvent<StandingStateComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMovementSpeed);
SubscribeLocalEvent<StandingStateComponent, AnimationEmoteAttemptEvent>(CheckEmote);
}
// Sunrise-Start
private void CheckEmote(EntityUid target, StandingStateComponent component, AnimationEmoteAttemptEvent args)
{
if (args.Emote.ID == "Jump" && (component.CurrentState == StandingState.Laying || !_jumpSystem.Enabled))
{
args.Cancel();
}
}
// Sunrise-End
#region Implementation
private void OnStandUpDoAfter(EntityUid uid, StandingStateComponent component, StandUpDoAfterEvent args)

View file

@ -0,0 +1,10 @@
using Robust.Shared.GameStates;
namespace Content.Shared._Sunrise.Flip
{
[NetworkedComponent, RegisterComponent]
public sealed partial class FlipComponent : Component
{
public Dictionary<string, int> OriginalCollisionLayers { get; } = new();
}
}

View file

@ -0,0 +1,7 @@
using Robust.Shared.GameStates;
namespace Content.Shared._Sunrise.Flip
{
[NetworkedComponent, RegisterComponent]
public sealed partial class FlipOnAttackComponent : Component;
}

View file

@ -0,0 +1,109 @@
using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Gravity;
using Content.Shared.Mobs.Systems;
using Content.Shared.Physics;
using Content.Shared.Standing;
using Content.Shared.StatusEffect;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Random;
namespace Content.Shared._Sunrise.Flip;
public abstract class SharedFlipSystem : EntitySystem
{
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
[Dependency] private readonly SharedGravitySystem _gravity = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly SharedStandingStateSystem _standingStateSystem = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
private EntityQuery<FixturesComponent> _fixturesQuery;
[ValidatePrototypeId<StatusEffectPrototype>]
private const string FlipStatusEffectKey = "Flip";
[ValidatePrototypeId<EmotePrototype>]
private const string EmoteFallOnNeckProto = "FallOnNeck";
private const string FlipSound = "";
private static float _deadChance = 0.001f;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FlipComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<FlipComponent, ComponentShutdown>(OnShutdown);
_cfg.OnValueChanged(SunriseCCVars.SunriseCCVars.FlipDeadChanse, OnFlipDeadChanseChanged, true);
_fixturesQuery = GetEntityQuery<FixturesComponent>();
}
private void OnFlipDeadChanseChanged(float deadChanse)
{
_deadChance = deadChanse;
}
public void TryFlip(EntityUid uid)
{
if (_gravity.IsWeightless(uid) ||
_standingStateSystem.IsDown(uid) ||
!_mobState.IsAlive(uid))
return;
Flip(uid);
}
public void Flip(EntityUid uid)
{
_statusEffects.TryAddStatusEffect<FlipComponent>(uid,
FlipStatusEffectKey,
TimeSpan.FromMilliseconds(500),
false);
}
private void OnStartup(Entity<FlipComponent> ent, ref ComponentStartup args)
{
if (!_fixturesQuery.TryGetComponent(ent.Owner, out var fixtures))
return;
// SUNRISE-TODO: Звук сальто
//if (_net.IsServer)
// _audioSystem.PlayEntity(FlipSound, Filter.Pvs(ent.Owner), ent.Owner, true, AudioParams.Default.WithVolume(-5f));
foreach (var (id, fixture) in fixtures.Fixtures)
{
ent.Comp.OriginalCollisionLayers[id] = fixture.CollisionLayer;
_physics.RemoveCollisionLayer(ent.Owner, id, fixture, (int) CollisionGroup.BulletImpassable, manager: fixtures);
_physics.RemoveCollisionLayer(ent.Owner, id, fixture, (int) CollisionGroup.Opaque, manager: fixtures);
}
}
private void OnShutdown(Entity<FlipComponent> ent, ref ComponentShutdown args)
{
if (!_fixturesQuery.TryGetComponent(ent.Owner, out var fixtures))
return;
foreach (var (id, fixture) in fixtures.Fixtures)
{
if (ent.Comp.OriginalCollisionLayers.TryGetValue(id, out var originalLayer))
{
_physics.SetCollisionLayer(ent.Owner, id, fixture, originalLayer, manager: fixtures);
}
}
if (_random.Prob(_deadChance) && _net.IsServer)
{
RaiseLocalEvent(ent, new PlayEmoteMessage(EmoteFallOnNeckProto));
}
}
}

View file

@ -0,0 +1,11 @@
using Robust.Shared.GameStates;
namespace Content.Shared._Sunrise.Jump;
[NetworkedComponent, RegisterComponent]
public sealed partial class BunnyHopComponent : Component
{
public TimeSpan LastLandingTime { get; set; } = TimeSpan.Zero;
public float SpeedMultiplier { get; set; } = 1.0f;
public bool CanBunnyHop => SpeedMultiplier > 1.0f;
};

View file

@ -0,0 +1,13 @@
using Robust.Shared.Serialization;
namespace Content.Shared._Sunrise.Jump;
[Serializable, NetSerializable]
public sealed class ClientOptionJumpSoundEvent : EntityEventArgs
{
public bool Enabled { get; }
public ClientOptionJumpSoundEvent(bool enabled)
{
Enabled = enabled;
}
}

View file

@ -1,7 +1,11 @@
using Robust.Shared.GameStates;
namespace Content.Shared._Sunrise.Animations
namespace Content.Shared._Sunrise.Jump;
[NetworkedComponent, RegisterComponent]
public sealed partial class JumpComponent : Component
{
[NetworkedComponent, RegisterComponent]
public sealed partial class JumpComponent : Component;
}
public Dictionary<string, int> OriginalCollisionMasks { get; } = new();
public Dictionary<string, int> OriginalCollisionLayers { get; } = new();
};

View file

@ -1,54 +0,0 @@
using Content.Shared._Sunrise.Animations;
using Content.Shared.Physics;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
namespace Content.Shared._Sunrise.Jump;
public class SharedJumpSystem : EntitySystem
{
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
private EntityQuery<PhysicsComponent> _physicsQuery;
private EntityQuery<FixturesComponent> _fixturesQuery;
public override void Initialize()
{
SubscribeLocalEvent<JumpComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<JumpComponent, ComponentShutdown>(OnShutdown);
_physicsQuery = GetEntityQuery<PhysicsComponent>();
_fixturesQuery = GetEntityQuery<FixturesComponent>();
}
private void OnStartup(Entity<JumpComponent> ent, ref ComponentStartup args)
{
if (!_physicsQuery.TryGetComponent(ent.Owner, out var body) ||
!_fixturesQuery.TryGetComponent(ent.Owner, out var fixtures))
return;
_physics.SetBodyStatus(ent.Owner, body, BodyStatus.InAir);
foreach (var (id, fixture) in fixtures.Fixtures)
{
_physics.RemoveCollisionMask(ent.Owner, id, fixture, (int) CollisionGroup.TableLayer, manager: fixtures);
_physics.RemoveCollisionMask(ent.Owner, id, fixture, (int) CollisionGroup.BulletImpassable, manager: fixtures);
_physics.RemoveCollisionMask(ent.Owner, id, fixture, (int) CollisionGroup.CrateMask, manager: fixtures);
}
}
private void OnShutdown(Entity<JumpComponent> ent, ref ComponentShutdown args)
{
if (!_physicsQuery.TryGetComponent(ent.Owner, out var body) ||
!_fixturesQuery.TryGetComponent(ent.Owner, out var fixtures))
return;
_physics.SetBodyStatus(ent.Owner, body, BodyStatus.OnGround);
foreach (var (id, fixture) in fixtures.Fixtures)
{
_physics.AddCollisionMask(ent.Owner, id, fixture, (int) CollisionGroup.TableLayer, manager: fixtures);
_physics.AddCollisionMask(ent.Owner, id, fixture, (int) CollisionGroup.BulletImpassable, manager: fixtures);
_physics.AddCollisionMask(ent.Owner, id, fixture, (int) CollisionGroup.CrateMask, manager: fixtures);
}
}
}

View file

@ -0,0 +1,196 @@
using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Damage.Systems;
using Content.Shared.Gravity;
using Content.Shared.Mobs.Systems;
using Content.Shared.Physics;
using Content.Shared.Standing;
using Content.Shared.StatusEffect;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Player;
using Robust.Shared.Random;
using Content.Shared.Movement.Systems;
using Robust.Shared.Timing;
namespace Content.Shared._Sunrise.Jump;
public abstract class SharedJumpSystem : EntitySystem
{
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffects = default!;
[Dependency] private readonly SharedGravitySystem _gravity = default!;
[Dependency] private readonly StaminaSystem _staminaSystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly SharedStandingStateSystem _standingStateSystem = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly MovementSpeedModifierSystem _movementSpeedModifier = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private EntityQuery<PhysicsComponent> _physicsQuery;
private EntityQuery<FixturesComponent> _fixturesQuery;
[ValidatePrototypeId<StatusEffectPrototype>]
private const string JumpStatusEffectKey = "Jump";
[ValidatePrototypeId<EmotePrototype>]
private const string EmoteFallOnNeckProto = "FallOnNeck";
private static float _deadChance = 1.0f;
private static readonly TimeSpan SpeedBoostWindow = TimeSpan.FromSeconds(0.650);
private const float MinSpeedThreshold = 4.0f;
public bool Enabled;
private readonly List<ICommonSession> _ignoredRecipients = [];
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<JumpComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<JumpComponent, ComponentShutdown>(OnShutdown);
SubscribeNetworkEvent<ClientOptionJumpSoundEvent>(OnClientOptionJumpSound);
SubscribeLocalEvent<BunnyHopComponent, RefreshMovementSpeedModifiersEvent>(OnRefreshMoveSpeed);
_physicsQuery = GetEntityQuery<PhysicsComponent>();
_fixturesQuery = GetEntityQuery<FixturesComponent>();
_cfg.OnValueChanged(SunriseCCVars.SunriseCCVars.JumpEnabled, OnJumpEnabledChanged, true);
_cfg.OnValueChanged(SunriseCCVars.SunriseCCVars.JumpDeadChanse, OnJumpDeadChanseChanged, true);
}
private void OnRefreshMoveSpeed(EntityUid uid, BunnyHopComponent component, RefreshMovementSpeedModifiersEvent args)
{
if (component.CanBunnyHop)
args.ModifySpeed(component.SpeedMultiplier, component.SpeedMultiplier);
}
private async void OnClientOptionJumpSound(ClientOptionJumpSoundEvent ev, EntitySessionEventArgs args)
{
if (ev.Enabled)
_ignoredRecipients.Remove(args.SenderSession);
else
_ignoredRecipients.Add(args.SenderSession);
}
private void OnJumpEnabledChanged(bool enanled)
{
Enabled = enanled;
}
private void OnJumpDeadChanseChanged(float deadChanse)
{
_deadChance = deadChanse;
}
public void TryJump(EntityUid uid)
{
if (_gravity.IsWeightless(uid) ||
_standingStateSystem.IsDown(uid) ||
!_mobState.IsAlive(uid))
return;
Jump(uid);
}
public void Jump(EntityUid uid)
{
_statusEffects.TryAddStatusEffect<JumpComponent>(uid,
JumpStatusEffectKey,
TimeSpan.FromMilliseconds(500),
false);
}
private void OnStartup(Entity<JumpComponent> ent, ref ComponentStartup args)
{
if (!_physicsQuery.TryGetComponent(ent.Owner, out var body) ||
!_fixturesQuery.TryGetComponent(ent.Owner, out var fixtures))
return;
// SUNRISE-TODO: Прыжки тратят стамину
//_staminaSystem.TakeStaminaDamage(uid, 10);
if (_net.IsServer)
_audioSystem.PlayEntity("/Audio/_Sunrise/jump_mario.ogg", Filter.Pvs(ent.Owner).RemovePlayers(_ignoredRecipients), ent.Owner, true, AudioParams.Default.WithVolume(-5f));
_physics.SetBodyStatus(ent.Owner, body, BodyStatus.InAir);
foreach (var (id, fixture) in fixtures.Fixtures)
{
ent.Comp.OriginalCollisionMasks[id] = fixture.CollisionMask;
ent.Comp.OriginalCollisionLayers[id] = fixture.CollisionLayer;
_physics.RemoveCollisionMask(ent.Owner, id, fixture, (int) CollisionGroup.LowImpassable, manager: fixtures);
_physics.RemoveCollisionMask(ent.Owner, id, fixture, (int) CollisionGroup.MidImpassable, manager: fixtures);
_physics.RemoveCollisionLayer(ent.Owner, id, fixture, (int) CollisionGroup.BulletImpassable, manager: fixtures);
_physics.RemoveCollisionLayer(ent.Owner, id, fixture, (int) CollisionGroup.Opaque, manager: fixtures);
}
var currentSpeed = body.LinearVelocity.Length();
if (currentSpeed < MinSpeedThreshold)
return;
var bunnyHopComp = EnsureComp<BunnyHopComponent>(ent.Owner);
bunnyHopComp.LastLandingTime = _timing.CurTime;
var timeSinceLastLand = _timing.CurTime - bunnyHopComp.LastLandingTime;
if (timeSinceLastLand <= SpeedBoostWindow)
{
bunnyHopComp.SpeedMultiplier += 0.05f;
_movementSpeedModifier.RefreshMovementSpeedModifiers(ent.Owner);
}
}
private void OnShutdown(Entity<JumpComponent> ent, ref ComponentShutdown args)
{
if (!_physicsQuery.TryGetComponent(ent.Owner, out var body) ||
!_fixturesQuery.TryGetComponent(ent.Owner, out var fixtures))
return;
_physics.SetBodyStatus(ent.Owner, body, BodyStatus.OnGround);
foreach (var (id, fixture) in fixtures.Fixtures)
{
if (ent.Comp.OriginalCollisionMasks.TryGetValue(id, out var originalMask))
{
_physics.SetCollisionMask(ent.Owner, id, fixture, originalMask, manager: fixtures);
}
if (ent.Comp.OriginalCollisionLayers.TryGetValue(id, out var originalLayer))
{
_physics.SetCollisionLayer(ent.Owner, id, fixture, originalLayer, manager: fixtures);
}
}
if (_random.Prob(_deadChance) && _net.IsServer)
{
RaiseLocalEvent(ent, new PlayEmoteMessage(EmoteFallOnNeckProto));
}
if (TryComp(ent.Owner, out BunnyHopComponent? bunnyHopComp))
{
bunnyHopComp.LastLandingTime = _timing.CurTime;
}
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<BunnyHopComponent>();
while (query.MoveNext(out var uid, out var bunnyHop))
{
var timeSinceLastLand = _timing.CurTime - bunnyHop.LastLandingTime;
if (timeSinceLastLand > SpeedBoostWindow)
{
RemComp<BunnyHopComponent>(uid);
_movementSpeedModifier.RefreshMovementSpeedModifiers(uid);
}
}
}
}

View file

@ -319,4 +319,24 @@ public sealed class SunriseCCVars
public static readonly CVarDef<bool> MoodDecreasesSpeed =
CVarDef.Create("mood.decreases_speed", true, CVar.SERVER);
/**
* Tape Player
*/
public static readonly CVarDef<bool> JumpEnabled =
CVarDef.Create("jump.enabled", true, CVar.SERVER | CVar.REPLICATED);
public static readonly CVarDef<float> JumpDeadChanse =
CVarDef.Create("jump.dead_chanse", 0.001f, CVar.SERVER | CVar.REPLICATED);
public static readonly CVarDef<bool> JumpSoundEnabled =
CVarDef.Create("jump.sound_enabled", true, CVar.CLIENTONLY | CVar.ARCHIVE);
/**
* Tape Player
*/
public static readonly CVarDef<float> FlipDeadChanse =
CVarDef.Create("flip.dead_chanse", 0.001f, CVar.SERVER | CVar.REPLICATED);
}

View file

@ -8671,3 +8671,46 @@
type: Tweak
id: 607
time: '2024-12-25T00:28:56.511391+00:00'
- author: VigersRay
changes:
- message: "\u0411\u043E\u043B\u044C\u0448\u0435 \u043D\u0435\u043B\u044C\u0437\u044F\
\ \u043F\u0440\u044B\u0433\u0430\u0442\u044C \u0441\u043A\u0432\u043E\u0437\u044C\
\ \u0441\u0442\u0435\u043D\u044B."
type: Fix
- message: "\u0411\u043E\u043B\u044C\u0448\u0435 \u043D\u0435\u043B\u044C\u0437\u044F\
\ \u043F\u0440\u044B\u0433\u0430\u0442\u044C \u043B\u0435\u0436\u0430."
type: Fix
- message: "\u0411\u043E\u043B\u044C\u0448\u0435 \u043D\u0435\u043B\u044C\u0437\u044F\
\ \u043E\u0434\u043D\u043E\u0432\u0440\u0435\u043C\u0435\u043D\u043D\u043E \u0432\
\u044B\u043F\u043E\u043B\u043D\u044F\u0442\u044C \u043F\u0440\u044B\u0436\u043E\
\u043A \u0438 \u0441\u0430\u043B\u044C\u0442\u043E."
type: Fix
- message: "\u041D\u0430 \u043F\u0440\u044B\u0436\u043E\u043A \u043F\u0440\u043E\
\u0431\u0435\u043B\u043E\u043C \u0438 \u043F\u0430\u043D\u0435\u043B\u044C\u044E\
\ \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043E\u0431\u0449\u0438\u0439\
\ \u043A\u0443\u043B\u0434\u0430\u0443\u043D."
type: Fix
- message: "\u0422\u0435\u043F\u0435\u0440\u044C \u0432\u044B \u043C\u043E\u0436\
\u0435\u0442\u0435 \u043E\u0442\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u0437\
\u0432\u0443\u043A \u043F\u0440\u044B\u0436\u043A\u0430 \u0432 \u043D\u0430\u0441\
\u0442\u0440\u043E\u0439\u043A\u0430\u0445."
type: Tweak
- message: "\u0421\u0430\u043B\u044C\u0442\u043E \u0442\u0435\u043F\u0435\u0440\u044C\
\ \u043F\u043E\u0437\u0432\u043E\u043B\u044F\u0435\u0442 \u0443\u043A\u043B\u043E\
\u043D\u044F\u0442\u044C\u0441\u044F \u043E\u0442 \u043F\u0443\u043B\u044C."
type: Tweak
- message: "\u0410\u0442\u0430\u043A\u0443\u044F \u0434\u0432\u043E\u0439\u043D\u044B\
\u043C \u044D\u043D\u0435\u0440\u0433\u043E \u043C\u0435\u0447\u0435\u043C \u0432\
\u044B \u0431\u0443\u0434\u0435\u0442\u0435 \u0434\u0435\u043B\u0430\u0442\u044C\
\ \u0441\u0430\u043B\u044C\u0442\u043E."
type: Tweak
- message: "\u0414\u0435\u043B\u0430\u044F \u0441\u0430\u043B\u044C\u0442\u043E\
\ \u0438\u043B\u0438 \u043F\u0440\u044B\u0436\u043E\u043A \u0435\u0441\u0442\
\u044C \u0448\u0430\u043D\u0441 1/1000 \u0441\u043B\u043E\u043C\u0430\u0442\u044C\
\ \u0448\u0435\u044E."
type: Tweak
- message: "\u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D \u0431\u0430\u043D\u0438\
\u0445\u043E\u043F."
type: Add
id: 608
time: '2024-12-26T02:41:49.774848+00:00'

View file

@ -4,7 +4,3 @@ laying-comp-lay-fail-self = Вы не можете лечь прямо сейч
laying-comp-stand-success-self = Вы встаёте.
laying-comp-stand-success-other = { THE($entity) } встаёт.
laying-comp-stand-fail-self = Вы не можете встать прямо сейчас.
ui-options-function-toggle-standing = Лечь/Встать.
ui-options-function-look-up = Присмотреться/Прицелиться
ui-options-function-auto-get-up = Автоматически вставать при падении
ui-options-function-hold-look-up = Удерживать клавишу для прицеливания

View file

@ -15,65 +15,65 @@ server-role-ban =
}.
server-perma-role-ban = Перманентный джоб-бан.
server-time-ban-string =
> **Нарушитель**
> **Логин:** ``{ $targetName }``
> **Дискорд:** { $targetLink }
> **Администратор**
> **Логин:** ``{ $adminName }``
> **Дискорд:** { $adminLink }
> **Нарушитель**
> **Логин:** ``{ $targetName }``
> **Дискорд:** { $targetLink }
> **Выдан:** { $TimeNow }
> **Истечёт:** { $expiresString }
> **Причина:** { $reason }
> **Уровень тяжести:** { $severity }
server-ban-footer = { $server } | Раунд: #{ $round }
server-perma-ban-string =
> **Нарушитель**
> **Логин:** ``{ $targetName }``
> **Дискорд:** { $targetLink }
> **Администратор**
> **Логин:** ``{ $adminName }``
> **Дискорд:** { $adminLink }
> **Нарушитель**
> **Логин:** ``{ $targetName }``
> **Дискорд:** { $targetLink }
> **Выдан:** { $TimeNow }
> **Причина:** { $reason }
> **Уровень тяжести:** { $severity }
server-role-ban-string =
> **Нарушитель**
> **Логин:** ``{ $targetName }``
> **Дискорд:** { $targetLink }
> **Администратор**
> **Логин:** ``{ $adminName }``
> **Дискорд:** { $adminLink }
> **Нарушитель**
> **Логин:** ``{ $targetName }``
> **Дискорд:** { $targetLink }
> **Выдан:** { $TimeNow }
> **Истечёт:** { $expiresString }
> **Роли:** { $roles }
> **Причина:** { $reason }
> **Уровень тяжести:** { $severity }
server-perma-role-ban-string =
> **Администратор**
> **Логин:** ``{ $adminName }``
> **Дискорд:** { $adminLink }
> **Нарушитель**
> **Логин:** ``{ $targetName }``
> **Дискорд:** ``{ $targetLink }``
> **Администратор**
> **Логин:** ``{ $adminName }``
> **Дискорд:** { $adminLink }
> **Выдан:** { $TimeNow }
> **Роли:** { $roles }
> **Причина:** { $reason }
> **Уровень тяжести:** { $severity }

View file

@ -9,3 +9,13 @@ ui-options-sunrise-general-graphics = Графика
ui-options-sunrise-general-lobby = Лобби
ui-options-sunrise-general-combat = Бой
ui-options-tab-sunrise = Санрайз
ui-options-tts-enabled = TTS интеграция
ui-options-tape-player-enabled = Школьники с колонками (Нужен рестарт раунда)
ui-options-jump-sound-enabled = Звук прыжка
ui-options-function-toggle-standing = Лечь/Встать
ui-options-function-cock-gun = Взвести оружие/Разрядить
ui-options-function-jump = Прыжок
ui-options-function-reloading = Перезарядка
ui-options-function-look-up = Присмотреться/Прицелиться
ui-options-function-auto-get-up = Автоматически вставать при падении
ui-options-function-hold-look-up = Удерживать клавишу для прицеливания

View file

@ -35,8 +35,6 @@ ui-options-lobby-music = Музыка в лобби
ui-options-restart-sounds = Звуки перезапуска раунда
ui-options-event-music = Музыка событий
ui-options-admin-sounds = Музыка админов
ui-options-tts-enabled = TTS интеграция
ui-options-tape-player-enabled = Школьники с колонками (Нужен рестарт раунда)
ui-options-volume-label = Громкость
ui-options-display-label = Дисплей
ui-options-quality-label = Качество

View file

@ -1,2 +0,0 @@
ent-StorageCanisterBase = самодельная канистра для газа
.desc = { ent-GasCanister.desc }

View file

@ -41,6 +41,7 @@
- ForcedSleep
- StaminaModifier
- Jump # Sunrise-Edit
- Flip # Sunrise-Edit
- type: MobState
allowedStates:
- Alive

View file

@ -144,6 +144,7 @@
- Adrenaline
- LoveEffect # Sunrise-Edit
- Jump # Sunrise-Edit
- Flip # Sunrise-Edit
- type: Body
prototype: Human
requiredLegs: 2

View file

@ -345,6 +345,7 @@
reflectProb: .50
spread: 90
needActiveHand: true
- type: FlipOnAttack # Sunrise-Edit
- type: entity
suffix: One-Handed, For Borgs

View file

@ -1,5 +1,5 @@
- type: emote
id: EmoteFlip
id: Flip
category: Verb
name: Сальто
whitelist:
@ -9,6 +9,8 @@
components:
- Ghost
- BorgChassis
- Jump
- Flip
chatMessages: [делает сальто]
chatTriggers:
- сделал сальто
@ -16,9 +18,10 @@
- делает сальто
- устроила сальто
- устроил сальто
animation: true
- type: emote
id: EmoteJump
id: Jump
category: Verb
name: Прыгнуть
whitelist:
@ -28,6 +31,8 @@
components:
- Ghost
- BorgChassis
- Jump
- Flip
chatMessages: [прыгает]
chatTriggers:
- прыгает
@ -36,9 +41,10 @@
- подпрыгнул
- подпрыгнула
- подскакивает
animation: true
- type: emote
id: EmoteTurn
id: Dance
category: Verb
name: Танцевать
whitelist:
@ -48,6 +54,8 @@
components:
- Ghost
- BorgChassis
- Jump
- Flip
chatMessages: [танцует]
chatTriggers:
- танцует
@ -55,11 +63,27 @@
- оборачивается
- покружилась
- покружился
animation: true
- type: emote
id: EmoteLay
id: Lay
category: Verb
name: Лечь/Встать
whitelist:
components:
- Hands
- Jump
- Flip
blacklist:
components:
- Ghost
- BorgChassis
animation: true
- type: emote
id: FallOnNeck
category: Verb
name: Упасть на шею
whitelist:
components:
- Hands
@ -67,3 +91,5 @@
components:
- Ghost
- BorgChassis
chatMessages: [падает на шею]
animation: true

View file

@ -3,3 +3,6 @@
- type: statusEffect
id: Jump
- type: statusEffect
id: Flip