From d1504e4cb60ec1f88c74f1c9cf360167e3a6ea1c Mon Sep 17 00:00:00 2001 From: insvrg3ncy Date: Wed, 13 May 2026 14:03:40 +0300 Subject: [PATCH 1/4] linter fixes and readme update --- LICENSE-AGPLv3.txt | 18 --- README.md | 104 ++++++++++++++---- .../Prototypes/Entities/Mobs/NPCs/pets.yml | 2 +- .../Entities/Mobs/Player/silicon.yml | 2 +- .../Prototypes/_TSF/Reagents/morphine.yml | 2 +- 5 files changed, 87 insertions(+), 41 deletions(-) diff --git a/LICENSE-AGPLv3.txt b/LICENSE-AGPLv3.txt index c6ca1820041..be3f7b28e56 100644 --- a/LICENSE-AGPLv3.txt +++ b/LICENSE-AGPLv3.txt @@ -1,21 +1,3 @@ -Copyright (C) 2024-2026 The Space Frontier and TSF contributors - -Исходный код на C#, прототипы YAML, шейдеры и прочие -человекочитаемые материалы в перечисленных ниже путях этого репозитория -распространяются на условиях GNU Affero General Public License v3.0 -(полный текст лицензии следует ниже). - - Content.Shared/_TSF/ - Content.Server/_TSF/ - Content.Client/_TSF/ - Resources/Prototypes/_TSF/ - Resources/Textures/_TSF/ - -Остальные материалы репозитория остаются на условиях, указанных в LICENSE.TXT, -в RobustToolbox/legal.md, а также в метаданных отдельных файлов и ассетов. - ------------------------------------------------------------------------- - GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 diff --git a/README.md b/README.md index 553a2d9cffb..c5103c9975f 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,104 @@ -
-Space Station 14 +
+ +# TSF · The Space Frontier + +Форк Space Station 14 для проекта The Space Frontier. + +
+ +### Стек + +

+ +   + +   + +   + +

+ + +

+ + + +

+ +
+ +### Ссылки + + + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ +
+
-Space Station 14 это ремейк SS13, который работает на собственном движке [Robust Toolbox](https://github.com/space-wizards/RobustToolbox), написанном на C#. +--- + +## О проекте -Это репозиторий первого русскоязычного сервера по Space Station 14, целью которого является полный перевод игры на русский язык, поддержка актуальных изменений из основного репозитория, а так же добавление собственных изменений по необходимости. +**Space Station 14** - ремейк SS13. Игровой клиент и движок - **[Robust Toolbox](https://github.com/space-wizards/RobustToolbox)** написаны на C#. -## Ссылки +**The Space Frontier** - репозиторий проекта The Space Frontier (aka Космический рубеж). Контент и код мы ведём здесь. **Upstream по игровому контенту - Corvax** ([space-syndicate/space-station-14](https://github.com/space-syndicate/space-station-14)). -[Наш Discord](https://discord.station14.ru) | [Наша Вики](https://wiki.station14.ru) | [Steam](https://store.steampowered.com/app/1255460/Space_Station_14/) | [Клиент без Steam](https://spacestation14.io/about/nightlies/) | [Основной репозиторий](https://github.com/space-wizards/space-station-14) +--- ## Документация -На официальном сайте с [документацией](https://docs.spacestation14.io/) имеется вся необходимая информация о контенте SS14, движке, дизайне игры и многом другом. Также имеется много информации для начинающих разработчиков. +На **[docs.spacestation14.io](https://docs.spacestation14.io/)** собраны материалы по контенту, движку и дизайну - удобная отправная точка и для новичков в разработке. + +--- + +## Участие в разработке -## Контрибьют +Мы рады вкладу от сообщества. Заходите в **Discord**, если хотите помочь. Есть **[issues](https://github.com/TheSpaceFrontier/TSF/issues)** - можно брать задачи и не стесняться спрашивать совета. -Мы рады принять вклад от любого человека. Заходите в Discord, если хотите помочь. У нас есть [список проблем](https://github.com/space-syndicate/space-station-14-content/issues), которые нужно решить, и любой может за них взяться. Не бойтесь просить о помощи! -Только убедитесь, что ваши изменения и PRы соответствуют [руководству по контрибьюту](https://docs.spacestation14.com/en/general-development/codebase-info/pull-request-guidelines.html). +Пожалуйста, придерживайтесь **[руководства по PR](https://docs.spacestation14.com/en/general-development/codebase-info/pull-request-guidelines.html)** для изменений и пулл-реквестов. + +--- ## Сборка -1. Склонируйте этот репозиторий локально -2. Запустите `RUN_THIS.py` для инициализации подмодулей и скачивания движка. -3. Скомпилируйте проект. +1. Клонируйте репозиторий. +2. Запустите `RUN_THIS.py` - инициализация субмодулей и движка. +3. Соберите решение в IDE или через `dotnet build`. -[Более подробная инструкция по запуску проекта.](https://docs.spacestation14.com/en/general-development/setup.html) +Подробнее: **[настройка окружения](https://docs.spacestation14.com/en/general-development/setup.html)**. -## Лицензия +--- -Основной код форка (наследие Space Station 14 / Corvax) — по [MIT](LICENSE.TXT), с указанием правообладателей в том же файле. +## Лицензия -Оригинальный код **The Space Frontier** (`Content.Shared/_TSF/`, `Content.Server/_TSF/`, `Content.Client/_TSF/`) — по [GNU AGPLv3](LICENSE-AGPLv3.txt). Новые изменения в этих путях принимаются на условиях AGPLv3. -Движок **Robust Toolbox** (подмодуль) лицензируется отдельно; см. [RobustToolbox/legal.md](RobustToolbox/legal.md). +| | | +| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Код** | [AGPLv3](LICENSE-AGPLv3.txt) | +| **Большинство ассетов** | [CC-BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/) - лицензия и авторы указаны в метаданных RSI, [пример](https://github.com/space-syndicate/space-station-14/blob/master/Resources/Textures/Objects/Tools/crowbar.rsi/meta.json). | -Большинство ассетов лицензированы под [CC-BY-SA 3.0](https://creativecommons.org/licenses/by-sa/3.0/), если не указано иное. Ассеты имеют свою лицензию и авторские права в файле метаданных. [Пример](https://github.com/space-syndicate/space-station-14/blob/master/Resources/Textures/Objects/Tools/crowbar.rsi/meta.json). -Обратите внимание, что некоторые ассеты лицензированы на некоммерческой основе [CC-BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/) или аналогичной некоммерческой лицензией, и их необходимо удалить, если вы хотите использовать этот проект в коммерческих целях. +Часть ассетов распространяется на **некоммерческой** основе ([CC-BY-NC-SA 3.0](https://creativecommons.org/licenses/by-nc-sa/3.0/) и аналоги) - перед коммерческим использованием такие файлы нужно удалить или заменить. diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml index 5805c9b8826..df91761a472 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml @@ -928,7 +928,7 @@ description: An expert in quantum cracker theory components: - type: TTS # Corvax-TTS - voice: Meiow + voice: Meepo - type: Vocalizer maxVocalizeInterval: 240 # polly is chattier - type: RadioVocalizer diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index 3c9b85e197c..6c5105b85f8 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -412,7 +412,7 @@ categories: [ HideSpawnMenu, DoNotMap ] components: - type: TTS - voice: Machine_spirit_4 # Corvax-TTS + voice: Glados - type: Sprite # Once it's in a core it's pretty much an abstract entity at that point. visible: false diff --git a/Resources/Prototypes/_TSF/Reagents/morphine.yml b/Resources/Prototypes/_TSF/Reagents/morphine.yml index 36e4c46009c..616593887fc 100644 --- a/Resources/Prototypes/_TSF/Reagents/morphine.yml +++ b/Resources/Prototypes/_TSF/Reagents/morphine.yml @@ -12,7 +12,7 @@ flavor: medicine color: "#8B7355" metabolisms: - Medicine: + Bloodstream: effects: - !type:ModifyStatusEffect effectProto: StatusEffectPainNumbness From 05c0b0d200bc37ea421d685de246184ede0f9cb6 Mon Sep 17 00:00:00 2001 From: insvrg3ncy Date: Wed, 13 May 2026 14:44:19 +0300 Subject: [PATCH 2/4] yoo --- .../DamageEffects/TSFDamageEffectsSystem.cs | 16 ++- .../DamageEffects/TSFStatusMessageState.cs | 4 + .../TSFStatusMessageUIController.cs | 119 +++++++++++++++++- .../Health/TSFPneumothoraxDamageSystem.cs | 1 - .../Locale/en-US/_tsf/health-examine.ftl | 18 +-- .../Locale/ru-RU/_tsf/health-examine.ftl | 20 +-- .../Locale/ru-RU/_tsf/status_messages.ftl | 2 +- 7 files changed, 153 insertions(+), 27 deletions(-) diff --git a/Content.Client/_TSF/DamageEffects/TSFDamageEffectsSystem.cs b/Content.Client/_TSF/DamageEffects/TSFDamageEffectsSystem.cs index c5af5771c4b..bb53951e3e5 100644 --- a/Content.Client/_TSF/DamageEffects/TSFDamageEffectsSystem.cs +++ b/Content.Client/_TSF/DamageEffects/TSFDamageEffectsSystem.cs @@ -24,6 +24,7 @@ using Robust.Shared.Audio.Components; using Robust.Shared.Player; using Robust.Shared.Configuration; +using Robust.Shared.Localization; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -558,7 +559,18 @@ private void TryUpdateStatusMessage(EntityUid uid) var bucket = (int)(now / StatusMessageBucketSeconds); var seed = bucket * 13 + phraseList.Length; var idx = Math.Abs(seed % phraseList.Length); - TSFStatusMessageState.Message = phraseList[idx]; - TSFStatusMessageState.DisplayUntil = now + StatusMessageDisplayDuration; + var phraseId = phraseList[idx]; + var resolved = Loc.GetString(phraseId); + var revealSeconds = CountRunes(resolved) * TSFStatusMessageState.RevealSecondsPerRune; + TSFStatusMessageState.Message = phraseId; + TSFStatusMessageState.DisplayUntil = now + StatusMessageDisplayDuration + revealSeconds; + } + + private static int CountRunes(string s) + { + var n = 0; + foreach (var _ in s.EnumerateRunes()) + n++; + return n; } } diff --git a/Content.Client/_TSF/DamageEffects/TSFStatusMessageState.cs b/Content.Client/_TSF/DamageEffects/TSFStatusMessageState.cs index 4131b8e93de..d23c0e85b12 100644 --- a/Content.Client/_TSF/DamageEffects/TSFStatusMessageState.cs +++ b/Content.Client/_TSF/DamageEffects/TSFStatusMessageState.cs @@ -6,5 +6,9 @@ namespace Content.Client._TSF.DamageEffects; public static class TSFStatusMessageState { public static string? Message { get; set; } + public static double DisplayUntil { get; set; } + + /// Wall-clock delay between revealing each Unicode extended grapheme (rune). + public const float RevealSecondsPerRune = 0.042f; } diff --git a/Content.Client/_TSF/DamageEffects/TSFStatusMessageUIController.cs b/Content.Client/_TSF/DamageEffects/TSFStatusMessageUIController.cs index 6bc8366e611..8024e564b63 100644 --- a/Content.Client/_TSF/DamageEffects/TSFStatusMessageUIController.cs +++ b/Content.Client/_TSF/DamageEffects/TSFStatusMessageUIController.cs @@ -8,6 +8,7 @@ using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controllers; using Robust.Client.UserInterface.Controls; +using Robust.Shared.Localization; using Robust.Shared.Maths; using Robust.Shared.Timing; @@ -25,6 +26,17 @@ public sealed class TSFStatusMessageUIController : UIController private const float ShakeAmount = 3f; private const int FontSize = 22; private const int BottomMargin = 200; + private static readonly Color StatusTint = new(255, 45, 45, 255); + private const float HideFadeSeconds = 0.42f; + + private string? _revealLocId; + private string? _revealFullText; + private int _revealTotalRunes; + private int _revealVisibleRunes; + private float _revealCarrySeconds; + + private float _hideFadeRemaining; + private string? _hideFadeText; public override void Initialize() { @@ -101,6 +113,10 @@ private void OnScreenUnload() _panel = null; _labelContainer = null; _label = null; + _revealLocId = null; + _revealFullText = null; + _hideFadeRemaining = 0f; + _hideFadeText = null; } } @@ -110,9 +126,31 @@ public override void FrameUpdate(FrameEventArgs args) if (_label == null || _panel == null || _labelContainer == null) return; var now = _timing.RealTime.TotalSeconds; - if (TSFStatusMessageState.Message != null) + var msg = TSFStatusMessageState.Message; + if (msg != null) { - _label.Text = Loc.GetString(TSFStatusMessageState.Message); + _hideFadeRemaining = 0f; + _hideFadeText = null; + + if (msg != _revealLocId) + { + _revealLocId = msg; + _revealFullText = Loc.GetString(msg); + _revealTotalRunes = CountRunes(_revealFullText); + _revealVisibleRunes = 0; + _revealCarrySeconds = 0f; + } + + _revealCarrySeconds += args.DeltaSeconds; + var step = TSFStatusMessageState.RevealSecondsPerRune; + while (_revealVisibleRunes < _revealTotalRunes && _revealCarrySeconds >= step) + { + _revealCarrySeconds -= step; + _revealVisibleRunes++; + } + + _label.Text = TakeFirstRunes(_revealFullText!, _revealVisibleRunes); + _label.Modulate = StatusTint; _panel.Visible = true; var shakeX = (MathF.Sin((float)(now * 95)) + MathF.Sin((float)(now * 160) * 0.7f)) * ShakeAmount; var shakeY = (MathF.Sin((float)(now * 110) + 1.3f) + MathF.Sin((float)(now * 180) * 0.6f)) * ShakeAmount; @@ -120,8 +158,81 @@ public override void FrameUpdate(FrameEventArgs args) } else { - _panel.Visible = false; - LayoutContainer.SetPosition(_label, Vector2.Zero); + if (_hideFadeRemaining <= 0f) + { + if (!string.IsNullOrEmpty(_revealFullText)) + { + _hideFadeText = _revealFullText; + _hideFadeRemaining = HideFadeSeconds; + } + else if (_panel.Visible && !string.IsNullOrEmpty(_label.Text)) + { + _hideFadeText = _label.Text; + _hideFadeRemaining = HideFadeSeconds; + } + } + + _revealLocId = null; + _revealFullText = null; + _revealTotalRunes = 0; + _revealVisibleRunes = 0; + _revealCarrySeconds = 0f; + + if (_hideFadeRemaining > 0f) + { + _hideFadeRemaining -= args.DeltaSeconds; + var alphaNorm = Math.Clamp(Math.Max(0f, _hideFadeRemaining) / HideFadeSeconds, 0f, 1f); + _label.Text = _hideFadeText ?? string.Empty; + _label.Modulate = StatusTint.WithAlpha(alphaNorm); + _panel.Visible = true; + var shakeScale = alphaNorm; + var shakeX = (MathF.Sin((float)(now * 95)) + MathF.Sin((float)(now * 160) * 0.7f)) * ShakeAmount * shakeScale; + var shakeY = (MathF.Sin((float)(now * 110) + 1.3f) + MathF.Sin((float)(now * 180) * 0.6f)) * ShakeAmount * shakeScale; + LayoutContainer.SetPosition(_label, new Vector2(shakeX, shakeY)); + + if (_hideFadeRemaining <= 0f) + { + _hideFadeText = null; + _label.Text = string.Empty; + _label.Modulate = StatusTint; + _panel.Visible = false; + LayoutContainer.SetPosition(_label, Vector2.Zero); + } + } + else + { + _hideFadeText = null; + _label.Text = string.Empty; + _label.Modulate = StatusTint; + _panel.Visible = false; + LayoutContainer.SetPosition(_label, Vector2.Zero); + } + } + } + + private static int CountRunes(string s) + { + var n = 0; + foreach (var _ in s.EnumerateRunes()) + n++; + return n; + } + + private static string TakeFirstRunes(string s, int runeCount) + { + if (runeCount <= 0) + return string.Empty; + + var seen = 0; + var endUtf16 = 0; + foreach (var r in s.EnumerateRunes()) + { + if (seen >= runeCount) + break; + endUtf16 += r.Utf16SequenceLength; + seen++; } + + return s[..endUtf16]; } } diff --git a/Content.Server/_TSF/Health/TSFPneumothoraxDamageSystem.cs b/Content.Server/_TSF/Health/TSFPneumothoraxDamageSystem.cs index f8dcd1e6783..81d6fe56abe 100644 --- a/Content.Server/_TSF/Health/TSFPneumothoraxDamageSystem.cs +++ b/Content.Server/_TSF/Health/TSFPneumothoraxDamageSystem.cs @@ -33,7 +33,6 @@ public override void Update(float frameTime) continue; pn.NextDamage = _timing.CurTime + Interval; - Dirty(uid, pn); var spec = new DamageSpecifier(); spec.DamageDict["Asphyxiation"] = AsphyxPerTick; diff --git a/Resources/Locale/en-US/_tsf/health-examine.ftl b/Resources/Locale/en-US/_tsf/health-examine.ftl index 0c9c0414873..bb7f2cb6485 100644 --- a/Resources/Locale/en-US/_tsf/health-examine.ftl +++ b/Resources/Locale/en-US/_tsf/health-examine.ftl @@ -2,17 +2,17 @@ # SPDX-License-Identifier: AGPL-3.0-or-later tsf-health-examine-unconscious = [color=red]They are unconscious.[/color] -tsf-health-examine-consciousness-critical = [color=orange]Their vital signs suggest severe impairment of consciousness.[/color] +tsf-health-examine-consciousness-critical = [color=orange]Barely responsive - glassy stare, clumsy movements; clearly very out of it.[/color] tsf-health-examine-consciousness-low = They look dazed and unfocused. -tsf-health-examine-traumatic-shock = [color=orange]Signs of traumatic shock are present.[/color] -tsf-health-examine-hypovolemic-shock = [color=red]Signs of hypovolemic shock are present.[/color] +tsf-health-examine-traumatic-shock = [color=orange]Looks badly shaken: pale, wired, on edge.[/color] +tsf-health-examine-hypovolemic-shock = [color=red]Looks like serious blood loss: pale, clammy, barely holding up.[/color] tsf-health-examine-wound-infection = [color=orange]The open wounds look inflamed and hot to the touch.[/color] -tsf-health-examine-sepsis-mild = [color=red]Skin is flushed and clammy; pulse is racing — possible systemic infection.[/color] -tsf-health-examine-sepsis-severe = [color=red]Severe signs of sepsis: mottled skin, unstable vitals.[/color] +tsf-health-examine-sepsis-mild = [color=red]Skin feels clammy and cold, face waxy - like bad blood poisoning or sepsis.[/color] +tsf-health-examine-sepsis-severe = [color=red]They look awful: mottled, marbled skin, barely on their feet.[/color] tsf-stress-tension = Your heart hammers; every sound feels too loud. -tsf-defibrillator-revive-blocked = Vitals are too poor for a stable rhythm — stabilize blood and breathing first. +tsf-defibrillator-revive-blocked = They are not stable enough for a shock to catch - stabilize blood and breathing first. tsf-medical-record-defib = Defibrillation attempt logged (t+{$time}s). @@ -20,8 +20,8 @@ tsf-medical-record-tourniquet = Tourniquet applied; bleeding addressed (t+{$time tsf-medical-record-crit = Patient entered critical state (t+{$time}s). -tsf-medical-record-stabilized-from-crit = Vitals recovered from critical state (t+{$time}s). +tsf-medical-record-stabilized-from-crit = Condition cleared from critical (t+{$time}s). -tsf-health-examine-mob-critical = [color=red]They are in critical condition; vitals are unstable.[/color] +tsf-health-examine-mob-critical = [color=red]On the edge: breathing in jerks, barely moving.[/color] -tsf-morphine-tolerance-hint = Your limbs feel oddly heavy — the dose barely takes the edge off. +tsf-morphine-tolerance-hint = Your limbs feel oddly heavy - the dose barely takes the edge off. diff --git a/Resources/Locale/ru-RU/_tsf/health-examine.ftl b/Resources/Locale/ru-RU/_tsf/health-examine.ftl index 0956cb7bbfb..7f8ecde78cb 100644 --- a/Resources/Locale/ru-RU/_tsf/health-examine.ftl +++ b/Resources/Locale/ru-RU/_tsf/health-examine.ftl @@ -2,17 +2,17 @@ # SPDX-License-Identifier: AGPL-3.0-or-later tsf-health-examine-unconscious = [color=red]Без сознания.[/color] -tsf-health-examine-consciousness-critical = [color=orange]Жизненные показатели указывают на сильное угнетение сознания.[/color] +tsf-health-examine-consciousness-critical = [color=orange]Почти не откликается: взгляд пустой, движения неуверенные - явно сильно пришиблено по голове.[/color] tsf-health-examine-consciousness-low = Выглядит оглушённым и рассеянным. -tsf-health-examine-traumatic-shock = [color=orange]Признаки травматического шока.[/color] -tsf-health-examine-hypovolemic-shock = [color=red]Признаки гиповолемического шока.[/color] +tsf-health-examine-traumatic-shock = [color=orange]На вид сильное потрясение: бледный, весь на нервах.[/color] +tsf-health-examine-hypovolemic-shock = [color=red]Похоже на сильную кровопотерю: бледнота, холодный пот, еле держится.[/color] tsf-health-examine-wound-infection = [color=orange]Раны выглядят воспалёнными и горячими на ощупь.[/color] -tsf-health-examine-sepsis-mild = [color=red]Кожа влажная и бледная, пульс учащён — возможна сепсисная реакция.[/color] -tsf-health-examine-sepsis-severe = [color=red]Тяжёлые признаки сепсиса: пятнистая кожа, нестабильные показатели.[/color] +tsf-health-examine-sepsis-mild = [color=red]Кожа липкая и холодная на ощупь, лицо восковое - как при тяжёлой интоксикации или сепсисе.[/color] +tsf-health-examine-sepsis-severe = [color=red]Очень плохой вид: мраморная, пятнистая кожа, еле стоит на ногах.[/color] -tsf-stress-tension = Сердце колотится; каждый звук кажется слишком громким. +tsf-stress-tension = Сердце колотится, а каждый звук кажется слишком громким. -tsf-defibrillator-revive-blocked = Показатели слишком плохие для стабильного ритма — сначала стабилизируйте кровь и дыхание. +tsf-defibrillator-revive-blocked = Состояние слишком тяжёлое для стабильного ритма - сначала подтяните кровь и дыхание. tsf-medical-record-defib = Зафиксирована попытка дефибрилляции (t+{$time} с). @@ -20,8 +20,8 @@ tsf-medical-record-tourniquet = Наложен жгут; кровотечени tsf-medical-record-crit = Пациент вошёл в критическое состояние (t+{$time} с). -tsf-medical-record-stabilized-from-crit = Показатели восстановлены после критического состояния (t+{$time} с). +tsf-medical-record-stabilized-from-crit = Состояние отошло от критического (t+{$time} с). -tsf-health-examine-mob-critical = [color=red]Критическое состояние; показатели нестабильны.[/color] +tsf-health-examine-mob-critical = [color=red]На грани: дышит рывками, с трудом шевелится.[/color] -tsf-morphine-tolerance-hint = Конечности наливаются свинцом — доза едва берёт край с боли. +tsf-morphine-tolerance-hint = Конечности наливаются свинцом - доза едва берёт край с боли. diff --git a/Resources/Locale/ru-RU/_tsf/status_messages.ftl b/Resources/Locale/ru-RU/_tsf/status_messages.ftl index 9bd77feef86..51390be787a 100644 --- a/Resources/Locale/ru-RU/_tsf/status_messages.ftl +++ b/Resources/Locale/ru-RU/_tsf/status_messages.ftl @@ -91,7 +91,7 @@ tsf-status-near-death-positive-6 = Ладно... думать. tsf-status-near-death-positive-7 = Не двигаться. Движение — хуже. tsf-status-near-death-positive-8 = Дышать медленно. Паника не поможет. tsf-status-near-death-positive-9 = Всё кончено только когда кончено. -tsf-status-near-death-positive-10 = Боль — просто сигнал. Игнорировать. +tsf-status-near-death-positive-10 = Боль - просто сигнал. Игнорировать. tsf-status-near-death-positive-11 = Если конец... хоть быстро. tsf-status-near-death-positive-12 = Выживал и похуже. Наверное. tsf-status-near-death-positive-13 = Не так я это представлял. From aaca721897fb4c6836151133822a56bfd4db829c Mon Sep 17 00:00:00 2001 From: insvrg3ncy Date: Wed, 13 May 2026 14:46:39 +0300 Subject: [PATCH 3/4] i wanted this --- .../_TSF/AutonomousLobby/VoteManager.TSF.LobbyAutovote.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Content.Server/_TSF/AutonomousLobby/VoteManager.TSF.LobbyAutovote.cs b/Content.Server/_TSF/AutonomousLobby/VoteManager.TSF.LobbyAutovote.cs index dcf9e63946a..2b58a06f8d5 100644 --- a/Content.Server/_TSF/AutonomousLobby/VoteManager.TSF.LobbyAutovote.cs +++ b/Content.Server/_TSF/AutonomousLobby/VoteManager.TSF.LobbyAutovote.cs @@ -20,10 +20,7 @@ public sealed partial class VoteManager private static readonly string[] TSFLobbyVotePresetIds = { "Extended", - "Nukeops", - "Secret", - "Zombie", - "Revolutionary", + "Secret" }; private Dictionary TSFGetLobbyVotePresets() From 25627f367e0a3546b63b23e83cd457301906b608 Mon Sep 17 00:00:00 2001 From: insvrg3ncy Date: Wed, 13 May 2026 15:14:44 +0300 Subject: [PATCH 4/4] test fixes --- .../DamageEffects/TSFDamageEffectsSystem.cs | 64 ++++++++++++++++--- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/Content.Client/_TSF/DamageEffects/TSFDamageEffectsSystem.cs b/Content.Client/_TSF/DamageEffects/TSFDamageEffectsSystem.cs index bb53951e3e5..d2a8ca6fd33 100644 --- a/Content.Client/_TSF/DamageEffects/TSFDamageEffectsSystem.cs +++ b/Content.Client/_TSF/DamageEffects/TSFDamageEffectsSystem.cs @@ -167,6 +167,7 @@ private void OnTraumaticShockStateHandled(EntityUid uid, TraumaticShockComponent public override void Shutdown() { base.Shutdown(); + CleanupLocalPlayerDamageEffects(); if (_overlay != null) { _overlayManager.RemoveOverlay(_overlay); @@ -176,6 +177,7 @@ public override void Shutdown() private void OnLocalPlayerAttached(LocalPlayerAttachedEvent ev) { + CleanupLocalPlayerDamageEffects(); _overlayManager.AddOverlay(_overlay!); UpdateOverlayIntensity(ev.Entity); var result = _audio.PlayGlobal(DamageMusic, Filter.Local(), true); @@ -199,10 +201,33 @@ private void OnLocalPlayerAttached(LocalPlayerAttachedEvent ev) private void OnLocalPlayerDetached(LocalPlayerDetachedEvent ev) { - _overlayManager.RemoveOverlay(_overlay!); - _damageMusicStream = _audio.Stop(_damageMusicStream); - _painSoundStream = _audio.Stop(_painSoundStream); - _tinnitusStream = _audio.Stop(_tinnitusStream); + CleanupLocalPlayerDamageEffects(); + } + + private void CleanupLocalPlayerDamageEffects() + { + if (_overlay != null) + _overlayManager.RemoveOverlay(_overlay); + if (_damageMusicStream is {} dm) + { + _damageMusicStream = null; + if (Exists(dm)) + QueueDel(dm); + } + + if (_painSoundStream is {} ps) + { + _painSoundStream = null; + if (Exists(ps)) + QueueDel(ps); + } + + if (_tinnitusStream is {} ts) + { + _tinnitusStream = null; + if (Exists(ts)) + QueueDel(ts); + } if (_overlay != null) { _overlay.DamageStrength = 0f; @@ -223,6 +248,24 @@ private void OnLocalPlayerDetached(LocalPlayerDetachedEvent ev) TSFStatusMessageState.Message = null; } + private bool HasLiveLocalControlledEntity() + { + return _playerManager.LocalEntity is { } le && Exists(le); + } + + private void TryCleanupOrphanedLocalPlayerEffects() + { + if (HasLiveLocalControlledEntity()) + return; + CleanupLocalPlayerDamageEffects(); + } + + public override void Update(float frameTime) + { + TryCleanupOrphanedLocalPlayerEffects(); + base.Update(frameTime); + } + private bool ShouldTriggerTinnitus(EntityUid uid, DamageableComponent damageable) { var piercingDelta = FixedPoint2.Zero; @@ -274,11 +317,14 @@ private void OnThresholdChecked(ref MobThresholdChecked ev) public override void FrameUpdate(float frameTime) { base.FrameUpdate(frameTime); - var local = _playerManager.LocalEntity; - if (local == null || _overlay == null) + TryCleanupOrphanedLocalPlayerEffects(); + if (!HasLiveLocalControlledEntity()) + return; + + if (_overlay == null) return; - var uid = local.Value; + var uid = _playerManager.LocalEntity!.Value; if (TryComp(uid, out DamageableComponent? damageable)) { var totalDamage = _damageable.GetTotalDamage((uid, damageable)); @@ -350,13 +396,13 @@ public override void FrameUpdate(float frameTime) } _disorientationBurstTime = Math.Max(0f, _disorientationBurstTime - frameTime); - if (local != null && _disorientationBurstTime > 0f && TryComp(local, out MobStateComponent? mobState) && mobState.CurrentState == MobState.Alive) + if (_disorientationBurstTime > 0f && TryComp(uid, out MobStateComponent? mobState) && mobState.CurrentState == MobState.Alive) { var strength = _disorientationBurstTime / DisorientationBurstDuration; var kick = new Vector2( (_random.NextFloat() - 0.5f) * 2f * DisorientationKickMagnitude * strength, (_random.NextFloat() - 0.5f) * 2f * DisorientationKickMagnitude * strength); - _cameraRecoil.KickCamera(local.Value, kick); + _cameraRecoil.KickCamera(uid, kick); } }