mirror of
https://github.com/DeltaV-Station/Delta-v.git
synced 2026-09-29 23:57:29 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17e2dffdb2 | ||
|
|
22e287ec45 | ||
|
|
9a0a4abf5d | ||
|
|
0b685a52b6 | ||
|
|
52d3b54d2c |
+19
-10
@@ -1,25 +1,34 @@
|
|||||||
# Last match in file takes precedence.
|
# Last match in file takes precedence.
|
||||||
# See https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#example-of-a-codeowners-file
|
|
||||||
|
|
||||||
* @DeltaV-Station/maintainers
|
# C# code
|
||||||
|
/Content.*/ @DeltaV-Station/maintainers
|
||||||
|
|
||||||
|
# Any assets
|
||||||
|
/Resources/ @DeltaV-Station/maintainers
|
||||||
|
|
||||||
# Server config files
|
# Server config files
|
||||||
/Resources/ConfigPresets/ @DeltaV-Station/lead-maintainers
|
/Resources/ConfigPresets/ @Toby222
|
||||||
|
|
||||||
# Github workflows
|
|
||||||
/.github/ @DeltaV-Station/lead-maintainers
|
|
||||||
|
|
||||||
# Lobby art and music - automatically direction issues since its immediately visible to players
|
# Lobby art and music - automatically direction issues since its immediately visible to players
|
||||||
/Resources/Audio/Lobby/ @DeltaV-Station/direction @DeltaV-Station/maintainers
|
/Resources/Audio/Lobby/ @DeltaV-Station/direction
|
||||||
/Resources/Textures/LobbyScreens/ @DeltaV-Station/direction @DeltaV-Station/maintainers
|
/Resources/Textures/LobbyScreens/ @DeltaV-Station/direction
|
||||||
|
|
||||||
# Maps
|
# Maps
|
||||||
/Resources/Maps/ @DeltaV-Station/maptainers
|
/Resources/Maps/ @DeltaV-Station/maptainers
|
||||||
/Resources/Prototypes/Maps/ @DeltaV-Station/maptainers
|
/Resources/Prototypes/Maps/ @DeltaV-Station/maptainers
|
||||||
/Content.IntegrationTests/Tests/PostMapInitTest.cs @DeltaV-Station/maptainers @DeltaV-Station/maintainers
|
/Content.IntegrationTests/Tests/PostMapInitTest.cs @DeltaV-Station/maptainers
|
||||||
|
|
||||||
# Server rules
|
# Server rules
|
||||||
/Resources/ServerInfo/Guidebook/_DV/Rules/ @DeltaV-Station/head-administrators
|
/Resources/ServerInfo/Guidebook/_DV/Rules/ @DeltaV-Station/head-administrators
|
||||||
|
|
||||||
# Wiki
|
# Wiki
|
||||||
/.wiki/ @DeltaV-Station/direction
|
/.wiki/ @DeltaV-Station/direction
|
||||||
|
|
||||||
|
# Tools and scripts
|
||||||
|
/Tools/ @Toby222
|
||||||
|
|
||||||
|
# Workflows, codeowners, templates, etc.
|
||||||
|
/.github/ @Toby222
|
||||||
|
|
||||||
|
# Standalone files in the root repo
|
||||||
|
/* @Toby222
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ This just saves them the trouble. Note that AGPL or MIT licensing is only applic
|
|||||||
- [ ] I confirm that I am the creator of the code in this PR, and allow licensing it under the following license(s), or that the original author(s) has given me permission to do so:
|
- [ ] I confirm that I am the creator of the code in this PR, and allow licensing it under the following license(s), or that the original author(s) has given me permission to do so:
|
||||||
- [X] AGPL (https://github.com/DeltaV-Station/Delta-v/blob/master/LICENSE-AGPLv3.txt) <!-- This one is required to contribute to DeltaV -->
|
- [X] AGPL (https://github.com/DeltaV-Station/Delta-v/blob/master/LICENSE-AGPLv3.txt) <!-- This one is required to contribute to DeltaV -->
|
||||||
- [X] MIT (https://github.com/DeltaV-Station/Delta-v/blob/master/LICENSE-MIT.txt) <!-- Optional - A lot of other SS14 forks use MIT -->
|
- [X] MIT (https://github.com/DeltaV-Station/Delta-v/blob/master/LICENSE-MIT.txt) <!-- Optional - A lot of other SS14 forks use MIT -->
|
||||||
<!-- Feel free to add more licenses as you see fit -->
|
<!-- Feel free to add more licenses as you see fit -->
|
||||||
|
|
||||||
**Changelog**
|
**Changelog**
|
||||||
<!-- Add a Changelog entry to make players aware of new features or changes that could affect gameplay.
|
<!-- Add a Changelog entry to make players aware of new features or changes that could affect gameplay.
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd RobustToolbox/
|
cd RobustToolbox/
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
rm Robust.Shared.Tests/Networking/NetEncryptionDoSTest.cs # DeltaV - work around bug in the backport
|
|
||||||
|
|
||||||
- name: Setup .NET Core
|
- name: Setup .NET Core
|
||||||
uses: actions/setup-dotnet@v4.1.0
|
uses: actions/setup-dotnet@v4.1.0
|
||||||
@@ -46,23 +45,13 @@ jobs:
|
|||||||
run: dotnet build --configuration DebugOpt --no-restore /m
|
run: dotnet build --configuration DebugOpt --no-restore /m
|
||||||
|
|
||||||
- name: Run Content.Tests
|
- name: Run Content.Tests
|
||||||
shell: pwsh
|
run: dotnet test --no-build --configuration DebugOpt Content.Tests/Content.Tests.csproj -- NUnit.ConsoleOut=0
|
||||||
run: dotnet test --no-build --configuration DebugOpt Content.Tests/Content.Tests.csproj -- NUnit.ConsoleOut=0 NUnit.TestOutputXml="logs" NUnit.WorkDirectory="$(pwd)/test_results"
|
|
||||||
|
|
||||||
- name: Run Content.IntegrationTests
|
- name: Run Content.IntegrationTests
|
||||||
shell: pwsh
|
shell: pwsh
|
||||||
run: |
|
run: |
|
||||||
$env:DOTNET_gcServer=1
|
$env:DOTNET_gcServer=1
|
||||||
dotnet test --no-build --configuration DebugOpt Content.IntegrationTests/Content.IntegrationTests.csproj -- NUnit.ConsoleOut=0 NUnit.MapWarningTo=Failed NUnit.TestOutputXml="logs" NUnit.WorkDirectory="$(pwd)/test_results"
|
dotnet test --no-build --configuration DebugOpt Content.IntegrationTests/Content.IntegrationTests.csproj -- NUnit.ConsoleOut=0 NUnit.MapWarningTo=Failed
|
||||||
|
|
||||||
- name: Archive NUnit3 test results.
|
|
||||||
if: always()
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: nunit3-results-${{ matrix.os }}
|
|
||||||
path: test_results/*
|
|
||||||
retention-days: 7
|
|
||||||
compression-level: 9
|
|
||||||
ci-success:
|
ci-success:
|
||||||
name: Build & Test Debug
|
name: Build & Test Debug
|
||||||
needs:
|
needs:
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd RobustToolbox
|
cd RobustToolbox
|
||||||
git fetch --depth=1
|
git fetch --depth=1
|
||||||
rm Robust.Shared.Tests/Networking/NetEncryptionDoSTest.cs # DeltaV - work around bug in the backport
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
|
|||||||
@@ -48,11 +48,10 @@ jobs:
|
|||||||
cd RobustToolbox/
|
cd RobustToolbox/
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
|
|
||||||
# ubuntu-latest has .NET 10
|
- name: Setup .NET Core
|
||||||
# - name: Setup .NET Core
|
uses: actions/setup-dotnet@v4.1.0
|
||||||
# uses: actions/setup-dotnet@v4.1.0
|
with:
|
||||||
# with:
|
dotnet-version: 10.0.x
|
||||||
# dotnet-version: 10.0.x
|
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
@@ -61,13 +60,7 @@ jobs:
|
|||||||
run: dotnet build Content.Packaging --configuration Release --no-restore /m
|
run: dotnet build Content.Packaging --configuration Release --no-restore /m
|
||||||
|
|
||||||
- name: Package server
|
- name: Package server
|
||||||
run: dotnet run --project Content.Packaging server --log-build --platform win-x64 --platform win-arm64 --platform linux-x64 --platform linux-arm64 --platform osx-x64 --platform osx-arm64
|
run: dotnet run --project Content.Packaging server --platform win-x64 --platform win-arm64 --platform linux-x64 --platform linux-arm64 --platform osx-x64 --platform osx-arm64
|
||||||
|
|
||||||
- name: Package client
|
- name: Package client
|
||||||
run: dotnet run --project Content.Packaging client --log-build --no-wipe-release
|
run: dotnet run --project Content.Packaging client --no-wipe-release
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: binlogs
|
|
||||||
path: release/*.binlog
|
|
||||||
retention-days: 7
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd RobustToolbox/
|
cd RobustToolbox/
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
rm Robust.Shared.Tests/Networking/NetEncryptionDoSTest.cs # DeltaV - work around bug in the backport
|
|
||||||
- name: Setup .NET Core
|
- name: Setup .NET Core
|
||||||
uses: actions/setup-dotnet@v4.1.0
|
uses: actions/setup-dotnet@v4.1.0
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ Examples of Pets include, but are not limited to:
|
|||||||
:* hand-held "personal AI" devices
|
:* hand-held "personal AI" devices
|
||||||
|
|
||||||
== Synthetic ==
|
== Synthetic ==
|
||||||
Any Entity consisting primarily of non-organic matter, designed and/or constructed by NanoTrasen or its Employees for the purpose of performing tasks aboard a Space Station. Synthetics are bound by software limitations, typically referred to as Synthetic or Silicon Laws, and physically incorporated into their chassis. Any damage to a Synthetic- including un-authorized modification of their Laws- may leave the offender liable to charges of Sabotage.
|
Any Entity consisting primarily of non-organic matter, designed and/or constructed by NanoTrasen or its Employees for the purpose of performing tasks aboard a Space Station. Synthetics are bound by software limitations, typically referred to as Synthetic or Silicon Laws, and physically incorporated into their chassis. Any damage to a Synthetic- including un-authorized modification of their Laws- may leave the offender liable to charges of Sabotage. Irrevocable destruction of a Synthetic may leave the offender liable to the crime of Grand Sabotage.
|
||||||
Examples of Synthetics include, but are not limited to:
|
Examples of Synthetics include, but are not limited to:
|
||||||
:* Crew-constructed Cyborgs
|
:* Crew-constructed Cyborgs
|
||||||
:* The Station AI
|
:* The Station AI
|
||||||
@@ -86,7 +86,7 @@ Any individual requiring any above item in the course of their job, or for regul
|
|||||||
Should the holder commit crimes through the use of such authorized items, the authorizing party may be found guilty of Accessory to said crimes, in addition to Endangerment and Abuse of Power where applicable. The Commanding Officer is also authorized to supervise the approval and revocation of documentation as they see fit.
|
Should the holder commit crimes through the use of such authorized items, the authorizing party may be found guilty of Accessory to said crimes, in addition to Endangerment and Abuse of Power where applicable. The Commanding Officer is also authorized to supervise the approval and revocation of documentation as they see fit.
|
||||||
|
|
||||||
== Controlled Substances ==
|
== Controlled Substances ==
|
||||||
Any individual requiring a Controlled Substance in the course of their job, or for regular function, must request access to a prescription or special dispensation from the Chief Medical Officer. Medical personnel are also permitted to [[Standard Operating Procedure#Prescribing Medication|prescribe medication]] for chronic illnesses or mental health. Any such document must state the substance(s) being prescribed, the amount(s) where applicable, and the stamp and signature of the authorizing party.
|
Any individual requiring a Controlled Substance in the course of their job, or for regular function, must request access to a perscription or special dispensation from the Chief Medical Officer. The Psychologist is also permitted to grant prescriptions for psychoactive drugs. Any such document must state the substance(s) being prescribed, the amount(s) where applicable, and the stamp and signature of the authorizing party.
|
||||||
|
|
||||||
A list of such Substances follow:
|
A list of such Substances follow:
|
||||||
|
|
||||||
@@ -370,38 +370,6 @@ Given good medical reason and with documentation, the Chief Medical Officer of a
|
|||||||
|
|
||||||
In order for a medical evaluation to be considered lawfully applicable, the CMO and relevant head of department must both agree that the specified crewmate is unfit for duty in order to proceed with the demotion. In the case of the Commanding Officer, Central Command should be contacted as soon as possible.
|
In order for a medical evaluation to be considered lawfully applicable, the CMO and relevant head of department must both agree that the specified crewmate is unfit for duty in order to proceed with the demotion. In the case of the Commanding Officer, Central Command should be contacted as soon as possible.
|
||||||
|
|
||||||
==Prescribing Medication==
|
|
||||||
In the event that a patient requires stronger medication outside of medbay, Medical personnel have the ability to prescribe medicine to a patient. Prescriptions must be written on valid prescription paper, as well as signed and stamped with a valid medical personnel's stamp and signature. Any such document must state the substance(s) being prescribed as well as the amount(s) where applicable. The chief medical officer also has the right to revoke any prescription with valid medical reasoning. Prescriptions are not valid if they are both intended for and signed and stamped by the same person (e.g. You cannot prescribe something to yourself as a doctor).
|
|
||||||
|
|
||||||
=== Prescription Medicine ===
|
|
||||||
Prescriptions that are valid with any medical personnel's stamp and signature are as follows:
|
|
||||||
* diphenylmethylamine
|
|
||||||
* equilibrazine
|
|
||||||
* tranquinase
|
|
||||||
* neurozenium
|
|
||||||
* serenitol
|
|
||||||
* soretizone
|
|
||||||
|
|
||||||
Highly-addictive mental health prescriptions that are only valid with the chief medical officer's or psychologist's stamp and signature are as follows:
|
|
||||||
* blissifylovene
|
|
||||||
* happiness
|
|
||||||
|
|
||||||
Highly-addictive or potentially-harmful prescriptions that are only valid with the chief medical officer's stamp and signature are as follows:
|
|
||||||
* agonolexyne
|
|
||||||
* desoxyephedrine
|
|
||||||
* nocturine
|
|
||||||
|
|
||||||
=== Dangerous Chemical Authorizations ===
|
|
||||||
|
|
||||||
Other dangerous chemicals that may be authorized and given out ONLY with valid written permission with the chief medical officer's stamp are as follows:
|
|
||||||
* mindbreaker, heartbreaker, and mute toxins
|
|
||||||
* amatoxin and other dangerous poisons
|
|
||||||
* phlogiston, napalm, and chlorine trifluoride
|
|
||||||
* vestine and romerol
|
|
||||||
* Any other [[Standard Operating Procedure#Controlled Substances|controlled substances]] not listed here
|
|
||||||
|
|
||||||
The chief medical officer is also required to inform and/or forward authorization of any dangerous chemical to Security.
|
|
||||||
|
|
||||||
==Quarantine==
|
==Quarantine==
|
||||||
Medical staff are afforded the right to quarantine individuals that currently suffer from infectious or contagious diseases, and may confine them within pre-designated quarantine areas in the course of treatment, until the point that they are no longer infectious or harmful to the rest of the crew.
|
Medical staff are afforded the right to quarantine individuals that currently suffer from infectious or contagious diseases, and may confine them within pre-designated quarantine areas in the course of treatment, until the point that they are no longer infectious or harmful to the rest of the crew.
|
||||||
|
|
||||||
|
|||||||
+18
-78
@@ -73,88 +73,28 @@ If you are adding a lot of C# code, then take advantage of partial classes. Put
|
|||||||
|
|
||||||
Otherwise, **add comments on or around any changed lines.**
|
Otherwise, **add comments on or around any changed lines.**
|
||||||
|
|
||||||
### Single-Line Changes
|
A comment on a new imported namespace:
|
||||||
Format should look like this.
|
|
||||||
```cs
|
```cs
|
||||||
/* Importing Namespaces - Include optional comment if its not obvious what its being used for. */
|
using Content.Server.Psionics.Glimmer; // DeltaV
|
||||||
using Content.Server._DV.Psionics.Glimmer; // DeltaV
|
|
||||||
using Content.Shared.Damage.Systems; // DeltaV - Addition of HandHeldArmor
|
|
||||||
|
|
||||||
/* Changing an upstream line - Same line as the change */
|
|
||||||
if (!TryComp<EyeComponent>(ent, out var eye) || _disabled) // DeltaV - check if disabled
|
|
||||||
|
|
||||||
/* Adding - Either same line or above the line. */
|
|
||||||
EnsureComp<PotentialPsionicComponent>(entity); // Deltav - Psionics
|
|
||||||
|
|
||||||
/* "Deleting" - Don't actually delete, just comment out and say why. This only applies to upstream code. */
|
|
||||||
// args.StatusIcons.Add(_prototype.Index(component.Icon)); // DeltaV - commented out. status icon now added above
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> * Its pretty obvious in the example above that importing `Content.Server._DV.Psionics.Glimmer` means we'll be interacting with glimmer so putting `// DeltaV - Add Glimmer` is needlessly redundant.
|
A pair of comments enclosing a block of added code:
|
||||||
> * It's not as obvious what the `Content.Shared.Damage.Systems` namespace is used for, since its so broad, so adding a comment what feature is using it helps.
|
|
||||||
> * Actual code changes should almost always include the comment after ``// DeltaV`.
|
|
||||||
|
|
||||||
### Multi-Line Changes
|
|
||||||
Depending on how much you are editing, putting a comment on EACH line may be excessive, so if you have a larger block of code you are changing, denote it like so:
|
|
||||||
```cs
|
```cs
|
||||||
// BEGIN DeltaV - Remove innate radio and radios from pockets
|
private EntityUid Slice(...)
|
||||||
for (var i = 1; i <= 4; i++) // Arachnids have 4 pockets
|
|
||||||
{
|
{
|
||||||
if (_inventory.TryGetSlotEntity(target, $"pocket{i}", out var headset) && HasComp<HeadsetComponent>(headset))
|
...
|
||||||
_inventory.TryUnequip(target, $"pocket{i}", true, true);
|
|
||||||
|
_transform.SetLocalRotation(sliceUid, 0);
|
||||||
|
|
||||||
|
// DeltaV - start of deep frier stuff
|
||||||
|
var slicedEv = new FoodSlicedEvent(user, uid, sliceUid);
|
||||||
|
RaiseLocalEvent(uid, ref slicedEv);
|
||||||
|
// DeltaV - end of deep frier stuff
|
||||||
|
|
||||||
|
...
|
||||||
}
|
}
|
||||||
|
|
||||||
RemComp<ActiveRadioComponent>(target); // If the zombie has an innate radio, get rid of it.
|
|
||||||
// END DeltaV
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> * Denoting these with a BEGIN and END clearly shows they are block of code without having to read the entire comment. This makes it easier to tell when you're dealing with single-line comments versus a block with merging in conflicts.
|
|
||||||
> * Case and order of the first two words is less of a concern. `// DeltaV Begin` or `// Begin DeltaV` will work fine too.
|
|
||||||
> * Try to make your blocks as small as possible, but use your discretion.
|
|
||||||
> * If you deleting multiple lines, use line comments (``//``) if its a few lines but if its a larger block (like commenting out an entire function), it is preferable to use block comments (`/* */`).
|
|
||||||
|
|
||||||
#### Soft Exceptions to the Multi-Line "Rules"
|
|
||||||
Some multi-line changes can use a single-line comment in certain scenarios. But if you are UNSURE, just use `// BEGIN DeltaV` and `// END DeltaV` comments like the previous section does and it'll be fine.
|
|
||||||
|
|
||||||
I'll give some examples.
|
|
||||||
```cs
|
|
||||||
/* This change comments out 3 lines but only needs a single line comment because commenting out the if statement implies that its logic will be commented out too. */
|
|
||||||
// if (obj.WasModified<TraitPrototype>()) // DeltaV - Refreshed in TraitsTab
|
|
||||||
// {
|
|
||||||
// _profileEditor.RefreshTraits();
|
|
||||||
// }
|
|
||||||
|
|
||||||
/* Same principle here. This adds two lines but the if statement implies the next line so commenting both lines isn't really needed. */
|
|
||||||
if (_flight.IsFlying(entity.Owner)) // DeltaV - Harpy Flight
|
|
||||||
return true;
|
|
||||||
```
|
|
||||||
### New Methods or Component Variables
|
|
||||||
Sometimes, you'll need to implement a whole new method or component variable and instead of wrapping it in `// BEGIN DeltaV` and `// END DeltaV`, you can just denote that it's a DeltaV function in the summary block before the function. This denotes the WHOLE function as a DeltaV addition.
|
|
||||||
|
|
||||||
```cs
|
|
||||||
/* New Method Example */
|
|
||||||
/// <summary>
|
|
||||||
/// DeltaV - Handle revealing ninja if cloaked when attacked by a hitscan attack.
|
|
||||||
/// </summary>
|
|
||||||
private void OnNinjaAttacked(Entity<SpaceNinjaComponent> ent, ref DamageChangedEvent args)
|
|
||||||
{
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
/* New Component Variable Example */
|
|
||||||
/// <summary>
|
|
||||||
/// DeltaV - If disabled the action will not disable when no charges remain. Use if you want to handle no charges differently.
|
|
||||||
/// </summary>
|
|
||||||
[DataField]
|
|
||||||
public bool DisableWhenEmpty = true;
|
|
||||||
```
|
|
||||||
|
|
||||||
In short:
|
|
||||||
* Use `// BEGIN DeltaV` and `// END Delta` to denote a *block* of changes.
|
|
||||||
* Keep blocks as small as possible.
|
|
||||||
* Use `// DeltaV` on or before the line if its not a block of changes.
|
|
||||||
* Use exceptions when they make sense.
|
|
||||||
|
|
||||||
### Changing Upstream Localization Fluent .ftl files
|
### Changing Upstream Localization Fluent .ftl files
|
||||||
|
|
||||||
**Move all changed locale strings to a new DeltaV file** - use a `.ftl` file in the `_DV` folder. Comment out the old strings in the upstream file, and explain that they were moved.
|
**Move all changed locale strings to a new DeltaV file** - use a `.ftl` file in the `_DV` folder. Comment out the old strings in the upstream file, and explain that they were moved.
|
||||||
@@ -164,10 +104,10 @@ Example:
|
|||||||
Commented out old string in `Resources\Locale\en-US\xenoarchaeology\artifact-analyzer.ftl`
|
Commented out old string in `Resources\Locale\en-US\xenoarchaeology\artifact-analyzer.ftl`
|
||||||
```
|
```
|
||||||
# DeltaV - moved to _DV file
|
# DeltaV - moved to _DV file
|
||||||
# analysis-console-info-effect-value = [font="Monospace" size=11][color=gray]{ $state ->
|
#analysis-console-info-effect-value = [font="Monospace" size=11][color=gray]{ $state ->
|
||||||
# [true] {$info}
|
# [true] {$info}
|
||||||
# *[false] Unlock nodes to gain info
|
# *[false] Unlock nodes to gain info
|
||||||
# }[/color][/font]
|
#}[/color][/font]
|
||||||
```
|
```
|
||||||
|
|
||||||
The new version of the string in `Resources\Locale\en-US\_DV\xenoarchaeology\artifact-analyzer.ftl`
|
The new version of the string in `Resources\Locale\en-US\_DV\xenoarchaeology\artifact-analyzer.ftl`
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
@@ -45,7 +44,7 @@ public class ComponentQueryBenchmark
|
|||||||
ProgramShared.PathOffset = "../../../../";
|
ProgramShared.PathOffset = "../../../../";
|
||||||
PoolManager.Startup(typeof(QueryBenchSystem).Assembly);
|
PoolManager.Startup(typeof(QueryBenchSystem).Assembly);
|
||||||
|
|
||||||
_pair = PoolManager.GetServerClient(testContext: new ExternalTestContext("Benchmark", StreamWriter.Null)).GetAwaiter().GetResult();
|
_pair = PoolManager.GetServerClient().GetAwaiter().GetResult();
|
||||||
_entMan = _pair.Server.ResolveDependency<IEntityManager>();
|
_entMan = _pair.Server.ResolveDependency<IEntityManager>();
|
||||||
|
|
||||||
_itemQuery = _entMan.GetEntityQuery<ItemComponent>();
|
_itemQuery = _entMan.GetEntityQuery<ItemComponent>();
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<IsTestingPlatformApplication>false</IsTestingPlatformApplication>
|
<IsTestingPlatformApplication>false</IsTestingPlatformApplication>
|
||||||
<Nullable>disable</Nullable>
|
<Nullable>disable</Nullable>
|
||||||
<DefineConstants>$(DefineConstants);ALLOW_BAD_PRACTICES</DefineConstants>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="../MSBuild/Content.props" />
|
<Import Project="../MSBuild/Content.props" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Diagnosers;
|
||||||
using Content.IntegrationTests;
|
using Content.IntegrationTests;
|
||||||
using Content.IntegrationTests.Pair;
|
using Content.IntegrationTests.Pair;
|
||||||
|
using Content.Server.Atmos.Components;
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
using Content.Shared.Atmos.Components;
|
using Content.Shared.Atmos.Components;
|
||||||
using Content.Shared.Atmos.EntitySystems;
|
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Robust.Shared;
|
using Robust.Shared;
|
||||||
using Robust.Shared.Analyzers;
|
using Robust.Shared.Analyzers;
|
||||||
@@ -69,7 +69,7 @@ public class DeltaPressureBenchmark
|
|||||||
{
|
{
|
||||||
ProgramShared.PathOffset = "../../../../";
|
ProgramShared.PathOffset = "../../../../";
|
||||||
PoolManager.Startup();
|
PoolManager.Startup();
|
||||||
_pair = await PoolManager.GetServerClient(testContext: new ExternalTestContext("Benchmark", StreamWriter.Null));
|
_pair = await PoolManager.GetServerClient();
|
||||||
var server = _pair.Server;
|
var server = _pair.Server;
|
||||||
|
|
||||||
var mapdata = await _pair.CreateTestMap();
|
var mapdata = await _pair.CreateTestMap();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using Content.IntegrationTests;
|
using Content.IntegrationTests;
|
||||||
@@ -70,7 +69,7 @@ public class DestructibleBenchmark
|
|||||||
{
|
{
|
||||||
ProgramShared.PathOffset = "../../../../";
|
ProgramShared.PathOffset = "../../../../";
|
||||||
PoolManager.Startup();
|
PoolManager.Startup();
|
||||||
_pair = await PoolManager.GetServerClient(testContext: new ExternalTestContext("Benchmark", StreamWriter.Null));
|
_pair = await PoolManager.GetServerClient();
|
||||||
var server = _pair.Server;
|
var server = _pair.Server;
|
||||||
|
|
||||||
_entMan = server.ResolveDependency<IEntityManager>();
|
_entMan = server.ResolveDependency<IEntityManager>();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using Content.IntegrationTests;
|
using Content.IntegrationTests;
|
||||||
@@ -61,7 +60,7 @@ public class DeviceNetworkingBenchmark
|
|||||||
{
|
{
|
||||||
ProgramShared.PathOffset = "../../../../";
|
ProgramShared.PathOffset = "../../../../";
|
||||||
PoolManager.Startup(typeof(DeviceNetworkingBenchmark).Assembly);
|
PoolManager.Startup(typeof(DeviceNetworkingBenchmark).Assembly);
|
||||||
_pair = await PoolManager.GetServerClient(testContext: new ExternalTestContext("Benchmark", StreamWriter.Null));
|
_pair = await PoolManager.GetServerClient();
|
||||||
var server = _pair.Server;
|
var server = _pair.Server;
|
||||||
|
|
||||||
await server.WaitPost(() =>
|
await server.WaitPost(() =>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using Content.IntegrationTests;
|
using Content.IntegrationTests;
|
||||||
@@ -52,7 +51,7 @@ public class GasReactionBenchmark
|
|||||||
{
|
{
|
||||||
ProgramShared.PathOffset = "../../../../";
|
ProgramShared.PathOffset = "../../../../";
|
||||||
PoolManager.Startup();
|
PoolManager.Startup();
|
||||||
_pair = await PoolManager.GetServerClient(testContext: new ExternalTestContext("Benchmark", StreamWriter.Null));
|
_pair = await PoolManager.GetServerClient();
|
||||||
var server = _pair.Server;
|
var server = _pair.Server;
|
||||||
|
|
||||||
// Create test map and grid
|
// Create test map and grid
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.IO;
|
using System.Threading.Tasks;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using Content.IntegrationTests;
|
using Content.IntegrationTests;
|
||||||
using Content.IntegrationTests.Pair;
|
using Content.IntegrationTests.Pair;
|
||||||
@@ -28,7 +27,7 @@ public class HeatCapacityBenchmark
|
|||||||
{
|
{
|
||||||
ProgramShared.PathOffset = "../../../../";
|
ProgramShared.PathOffset = "../../../../";
|
||||||
PoolManager.Startup();
|
PoolManager.Startup();
|
||||||
_pair = await PoolManager.GetServerClient(testContext: new ExternalTestContext("Benchmark", StreamWriter.Null));
|
_pair = await PoolManager.GetServerClient();
|
||||||
await _pair.Connect();
|
await _pair.Connect();
|
||||||
_cEntMan = _pair.Client.ResolveDependency<IEntityManager>();
|
_cEntMan = _pair.Client.ResolveDependency<IEntityManager>();
|
||||||
_sEntMan = _pair.Server.ResolveDependency<IEntityManager>();
|
_sEntMan = _pair.Server.ResolveDependency<IEntityManager>();
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
@@ -30,7 +29,7 @@ public class MapLoadBenchmark
|
|||||||
ProgramShared.PathOffset = "../../../../";
|
ProgramShared.PathOffset = "../../../../";
|
||||||
PoolManager.Startup();
|
PoolManager.Startup();
|
||||||
|
|
||||||
_pair = PoolManager.GetServerClient(testContext: new ExternalTestContext("Benchmark", StreamWriter.Null)).GetAwaiter().GetResult();
|
_pair = PoolManager.GetServerClient().GetAwaiter().GetResult();
|
||||||
var server = _pair.Server;
|
var server = _pair.Server;
|
||||||
|
|
||||||
Paths = server.ResolveDependency<IPrototypeManager>()
|
Paths = server.ResolveDependency<IPrototypeManager>()
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
@@ -51,7 +50,7 @@ public class PvsBenchmark
|
|||||||
#endif
|
#endif
|
||||||
PoolManager.Startup();
|
PoolManager.Startup();
|
||||||
|
|
||||||
_pair = PoolManager.GetServerClient(testContext: new ExternalTestContext("Benchmark", StreamWriter.Null)).GetAwaiter().GetResult();
|
_pair = PoolManager.GetServerClient().GetAwaiter().GetResult();
|
||||||
_entMan = _pair.Server.ResolveDependency<IEntityManager>();
|
_entMan = _pair.Server.ResolveDependency<IEntityManager>();
|
||||||
_pair.Server.CfgMan.SetCVar(CVars.NetPVS, true);
|
_pair.Server.CfgMan.SetCVar(CVars.NetPVS, true);
|
||||||
_pair.Server.CfgMan.SetCVar(CVars.ThreadParallelCount, 0);
|
_pair.Server.CfgMan.SetCVar(CVars.ThreadParallelCount, 0);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#nullable enable
|
#nullable enable
|
||||||
using System.IO;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
@@ -22,7 +21,7 @@ public class RaiseEventBenchmark
|
|||||||
{
|
{
|
||||||
ProgramShared.PathOffset = "../../../../";
|
ProgramShared.PathOffset = "../../../../";
|
||||||
PoolManager.Startup(typeof(BenchSystem).Assembly);
|
PoolManager.Startup(typeof(BenchSystem).Assembly);
|
||||||
_pair = PoolManager.GetServerClient(testContext: new ExternalTestContext("Benchmark", StreamWriter.Null)).GetAwaiter().GetResult();
|
_pair = PoolManager.GetServerClient().GetAwaiter().GetResult();
|
||||||
var entMan = _pair.Server.EntMan;
|
var entMan = _pair.Server.EntMan;
|
||||||
var fact = _pair.Server.ResolveDependency<IComponentFactory>();
|
var fact = _pair.Server.ResolveDependency<IComponentFactory>();
|
||||||
var bus = (EntityEventBus)entMan.EventBus;
|
var bus = (EntityEventBus)entMan.EventBus;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.IO;
|
using System.Threading.Tasks;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using Content.IntegrationTests;
|
using Content.IntegrationTests;
|
||||||
using Content.IntegrationTests.Pair;
|
using Content.IntegrationTests.Pair;
|
||||||
@@ -37,7 +36,7 @@ public class SpawnEquipDeleteBenchmark
|
|||||||
{
|
{
|
||||||
ProgramShared.PathOffset = "../../../../";
|
ProgramShared.PathOffset = "../../../../";
|
||||||
PoolManager.Startup();
|
PoolManager.Startup();
|
||||||
_pair = await PoolManager.GetServerClient(testContext: new ExternalTestContext("Benchmark", StreamWriter.Null));
|
_pair = await PoolManager.GetServerClient();
|
||||||
var server = _pair.Server;
|
var server = _pair.Server;
|
||||||
|
|
||||||
var mapData = await _pair.CreateTestMap();
|
var mapData = await _pair.CreateTestMap();
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
using Content.Client.Overlays;
|
|
||||||
using Content.Shared.Access.Systems;
|
|
||||||
using Content.Shared.StatusIcon;
|
|
||||||
using Content.Shared.StatusIcon.Components;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Client.Access.Systems;
|
|
||||||
|
|
||||||
public sealed class JobStatusSystem : SharedJobStatusSystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly ShowJobIconsSystem _showJobIcons = default!;
|
|
||||||
[Dependency] private readonly ShowCrewIconsSystem _showCrewIcons = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
|
||||||
|
|
||||||
private static readonly ProtoId<SecurityIconPrototype> CrewBorderIcon = "CrewBorderIcon";
|
|
||||||
private static readonly ProtoId<SecurityIconPrototype> CrewUncertainBorderIcon = "CrewUncertainBorderIcon";
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<JobStatusComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
// show the status icons if the player has the correponding HUDs
|
|
||||||
private void OnGetStatusIconsEvent(Entity<JobStatusComponent> ent, ref GetStatusIconsEvent ev)
|
|
||||||
{
|
|
||||||
if (_showJobIcons.IsActive && ent.Comp.JobStatusIcon != null)
|
|
||||||
ev.StatusIcons.Add(_prototype.Index(ent.Comp.JobStatusIcon));
|
|
||||||
|
|
||||||
if (_showCrewIcons.IsActive)
|
|
||||||
{
|
|
||||||
if (_showCrewIcons.UncertainCrewBorder)
|
|
||||||
ev.StatusIcons.Add(_prototype.Index(CrewUncertainBorderIcon));
|
|
||||||
else if (ent.Comp.IsCrew)
|
|
||||||
ev.StatusIcons.Add(_prototype.Index(CrewBorderIcon));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,9 +2,11 @@ using System.Linq; // DeltaV
|
|||||||
using Content.Shared.Access;
|
using Content.Shared.Access;
|
||||||
using Content.Shared.Access.Components;
|
using Content.Shared.Access.Components;
|
||||||
using Content.Shared.Access.Systems;
|
using Content.Shared.Access.Systems;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.Containers.ItemSlots;
|
using Content.Shared.Containers.ItemSlots;
|
||||||
using Content.Shared.CrewManifest;
|
using Content.Shared.CrewManifest;
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using static Content.Shared.Access.Components.IdCardConsoleComponent;
|
using static Content.Shared.Access.Components.IdCardConsoleComponent;
|
||||||
|
|
||||||
@@ -13,13 +15,21 @@ namespace Content.Client.Access.UI
|
|||||||
public sealed class IdCardConsoleBoundUserInterface : BoundUserInterface
|
public sealed class IdCardConsoleBoundUserInterface : BoundUserInterface
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
|
||||||
private readonly SharedIdCardConsoleSystem _idCardConsoleSystem = default!;
|
private readonly SharedIdCardConsoleSystem _idCardConsoleSystem = default!;
|
||||||
|
|
||||||
private IdCardConsoleWindow? _window;
|
private IdCardConsoleWindow? _window;
|
||||||
|
|
||||||
|
// CCVar.
|
||||||
|
private int _maxNameLength;
|
||||||
|
private int _maxIdJobLength;
|
||||||
|
|
||||||
public IdCardConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
public IdCardConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||||
{
|
{
|
||||||
_idCardConsoleSystem = EntMan.System<SharedIdCardConsoleSystem>();
|
_idCardConsoleSystem = EntMan.System<SharedIdCardConsoleSystem>();
|
||||||
|
|
||||||
|
_maxNameLength =_cfgManager.GetCVar(CCVars.MaxNameLength);
|
||||||
|
_maxIdJobLength = _cfgManager.GetCVar(CCVars.MaxIdJobLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Open()
|
protected override void Open()
|
||||||
@@ -69,6 +79,12 @@ namespace Content.Client.Access.UI
|
|||||||
|
|
||||||
public void SubmitData(string newFullName, string newJobTitle, List<ProtoId<AccessLevelPrototype>> newAccessList, ProtoId<JobPrototype> newJobPrototype)
|
public void SubmitData(string newFullName, string newJobTitle, List<ProtoId<AccessLevelPrototype>> newAccessList, ProtoId<JobPrototype> newJobPrototype)
|
||||||
{
|
{
|
||||||
|
if (newFullName.Length > _maxNameLength)
|
||||||
|
newFullName = newFullName[.._maxNameLength];
|
||||||
|
|
||||||
|
if (newJobTitle.Length > _maxIdJobLength)
|
||||||
|
newJobTitle = newJobTitle[.._maxIdJobLength];
|
||||||
|
|
||||||
SendMessage(new WriteToTargetIdMessage(
|
SendMessage(new WriteToTargetIdMessage(
|
||||||
newFullName,
|
newFullName,
|
||||||
newJobTitle,
|
newJobTitle,
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ namespace Content.Client.Access.UI
|
|||||||
|
|
||||||
private readonly IdCardConsoleBoundUserInterface _owner;
|
private readonly IdCardConsoleBoundUserInterface _owner;
|
||||||
|
|
||||||
|
// CCVar.
|
||||||
|
private int _maxNameLength;
|
||||||
|
private int _maxIdJobLength;
|
||||||
|
|
||||||
private AccessLevelControl _accessButtons = new();
|
private AccessLevelControl _accessButtons = new();
|
||||||
private readonly List<string> _jobPrototypeIds = new();
|
private readonly List<string> _jobPrototypeIds = new();
|
||||||
|
|
||||||
@@ -42,8 +46,11 @@ namespace Content.Client.Access.UI
|
|||||||
|
|
||||||
_owner = owner;
|
_owner = owner;
|
||||||
|
|
||||||
|
_maxNameLength = _cfgManager.GetCVar(CCVars.MaxNameLength);
|
||||||
|
_maxIdJobLength = _cfgManager.GetCVar(CCVars.MaxIdJobLength);
|
||||||
|
|
||||||
FullNameLineEdit.OnTextEntered += _ => SubmitData();
|
FullNameLineEdit.OnTextEntered += _ => SubmitData();
|
||||||
FullNameLineEdit.IsValid = s => s.Length <= _cfgManager.GetCVar(CCVars.MaxNameLength);
|
FullNameLineEdit.IsValid = s => s.Length <= _maxNameLength;
|
||||||
FullNameLineEdit.OnTextChanged += _ =>
|
FullNameLineEdit.OnTextChanged += _ =>
|
||||||
{
|
{
|
||||||
FullNameSaveButton.Disabled = FullNameSaveButton.Text == _lastFullName;
|
FullNameSaveButton.Disabled = FullNameSaveButton.Text == _lastFullName;
|
||||||
@@ -51,7 +58,7 @@ namespace Content.Client.Access.UI
|
|||||||
FullNameSaveButton.OnPressed += _ => SubmitData();
|
FullNameSaveButton.OnPressed += _ => SubmitData();
|
||||||
|
|
||||||
JobTitleLineEdit.OnTextEntered += _ => SubmitData();
|
JobTitleLineEdit.OnTextEntered += _ => SubmitData();
|
||||||
JobTitleLineEdit.IsValid = s => s.Length <= _cfgManager.GetCVar(CCVars.MaxIdJobLength);
|
JobTitleLineEdit.IsValid = s => s.Length <= _maxIdJobLength;
|
||||||
JobTitleLineEdit.OnTextChanged += _ =>
|
JobTitleLineEdit.OnTextChanged += _ =>
|
||||||
{
|
{
|
||||||
JobTitleSaveButton.Disabled = JobTitleLineEdit.Text == _lastJobTitle;
|
JobTitleSaveButton.Disabled = JobTitleLineEdit.Text == _lastJobTitle;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Linq;
|
using System.Numerics;
|
||||||
using System.Numerics;
|
|
||||||
using Content.Client.Administration.UI.BanList.Bans;
|
using Content.Client.Administration.UI.BanList.Bans;
|
||||||
using Content.Client.Administration.UI.BanList.RoleBans;
|
using Content.Client.Administration.UI.BanList.RoleBans;
|
||||||
using Content.Client.Eui;
|
using Content.Client.Eui;
|
||||||
@@ -74,7 +73,7 @@ public sealed class BanListEui : BaseEui
|
|||||||
return date.ToString("MM/dd/yyyy h:mm tt");
|
return date.ToString("MM/dd/yyyy h:mm tt");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetData<T>(IBanListLine<T> line, SharedBan ban) where T : SharedBan
|
public static void SetData<T>(IBanListLine<T> line, SharedServerBan ban) where T : SharedServerBan
|
||||||
{
|
{
|
||||||
line.Reason.Text = ban.Reason;
|
line.Reason.Text = ban.Reason;
|
||||||
line.BanTime.Text = FormatDate(ban.BanTime);
|
line.BanTime.Text = FormatDate(ban.BanTime);
|
||||||
@@ -95,20 +94,20 @@ public sealed class BanListEui : BaseEui
|
|||||||
line.BanningAdmin.Text = ban.BanningAdminName;
|
line.BanningAdmin.Text = ban.BanningAdminName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnLineIdsClicked<T>(IBanListLine<T> line) where T : SharedBan
|
private void OnLineIdsClicked<T>(IBanListLine<T> line) where T : SharedServerBan
|
||||||
{
|
{
|
||||||
_popup?.Close();
|
_popup?.Close();
|
||||||
_popup = null;
|
_popup = null;
|
||||||
|
|
||||||
var ban = line.Ban;
|
var ban = line.Ban;
|
||||||
var id = ban.Id == null ? string.Empty : Loc.GetString("ban-list-id", ("id", ban.Id.Value));
|
var id = ban.Id == null ? string.Empty : Loc.GetString("ban-list-id", ("id", ban.Id.Value));
|
||||||
var ip = ban.Addresses.Length == 0
|
var ip = ban.Address == null
|
||||||
? string.Empty
|
? string.Empty
|
||||||
: Loc.GetString("ban-list-ip", ("ip", string.Join(',', ban.Addresses.Select(a => a.address))));
|
: Loc.GetString("ban-list-ip", ("ip", ban.Address.Value.address));
|
||||||
var hwid = ban.HWIds.Length == 0 ? string.Empty : Loc.GetString("ban-list-hwid", ("hwid", string.Join(',', ban.HWIds)));
|
var hwid = ban.HWId == null ? string.Empty : Loc.GetString("ban-list-hwid", ("hwid", ban.HWId));
|
||||||
var guid = ban.UserIds.Length == 0
|
var guid = ban.UserId == null
|
||||||
? string.Empty
|
? string.Empty
|
||||||
: Loc.GetString("ban-list-guid", ("guid", string.Join(',', ban.UserIds)));
|
: Loc.GetString("ban-list-guid", ("guid", ban.UserId.Value.ToString()));
|
||||||
|
|
||||||
_popup = new BanListIdsPopup(id, ip, hwid, guid);
|
_popup = new BanListIdsPopup(id, ip, hwid, guid);
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public sealed partial class BanListControl : Control
|
|||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetBans(List<SharedBan> bans)
|
public void SetBans(List<SharedServerBan> bans)
|
||||||
{
|
{
|
||||||
for (var i = Bans.ChildCount - 1; i >= 1; i--)
|
for (var i = Bans.ChildCount - 1; i >= 1; i--)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ using static Robust.Client.UserInterface.Controls.BaseButton;
|
|||||||
namespace Content.Client.Administration.UI.BanList.Bans;
|
namespace Content.Client.Administration.UI.BanList.Bans;
|
||||||
|
|
||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class BanListLine : BoxContainer, IBanListLine<SharedBan>
|
public sealed partial class BanListLine : BoxContainer, IBanListLine<SharedServerBan>
|
||||||
{
|
{
|
||||||
public SharedBan Ban { get; }
|
public SharedServerBan Ban { get; }
|
||||||
|
|
||||||
public event Action<BanListLine>? IdsClicked;
|
public event Action<BanListLine>? IdsClicked;
|
||||||
|
|
||||||
public BanListLine(SharedBan ban)
|
public BanListLine(SharedServerBan ban)
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using Robust.Client.UserInterface.Controls;
|
|||||||
|
|
||||||
namespace Content.Client.Administration.UI.BanList;
|
namespace Content.Client.Administration.UI.BanList;
|
||||||
|
|
||||||
public interface IBanListLine<T> where T : SharedBan
|
public interface IBanListLine<T> where T : SharedServerBan
|
||||||
{
|
{
|
||||||
T Ban { get; }
|
T Ban { get; }
|
||||||
Label Reason { get; }
|
Label Reason { get; }
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public sealed partial class RoleBanListControl : Control
|
|||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetRoleBans(List<SharedBan> bans)
|
public void SetRoleBans(List<SharedServerRoleBan> bans)
|
||||||
{
|
{
|
||||||
for (var i = RoleBans.ChildCount - 1; i >= 1; i--)
|
for (var i = RoleBans.ChildCount - 1; i >= 1; i--)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ using static Robust.Client.UserInterface.Controls.BaseButton;
|
|||||||
namespace Content.Client.Administration.UI.BanList.RoleBans;
|
namespace Content.Client.Administration.UI.BanList.RoleBans;
|
||||||
|
|
||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class RoleBanListLine : BoxContainer, IBanListLine<SharedBan>
|
public sealed partial class RoleBanListLine : BoxContainer, IBanListLine<SharedServerRoleBan>
|
||||||
{
|
{
|
||||||
public SharedBan Ban { get; }
|
public SharedServerRoleBan Ban { get; }
|
||||||
|
|
||||||
public event Action<RoleBanListLine>? IdsClicked;
|
public event Action<RoleBanListLine>? IdsClicked;
|
||||||
|
|
||||||
public RoleBanListLine(SharedBan ban)
|
public RoleBanListLine(SharedServerRoleBan ban)
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ public sealed partial class RoleBanListLine : BoxContainer, IBanListLine<SharedB
|
|||||||
IdsHidden.OnPressed += IdsPressed;
|
IdsHidden.OnPressed += IdsPressed;
|
||||||
|
|
||||||
BanListEui.SetData(this, ban);
|
BanListEui.SetData(this, ban);
|
||||||
Role.Text = string.Join(", ", ban.Roles ?? []);
|
Role.Text = ban.Role;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void IdsPressed(ButtonEventArgs buttonEventArgs)
|
private void IdsPressed(ButtonEventArgs buttonEventArgs)
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public sealed partial class AdminNotesLine : BoxContainer
|
|||||||
|
|
||||||
TimeLabel.Text = Note.CreatedAt.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss");
|
TimeLabel.Text = Note.CreatedAt.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss");
|
||||||
ServerLabel.Text = Note.ServerName ?? "Unknown";
|
ServerLabel.Text = Note.ServerName ?? "Unknown";
|
||||||
RoundLabel.Text = Note.Rounds.Length == 0 ? "Unknown round" : "Round " + string.Join(',', Note.Rounds);
|
RoundLabel.Text = Note.Round == null ? "Unknown round" : "Round " + Note.Round;
|
||||||
AdminLabel.Text = Note.CreatedByName;
|
AdminLabel.Text = Note.CreatedByName;
|
||||||
PlaytimeLabel.Text = $"{Note.PlaytimeAtNote.TotalHours: 0.0}h";
|
PlaytimeLabel.Text = $"{Note.PlaytimeAtNote.TotalHours: 0.0}h";
|
||||||
|
|
||||||
@@ -143,12 +143,7 @@ public sealed partial class AdminNotesLine : BoxContainer
|
|||||||
|
|
||||||
private string FormatRoleBanMessage()
|
private string FormatRoleBanMessage()
|
||||||
{
|
{
|
||||||
var rolesText = string.Join(
|
var banMessage = new StringBuilder($"{Loc.GetString("admin-notes-banned-from")} {string.Join(", ", Note.BannedRoles ?? new[] { "unknown" })} ");
|
||||||
", ",
|
|
||||||
// Explicit cast here to avoid sandbox violation.
|
|
||||||
(IEnumerable<BanRoleDef>?)Note.BannedRoles ?? [new BanRoleDef("what", "You should not be seeing this")]);
|
|
||||||
|
|
||||||
var banMessage = new StringBuilder($"{Loc.GetString("admin-notes-banned-from")} {rolesText} ");
|
|
||||||
return FormatBanMessageCommon(banMessage);
|
return FormatBanMessageCommon(banMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ public sealed partial class AdminNotesLinePopup : Popup
|
|||||||
IdLabel.Text = Loc.GetString("admin-notes-id", ("id", note.Id));
|
IdLabel.Text = Loc.GetString("admin-notes-id", ("id", note.Id));
|
||||||
TypeLabel.Text = Loc.GetString("admin-notes-type", ("type", note.NoteType));
|
TypeLabel.Text = Loc.GetString("admin-notes-type", ("type", note.NoteType));
|
||||||
SeverityLabel.Text = Loc.GetString("admin-notes-severity", ("severity", note.NoteSeverity ?? NoteSeverity.None));
|
SeverityLabel.Text = Loc.GetString("admin-notes-severity", ("severity", note.NoteSeverity ?? NoteSeverity.None));
|
||||||
RoundIdLabel.Text = note.Rounds.Length == 0
|
RoundIdLabel.Text = note.Round == null
|
||||||
? Loc.GetString("admin-notes-round-id-unknown")
|
? Loc.GetString("admin-notes-round-id-unknown")
|
||||||
: Loc.GetString("admin-notes-round-id", ("id", string.Join(',', note.Rounds)));
|
: Loc.GetString("admin-notes-round-id", ("id", note.Round));
|
||||||
CreatedByLabel.Text = Loc.GetString("admin-notes-created-by", ("author", note.CreatedByName));
|
CreatedByLabel.Text = Loc.GetString("admin-notes-created-by", ("author", note.CreatedByName));
|
||||||
CreatedAtLabel.Text = Loc.GetString("admin-notes-created-at", ("date", note.CreatedAt.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")));
|
CreatedAtLabel.Text = Loc.GetString("admin-notes-created-at", ("date", note.CreatedAt.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")));
|
||||||
EditedByLabel.Text = Loc.GetString("admin-notes-last-edited-by", ("author", note.EditedByName));
|
EditedByLabel.Text = Loc.GetString("admin-notes-last-edited-by", ("author", note.EditedByName));
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ public sealed class ClientInnerBodyAnomalySystem : SharedInnerBodyAnomalySystem
|
|||||||
|
|
||||||
var index = _sprite.LayerMapReserve((ent.Owner, sprite), ent.Comp.LayerMap);
|
var index = _sprite.LayerMapReserve((ent.Owner, sprite), ent.Comp.LayerMap);
|
||||||
|
|
||||||
if (TryComp<HumanoidProfileComponent>(ent, out var humanoid) &&
|
if (TryComp<HumanoidAppearanceComponent>(ent, out var humanoidAppearance) &&
|
||||||
ent.Comp.SpeciesSprites.TryGetValue(humanoid.Species, out var speciesSprite))
|
ent.Comp.SpeciesSprites.TryGetValue(humanoidAppearance.Species, out var speciesSprite))
|
||||||
{
|
{
|
||||||
_sprite.LayerSetSprite((ent.Owner, sprite), index, speciesSprite);
|
_sprite.LayerSetSprite((ent.Owner, sprite), index, speciesSprite);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
Title="{Loc 'anomaly-generator-ui-title'}"
|
Title="{Loc 'anomaly-generator-ui-title'}"
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<!--Sprite View-->
|
<!--Sprite View-->
|
||||||
<PanelContainer Margin="12 0 0 0"
|
<PanelContainer Margin="12 0 0 0"
|
||||||
StyleClasses="BackgroundPanelDark"
|
StyleClasses="Inset"
|
||||||
VerticalAlignment="Center">
|
VerticalAlignment="Center">
|
||||||
<SpriteView Name="EntityView"
|
<SpriteView Name="EntityView"
|
||||||
SetSize="96 96"
|
SetSize="96 96"
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using Content.Shared.Atmos.Components;
|
||||||
|
|
||||||
|
namespace Content.Client.Atmos.Components;
|
||||||
|
|
||||||
|
[RegisterComponent]
|
||||||
|
public sealed partial class MapAtmosphereComponent : SharedMapAtmosphereComponent
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using Content.Client.Stylesheets;
|
using Content.Client.Stylesheets;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Atmos.Components;
|
using Content.Shared.Atmos.Components;
|
||||||
using Content.Shared.Atmos.EntitySystems;
|
|
||||||
using Content.Shared.Atmos.Monitor;
|
using Content.Shared.Atmos.Monitor;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Temperature;
|
using Content.Shared.Temperature;
|
||||||
@@ -23,7 +22,6 @@ public sealed partial class AtmosAlarmEntryContainer : BoxContainer
|
|||||||
|
|
||||||
private readonly IEntityManager _entManager;
|
private readonly IEntityManager _entManager;
|
||||||
private readonly IResourceCache _cache;
|
private readonly IResourceCache _cache;
|
||||||
private readonly SharedAtmosphereSystem _atmosphere;
|
|
||||||
|
|
||||||
private Dictionary<AtmosAlarmType, string> _alarmStrings = new Dictionary<AtmosAlarmType, string>()
|
private Dictionary<AtmosAlarmType, string> _alarmStrings = new Dictionary<AtmosAlarmType, string>()
|
||||||
{
|
{
|
||||||
@@ -39,7 +37,6 @@ public sealed partial class AtmosAlarmEntryContainer : BoxContainer
|
|||||||
|
|
||||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
_entManager = IoCManager.Resolve<IEntityManager>();
|
||||||
_cache = IoCManager.Resolve<IResourceCache>();
|
_cache = IoCManager.Resolve<IResourceCache>();
|
||||||
_atmosphere = _entManager.System<SharedAtmosphereSystem>();
|
|
||||||
|
|
||||||
NetEntity = uid;
|
NetEntity = uid;
|
||||||
Coordinates = coordinates;
|
Coordinates = coordinates;
|
||||||
@@ -152,7 +149,7 @@ public sealed partial class AtmosAlarmEntryContainer : BoxContainer
|
|||||||
foreach ((var gas, (var mol, var percent, var alert)) in keyValuePairs)
|
foreach ((var gas, (var mol, var percent, var alert)) in keyValuePairs)
|
||||||
{
|
{
|
||||||
FixedPoint2 gasPercent = percent * 100f;
|
FixedPoint2 gasPercent = percent * 100f;
|
||||||
var gasAbbreviation = Loc.GetString(_atmosphere.GetGas(gas).Abbreviation);
|
var gasAbbreviation = Atmospherics.GasAbbreviations.GetValueOrDefault(gas, Loc.GetString("gas-unknown-abbreviation"));
|
||||||
|
|
||||||
var gasLabel = new Label()
|
var gasLabel = new Label()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using Content.Client.Stylesheets;
|
using Content.Client.Stylesheets;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Atmos.Components;
|
using Content.Shared.Atmos.Components;
|
||||||
using Content.Shared.Atmos.EntitySystems;
|
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Temperature;
|
using Content.Shared.Temperature;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
@@ -20,14 +19,12 @@ public sealed partial class AtmosMonitoringEntryContainer : BoxContainer
|
|||||||
|
|
||||||
private readonly IEntityManager _entManager;
|
private readonly IEntityManager _entManager;
|
||||||
private readonly IResourceCache _cache;
|
private readonly IResourceCache _cache;
|
||||||
private readonly SharedAtmosphereSystem _atmosphere;
|
|
||||||
|
|
||||||
public AtmosMonitoringEntryContainer(AtmosMonitoringConsoleEntry data)
|
public AtmosMonitoringEntryContainer(AtmosMonitoringConsoleEntry data)
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
_entManager = IoCManager.Resolve<IEntityManager>();
|
_entManager = IoCManager.Resolve<IEntityManager>();
|
||||||
_cache = IoCManager.Resolve<IResourceCache>();
|
_cache = IoCManager.Resolve<IResourceCache>();
|
||||||
_atmosphere = _entManager.System<SharedAtmosphereSystem>();
|
|
||||||
|
|
||||||
Data = data;
|
Data = data;
|
||||||
|
|
||||||
@@ -135,7 +132,7 @@ public sealed partial class AtmosMonitoringEntryContainer : BoxContainer
|
|||||||
var gasPercent = (FixedPoint2)0f;
|
var gasPercent = (FixedPoint2)0f;
|
||||||
gasPercent = percent * 100f;
|
gasPercent = percent * 100f;
|
||||||
|
|
||||||
var gasAbbreviation = Loc.GetString(_atmosphere.GetGas(gas).Abbreviation);
|
var gasAbbreviation = Atmospherics.GasAbbreviations.GetValueOrDefault(gas, Loc.GetString("gas-unknown-abbreviation"));
|
||||||
|
|
||||||
var gasLabel = new Label()
|
var gasLabel = new Label()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,9 +10,7 @@ namespace Content.Client.Atmos.EntitySystems
|
|||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
internal sealed class AtmosDebugOverlaySystem : SharedAtmosDebugOverlaySystem
|
internal sealed class AtmosDebugOverlaySystem : SharedAtmosDebugOverlaySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IOverlayManager _overlayManager = default!;
|
public readonly Dictionary<EntityUid, AtmosDebugOverlayMessage> TileData = new();
|
||||||
|
|
||||||
public readonly Dictionary<EntityUid, AtmosDebugOverlayMessage> TileData = [];
|
|
||||||
|
|
||||||
// Configuration set by debug commands and used by AtmosDebugOverlay {
|
// Configuration set by debug commands and used by AtmosDebugOverlay {
|
||||||
/// <summary>Value source for display</summary>
|
/// <summary>Value source for display</summary>
|
||||||
@@ -27,8 +25,6 @@ namespace Content.Client.Atmos.EntitySystems
|
|||||||
public bool CfgCBM = false;
|
public bool CfgCBM = false;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
private AtmosDebugOverlay? _overlay;
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
base.Initialize();
|
base.Initialize();
|
||||||
@@ -38,6 +34,10 @@ namespace Content.Client.Atmos.EntitySystems
|
|||||||
SubscribeNetworkEvent<AtmosDebugOverlayDisableMessage>(HandleAtmosDebugOverlayDisableMessage);
|
SubscribeNetworkEvent<AtmosDebugOverlayDisableMessage>(HandleAtmosDebugOverlayDisableMessage);
|
||||||
|
|
||||||
SubscribeLocalEvent<GridRemovalEvent>(OnGridRemoved);
|
SubscribeLocalEvent<GridRemovalEvent>(OnGridRemoved);
|
||||||
|
|
||||||
|
var overlayManager = IoCManager.Resolve<IOverlayManager>();
|
||||||
|
if(!overlayManager.HasOverlay<AtmosDebugOverlay>())
|
||||||
|
overlayManager.AddOverlay(new AtmosDebugOverlay(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGridRemoved(GridRemovalEvent ev)
|
private void OnGridRemoved(GridRemovalEvent ev)
|
||||||
@@ -51,25 +51,19 @@ namespace Content.Client.Atmos.EntitySystems
|
|||||||
private void HandleAtmosDebugOverlayMessage(AtmosDebugOverlayMessage message)
|
private void HandleAtmosDebugOverlayMessage(AtmosDebugOverlayMessage message)
|
||||||
{
|
{
|
||||||
TileData[GetEntity(message.GridId)] = message;
|
TileData[GetEntity(message.GridId)] = message;
|
||||||
|
|
||||||
if (_overlay is not null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_overlay = new AtmosDebugOverlay(this);
|
|
||||||
_overlayManager.AddOverlay(_overlay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleAtmosDebugOverlayDisableMessage(AtmosDebugOverlayDisableMessage ev)
|
private void HandleAtmosDebugOverlayDisableMessage(AtmosDebugOverlayDisableMessage ev)
|
||||||
{
|
{
|
||||||
TileData.Clear();
|
TileData.Clear();
|
||||||
RemoveOverlay();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Shutdown()
|
public override void Shutdown()
|
||||||
{
|
{
|
||||||
base.Shutdown();
|
base.Shutdown();
|
||||||
|
var overlayManager = IoCManager.Resolve<IOverlayManager>();
|
||||||
RemoveOverlay();
|
if (overlayManager.HasOverlay<AtmosDebugOverlay>())
|
||||||
|
overlayManager.RemoveOverlay<AtmosDebugOverlay>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset(RoundRestartCleanupEvent ev)
|
public void Reset(RoundRestartCleanupEvent ev)
|
||||||
@@ -81,15 +75,6 @@ namespace Content.Client.Atmos.EntitySystems
|
|||||||
{
|
{
|
||||||
return TileData.ContainsKey(gridId);
|
return TileData.ContainsKey(gridId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveOverlay()
|
|
||||||
{
|
|
||||||
if (_overlay is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_overlayManager.RemoveOverlay(_overlay);
|
|
||||||
_overlay = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal enum AtmosDebugOverlayMode : byte
|
internal enum AtmosDebugOverlayMode : byte
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Atmos.Reactions;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.EntitySystems;
|
namespace Content.Client.Atmos.EntitySystems;
|
||||||
|
|
||||||
@@ -14,29 +13,6 @@ public sealed partial class AtmosphereSystem
|
|||||||
implementation.
|
implementation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
/// <remarks>No-op on client as reactions aren't entirely in shared.
|
|
||||||
/// Don't call it. Smile.</remarks>
|
|
||||||
public override ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder)
|
|
||||||
{
|
|
||||||
// Reactions don't work on client so don't even try.
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool IsMixtureFuel(GasMixture mixture, float epsilon = Atmospherics.Epsilon)
|
|
||||||
{
|
|
||||||
var tmp = new float[Atmospherics.AdjustedNumberOfGases];
|
|
||||||
NumericsHelpers.Multiply(mixture.Moles, GasFuelMask, tmp);
|
|
||||||
return NumericsHelpers.HorizontalAdd(tmp) > epsilon;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool IsMixtureOxidizer(GasMixture mixture, float epsilon = Atmospherics.Epsilon)
|
|
||||||
{
|
|
||||||
var tmp = new float[Atmospherics.AdjustedNumberOfGases];
|
|
||||||
NumericsHelpers.Multiply(mixture.Moles, GasOxidizerMask, tmp);
|
|
||||||
return NumericsHelpers.HorizontalAdd(tmp) > epsilon;
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
protected override float GetHeatCapacityCalculation(float[] moles, bool space)
|
protected override float GetHeatCapacityCalculation(float[] moles, bool space)
|
||||||
{
|
{
|
||||||
@@ -51,7 +27,7 @@ public sealed partial class AtmosphereSystem
|
|||||||
// though this isnt the hottest code path so it should be fine
|
// though this isnt the hottest code path so it should be fine
|
||||||
// the gc can eat a little as a treat
|
// the gc can eat a little as a treat
|
||||||
var tmp = new float[moles.Length];
|
var tmp = new float[moles.Length];
|
||||||
NumericsHelpers.Multiply(moles, GasMolarHeatCapacities, tmp);
|
NumericsHelpers.Multiply(moles, GasSpecificHeats, tmp);
|
||||||
// Adjust heat capacity by speedup, because this is primarily what
|
// Adjust heat capacity by speedup, because this is primarily what
|
||||||
// determines how quickly gases heat up/cool.
|
// determines how quickly gases heat up/cool.
|
||||||
return MathF.Max(NumericsHelpers.HorizontalAdd(tmp), Atmospherics.MinimumHeatCapacity);
|
return MathF.Max(NumericsHelpers.HorizontalAdd(tmp), Atmospherics.MinimumHeatCapacity);
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
using Content.Client.Atmos.Overlays;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.EntitySystems;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// System responsible for rendering atmos fire animations using <see cref="GasTileFireOverlay"/>.
|
|
||||||
/// </summary>
|
|
||||||
[UsedImplicitly]
|
|
||||||
public sealed class GasTileFireOverlaySystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
|
||||||
|
|
||||||
private GasTileFireOverlay _fireOverlay = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
_fireOverlay = new GasTileFireOverlay();
|
|
||||||
_overlayMan.AddOverlay(_fireOverlay);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Shutdown()
|
|
||||||
{
|
|
||||||
base.Shutdown();
|
|
||||||
_overlayMan.RemoveOverlay<GasTileFireOverlay>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using Content.Client.Atmos.Overlays;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.EntitySystems;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// System responsible for rendering heat distortion using <see cref="GasTileHeatBlurOverlay"/>.
|
|
||||||
/// </summary>
|
|
||||||
[UsedImplicitly]
|
|
||||||
public sealed class GasTileHeatBlurOverlaySystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
|
||||||
|
|
||||||
private GasTileHeatBlurOverlay _gasTileHeatBlurOverlay = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
_gasTileHeatBlurOverlay = new GasTileHeatBlurOverlay();
|
|
||||||
_overlayMan.AddOverlay(_gasTileHeatBlurOverlay);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Shutdown()
|
|
||||||
{
|
|
||||||
base.Shutdown();
|
|
||||||
_overlayMan.RemoveOverlay<GasTileHeatBlurOverlay>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +1,106 @@
|
|||||||
|
using Content.Client.Atmos.Overlays;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Atmos.Components;
|
using Content.Shared.Atmos.Components;
|
||||||
using Content.Shared.Atmos.EntitySystems;
|
using Content.Shared.Atmos.EntitySystems;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Client.ResourceManagement;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
namespace Content.Client.Atmos.EntitySystems;
|
namespace Content.Client.Atmos.EntitySystems
|
||||||
|
|
||||||
[UsedImplicitly]
|
|
||||||
public sealed class GasTileOverlaySystem : SharedGasTileOverlaySystem
|
|
||||||
{
|
{
|
||||||
public override void Initialize()
|
[UsedImplicitly]
|
||||||
|
public sealed class GasTileOverlaySystem : SharedGasTileOverlaySystem
|
||||||
{
|
{
|
||||||
base.Initialize();
|
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
||||||
SubscribeNetworkEvent<GasOverlayUpdateEvent>(HandleGasOverlayUpdate);
|
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
||||||
SubscribeLocalEvent<GasTileOverlayComponent, ComponentHandleState>(OnHandleState);
|
[Dependency] private readonly SpriteSystem _spriteSys = default!;
|
||||||
}
|
[Dependency] private readonly SharedTransformSystem _xformSys = default!;
|
||||||
|
|
||||||
private void OnHandleState(EntityUid gridUid, GasTileOverlayComponent comp, ref ComponentHandleState args)
|
private GasTileOverlay _overlay = default!;
|
||||||
{
|
|
||||||
Dictionary<Vector2i, GasOverlayChunk> modifiedChunks;
|
|
||||||
|
|
||||||
switch (args.Current)
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
// is this a delta or full state?
|
base.Initialize();
|
||||||
case GasTileOverlayDeltaState delta:
|
SubscribeNetworkEvent<GasOverlayUpdateEvent>(HandleGasOverlayUpdate);
|
||||||
|
SubscribeLocalEvent<GasTileOverlayComponent, ComponentHandleState>(OnHandleState);
|
||||||
|
|
||||||
|
_overlay = new GasTileOverlay(this, EntityManager, _resourceCache, ProtoMan, _spriteSys, _xformSys);
|
||||||
|
_overlayMan.AddOverlay(_overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Shutdown()
|
||||||
|
{
|
||||||
|
base.Shutdown();
|
||||||
|
_overlayMan.RemoveOverlay<GasTileOverlay>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnHandleState(EntityUid gridUid, GasTileOverlayComponent comp, ref ComponentHandleState args)
|
||||||
|
{
|
||||||
|
Dictionary<Vector2i, GasOverlayChunk> modifiedChunks;
|
||||||
|
|
||||||
|
switch (args.Current)
|
||||||
{
|
{
|
||||||
modifiedChunks = delta.ModifiedChunks;
|
// is this a delta or full state?
|
||||||
foreach (var index in comp.Chunks.Keys)
|
case GasTileOverlayDeltaState delta:
|
||||||
{
|
{
|
||||||
if (!delta.AllChunks.Contains(index))
|
modifiedChunks = delta.ModifiedChunks;
|
||||||
comp.Chunks.Remove(index);
|
foreach (var index in comp.Chunks.Keys)
|
||||||
}
|
{
|
||||||
|
if (!delta.AllChunks.Contains(index))
|
||||||
|
comp.Chunks.Remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case GasTileOverlayState state:
|
case GasTileOverlayState state:
|
||||||
{
|
|
||||||
modifiedChunks = state.Chunks;
|
|
||||||
foreach (var index in comp.Chunks.Keys)
|
|
||||||
{
|
{
|
||||||
if (!state.Chunks.ContainsKey(index))
|
modifiedChunks = state.Chunks;
|
||||||
comp.Chunks.Remove(index);
|
foreach (var index in comp.Chunks.Keys)
|
||||||
|
{
|
||||||
|
if (!state.Chunks.ContainsKey(index))
|
||||||
|
comp.Chunks.Remove(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var (index, data) in modifiedChunks)
|
foreach (var (index, data) in modifiedChunks)
|
||||||
{
|
|
||||||
comp.Chunks[index] = data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleGasOverlayUpdate(GasOverlayUpdateEvent ev)
|
|
||||||
{
|
|
||||||
foreach (var (nent, removedIndicies) in ev.RemovedChunks)
|
|
||||||
{
|
|
||||||
var grid = GetEntity(nent);
|
|
||||||
|
|
||||||
if (!TryComp(grid, out GasTileOverlayComponent? comp))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var index in removedIndicies)
|
|
||||||
{
|
{
|
||||||
comp.Chunks.Remove(index);
|
comp.Chunks[index] = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (nent, gridData) in ev.UpdatedChunks)
|
private void HandleGasOverlayUpdate(GasOverlayUpdateEvent ev)
|
||||||
{
|
{
|
||||||
var grid = GetEntity(nent);
|
foreach (var (nent, removedIndicies) in ev.RemovedChunks)
|
||||||
|
|
||||||
if (!TryComp(grid, out GasTileOverlayComponent? comp))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var chunkData in gridData)
|
|
||||||
{
|
{
|
||||||
comp.Chunks[chunkData.Index] = chunkData;
|
var grid = GetEntity(nent);
|
||||||
|
|
||||||
|
if (!TryComp(grid, out GasTileOverlayComponent? comp))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var index in removedIndicies)
|
||||||
|
{
|
||||||
|
comp.Chunks.Remove(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (nent, gridData) in ev.UpdatedChunks)
|
||||||
|
{
|
||||||
|
var grid = GetEntity(nent);
|
||||||
|
|
||||||
|
if (!TryComp(grid, out GasTileOverlayComponent? comp))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var chunkData in gridData)
|
||||||
|
{
|
||||||
|
comp.Chunks[chunkData.Index] = chunkData;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
using Content.Client.Atmos.Overlays;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.EntitySystems;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// System responsible for rendering visible atmos gasses (like plasma for example) using <see cref="GasTileVisibleGasOverlay"/>.
|
|
||||||
/// </summary>
|
|
||||||
[UsedImplicitly]
|
|
||||||
public sealed class GasTileVisibleGasOverlaySystem : EntitySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
|
||||||
|
|
||||||
private GasTileVisibleGasOverlay _visibleGasOverlay = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
_visibleGasOverlay = new GasTileVisibleGasOverlay();
|
|
||||||
_overlayMan.AddOverlay(_visibleGasOverlay);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Shutdown()
|
|
||||||
{
|
|
||||||
base.Shutdown();
|
|
||||||
_overlayMan.RemoveOverlay<GasTileVisibleGasOverlay>();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
<!-- Status (pressure, temperature, alarm state, device total, address, etc) -->
|
<!-- Status (pressure, temperature, alarm state, device total, address, etc) -->
|
||||||
<BoxContainer Orientation="Horizontal" Margin="0 0 0 2">
|
<BoxContainer Orientation="Horizontal" Margin="0 0 0 2">
|
||||||
<!-- Left column (view of entity) -->
|
<!-- Left column (view of entity) -->
|
||||||
<PanelContainer Margin="2 0 6 0" StyleClasses="BackgroundPanelDark" VerticalAlignment="Center" VerticalExpand="True">
|
<PanelContainer Margin="2 0 6 0" StyleClasses="Inset" VerticalAlignment="Center" VerticalExpand="True">
|
||||||
<SpriteView Name="EntityView" OverrideDirection="South" Scale="2 2" SetSize="64 64"/>
|
<SpriteView Name="EntityView" OverrideDirection="South" Scale="2 2" SetSize="64 64"/>
|
||||||
</PanelContainer>
|
</PanelContainer>
|
||||||
<!-- Center column (pressure, temperature, alarm state) -->
|
<!-- Center column (pressure, temperature, alarm state) -->
|
||||||
|
|||||||
@@ -1,253 +0,0 @@
|
|||||||
using Content.Client.Atmos.EntitySystems;
|
|
||||||
using Content.Client.Graphics;
|
|
||||||
using Content.Shared.Atmos;
|
|
||||||
using Content.Shared.Atmos.Components;
|
|
||||||
using Content.Shared.Atmos.EntitySystems;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Shared.Enums;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Map.Components;
|
|
||||||
using System.Numerics;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Overlays;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Renders a thermal heatmap overlay for gas tiles, used for equipment like thermal glasses.
|
|
||||||
/// /// </summary>
|
|
||||||
public sealed class GasTileDangerousTemperatureOverlay : Overlay
|
|
||||||
{
|
|
||||||
public override bool RequestScreenTexture { get; set; } = false;
|
|
||||||
|
|
||||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
|
||||||
[Dependency] private readonly IClyde _clyde = default!;
|
|
||||||
|
|
||||||
private GasTileOverlaySystem? _gasTileOverlay;
|
|
||||||
private readonly SharedTransformSystem _xformSys;
|
|
||||||
private EntityQuery<GasTileOverlayComponent> _overlayQuery;
|
|
||||||
|
|
||||||
private readonly OverlayResourceCache<CachedResources> _resources = new();
|
|
||||||
private List<Entity<MapGridComponent>> _grids = new();
|
|
||||||
|
|
||||||
// Cache used to transform ThermalByte into Color for overlay
|
|
||||||
private readonly Color[] _colorCache = new Color[256];
|
|
||||||
|
|
||||||
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowFOV;
|
|
||||||
|
|
||||||
public GasTileDangerousTemperatureOverlay()
|
|
||||||
{
|
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
_xformSys = _entManager.System<SharedTransformSystem>();
|
|
||||||
|
|
||||||
_overlayQuery = _entManager.GetEntityQuery<GasTileOverlayComponent>();
|
|
||||||
|
|
||||||
for (byte i = 0; i <= ThermalByte.TempResolution; i++)
|
|
||||||
{
|
|
||||||
_colorCache[i] = PreCalculateColor(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
_colorCache[ThermalByte.StateVacuum] = Color.Teal;
|
|
||||||
_colorCache[ThermalByte.StateVacuum].A = 0.6f;
|
|
||||||
_colorCache[ThermalByte.AtmosImpossible] = Color.Transparent;
|
|
||||||
|
|
||||||
#if DEBUG // This shouldn't happend so tell me if you see this LimeGreen on the screen
|
|
||||||
_colorCache[ThermalByte.ReservedFuture0] = Color.LimeGreen;
|
|
||||||
_colorCache[ThermalByte.ReservedFuture1] = Color.LimeGreen;
|
|
||||||
_colorCache[ThermalByte.ReservedFuture2] = Color.LimeGreen;
|
|
||||||
#else
|
|
||||||
_colorCache[ThermalByte.ReservedFuture0] = Color.Transparent;
|
|
||||||
_colorCache[ThermalByte.ReservedFuture1] = Color.Transparent;
|
|
||||||
_colorCache[ThermalByte.ReservedFuture2] = Color.Transparent;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Used for Calculating onscreen color from ThermalByte core value
|
|
||||||
/// /// </summary>
|
|
||||||
private static Color PreCalculateColor(byte byteTemp)
|
|
||||||
{
|
|
||||||
// Color Thresholds in Kelvin
|
|
||||||
// -150 C
|
|
||||||
const float deepFreezeK = 123.15f;
|
|
||||||
// -50 C
|
|
||||||
const float freezeStartK = 223.15f;
|
|
||||||
// 0 C
|
|
||||||
const float waterFreezeK = 273.15f;
|
|
||||||
// 50 C
|
|
||||||
const float heatStartK = 323.15f;
|
|
||||||
// 100 C
|
|
||||||
const float waterBoilK = 373.15f;
|
|
||||||
// 300 C
|
|
||||||
const float superHeatK = 573.15f;
|
|
||||||
|
|
||||||
var tempK = byteTemp * ThermalByte.TempDegreeResolution;
|
|
||||||
|
|
||||||
// Neutral Zone Check (0C to 50C)
|
|
||||||
// If between 273.15K and 323.15K, it's transparent.
|
|
||||||
if (tempK >= waterFreezeK && tempK < heatStartK)
|
|
||||||
{
|
|
||||||
return Color.Transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
Color resultingColor;
|
|
||||||
|
|
||||||
switch (tempK)
|
|
||||||
{
|
|
||||||
case < deepFreezeK:
|
|
||||||
resultingColor = Color.FromHex("#330066");
|
|
||||||
resultingColor.A = 0.7f;
|
|
||||||
break;
|
|
||||||
case < freezeStartK:
|
|
||||||
// Interpolate Deep Purple -> Blue
|
|
||||||
// Range: 123.15 to 223.15 (Span: 100)
|
|
||||||
resultingColor = Color.InterpolateBetween(
|
|
||||||
Color.FromHex("#330066"),
|
|
||||||
Color.Blue,
|
|
||||||
(tempK - deepFreezeK) * 0.01f);
|
|
||||||
resultingColor.A = 0.6f;
|
|
||||||
break;
|
|
||||||
case < waterFreezeK:
|
|
||||||
// Interpolate Blue -> Transparent
|
|
||||||
// Range: 223.15 to 273.15 (Span: 50)
|
|
||||||
|
|
||||||
resultingColor = Color.InterpolateBetween(
|
|
||||||
new Color(Color.Blue.R, Color.Blue.G, Color.Blue.B, 0.6f),
|
|
||||||
new Color(Color.Blue.R, Color.Blue.G, Color.Blue.B, 0.2f),
|
|
||||||
(tempK - freezeStartK) * 0.02f);
|
|
||||||
break;
|
|
||||||
case < waterBoilK:
|
|
||||||
// Interpolate Transparent -> Yellow
|
|
||||||
// Range: 323.15 to 373.15 (Span: 50)
|
|
||||||
|
|
||||||
resultingColor = Color.InterpolateBetween(
|
|
||||||
new Color(Color.Yellow.R, Color.Yellow.G, Color.Yellow.B, 0.2f),
|
|
||||||
new Color(Color.Yellow.R, Color.Yellow.G, Color.Yellow.B, 0.6f),
|
|
||||||
(tempK - heatStartK) * 0.02f);
|
|
||||||
break;
|
|
||||||
case < superHeatK:
|
|
||||||
// Interpolate Yellow -> Red
|
|
||||||
// Range: 373.15 to 573.15 (Span: 200)
|
|
||||||
resultingColor = Color.InterpolateBetween(
|
|
||||||
Color.Yellow,
|
|
||||||
Color.Red,
|
|
||||||
(tempK - waterBoilK) * 0.005f);
|
|
||||||
resultingColor.A = 0.6f;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
resultingColor = Color.DarkRed;
|
|
||||||
resultingColor.A = 0.7f;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return resultingColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
|
||||||
{
|
|
||||||
if (args.MapId == MapId.Nullspace)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
_gasTileOverlay ??= _entManager.System<GasTileOverlaySystem>();
|
|
||||||
if (_gasTileOverlay == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var target = args.Viewport.RenderTarget;
|
|
||||||
|
|
||||||
var res = _resources.GetForViewport(args.Viewport, static _ => new CachedResources());
|
|
||||||
if (res.TemperatureTarget is null || res.TemperatureTarget.Texture.Size != target.Size)
|
|
||||||
{
|
|
||||||
res.TemperatureTarget?.Dispose();
|
|
||||||
res.TemperatureTarget = _clyde.CreateRenderTarget(
|
|
||||||
target.Size,
|
|
||||||
new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb),
|
|
||||||
name: nameof(GasTileDangerousTemperatureOverlay));
|
|
||||||
}
|
|
||||||
|
|
||||||
var drawHandle = args.WorldHandle;
|
|
||||||
var worldBounds = args.WorldBounds;
|
|
||||||
var worldAABB = args.WorldAABB;
|
|
||||||
var mapId = args.MapId;
|
|
||||||
var worldToViewportLocal = args.Viewport.GetWorldToLocalMatrix();
|
|
||||||
|
|
||||||
drawHandle.RenderInRenderTarget(res.TemperatureTarget,
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
_grids.Clear();
|
|
||||||
_mapManager.FindGridsIntersecting(mapId, worldAABB, ref _grids);
|
|
||||||
|
|
||||||
foreach (var grid in _grids)
|
|
||||||
{
|
|
||||||
if (!_overlayQuery.TryGetComponent(grid.Owner, out var comp))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var gridTileSizeVec = grid.Comp.TileSizeVector;
|
|
||||||
var gridTileCenterVec = grid.Comp.TileSizeHalfVector;
|
|
||||||
var gridEntToWorld = _xformSys.GetWorldMatrix(grid.Owner);
|
|
||||||
var gridEntToViewportLocal = gridEntToWorld * worldToViewportLocal;
|
|
||||||
|
|
||||||
drawHandle.SetTransform(gridEntToViewportLocal);
|
|
||||||
|
|
||||||
var worldToGridLocal = _xformSys.GetInvWorldMatrix(grid.Owner);
|
|
||||||
var floatBounds = worldToGridLocal.TransformBox(worldBounds).Enlarged(grid.Comp.TileSize);
|
|
||||||
|
|
||||||
var localBounds = new Box2i(
|
|
||||||
(int)MathF.Floor(floatBounds.Left),
|
|
||||||
(int)MathF.Floor(floatBounds.Bottom),
|
|
||||||
(int)MathF.Ceiling(floatBounds.Right),
|
|
||||||
(int)MathF.Ceiling(floatBounds.Top));
|
|
||||||
|
|
||||||
foreach (var chunk in comp.Chunks.Values)
|
|
||||||
{
|
|
||||||
var enumerator = new GasChunkEnumerator(chunk);
|
|
||||||
while (enumerator.MoveNext(out var tileGas))
|
|
||||||
{
|
|
||||||
var tilePosition = chunk.Origin + (enumerator.X, enumerator.Y);
|
|
||||||
if (!localBounds.Contains(tilePosition))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var gasColor = _colorCache[tileGas.ByteGasTemperature.Value];
|
|
||||||
|
|
||||||
if (gasColor.A <= 0f)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
drawHandle.DrawRect(
|
|
||||||
Box2.CenteredAround(tilePosition + gridTileCenterVec, gridTileSizeVec),
|
|
||||||
gasColor
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new Color(0, 0, 0, 0));
|
|
||||||
|
|
||||||
drawHandle.SetTransform(Matrix3x2.Identity);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Draw(in OverlayDrawArgs args)
|
|
||||||
{
|
|
||||||
var res = _resources.GetForViewport(args.Viewport, static _ => new CachedResources());
|
|
||||||
|
|
||||||
if (res.TemperatureTarget != null)
|
|
||||||
args.WorldHandle.DrawTextureRect(res.TemperatureTarget.Texture, args.WorldBounds);
|
|
||||||
args.WorldHandle.SetTransform(Matrix3x2.Identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void DisposeBehavior()
|
|
||||||
{
|
|
||||||
_resources.Dispose();
|
|
||||||
base.DisposeBehavior();
|
|
||||||
}
|
|
||||||
|
|
||||||
private sealed class CachedResources : IDisposable
|
|
||||||
{
|
|
||||||
public IRenderTexture? TemperatureTarget;
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
TemperatureTarget?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
using Content.Client.Atmos.EntitySystems;
|
|
||||||
using Content.Shared.Atmos;
|
|
||||||
using Content.Shared.Atmos.Components;
|
|
||||||
using Content.Shared.Species;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Client.ResourceManagement;
|
|
||||||
using Robust.Shared.Enums;
|
|
||||||
using Robust.Shared.Graphics.RSI;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Map.Components;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
using System.Numerics;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Overlays;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Overlay responsible for rendering atmos fire animation.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class GasTileFireOverlay : Overlay
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IPrototypeManager _protoMan = default!;
|
|
||||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
|
||||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
|
||||||
|
|
||||||
public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities | OverlaySpace.WorldSpaceBelowWorld;
|
|
||||||
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
|
||||||
|
|
||||||
private readonly SharedTransformSystem _xformSys;
|
|
||||||
private readonly SharedMapSystem _mapSystem = default!;
|
|
||||||
private readonly ShaderInstance _shader;
|
|
||||||
|
|
||||||
private readonly float[] _timer;
|
|
||||||
private readonly float[][] _frameDelays;
|
|
||||||
private readonly int[] _frameCounter;
|
|
||||||
|
|
||||||
// TODO combine textures into a single texture atlas.
|
|
||||||
private readonly Texture[][] _frames;
|
|
||||||
|
|
||||||
private const int FireStates = 3;
|
|
||||||
private const string FireRsiPath = "/Textures/Effects/fire.rsi";
|
|
||||||
|
|
||||||
public const int GasOverlayZIndex = (int)Shared.DrawDepth.DrawDepth.Effects; // Under ghosts, above mostly everything else
|
|
||||||
|
|
||||||
public GasTileFireOverlay()
|
|
||||||
{
|
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
_xformSys = _entManager.System<SharedTransformSystem>();
|
|
||||||
_mapSystem = _entManager.System<SharedMapSystem>();
|
|
||||||
_shader = _protoMan.Index(UnshadedShader).Instance();
|
|
||||||
ZIndex = GasOverlayZIndex;
|
|
||||||
|
|
||||||
_timer = new float[FireStates];
|
|
||||||
_frameDelays = new float[FireStates][];
|
|
||||||
_frameCounter = new int[FireStates];
|
|
||||||
_frames = new Texture[FireStates][];
|
|
||||||
|
|
||||||
var fire = _resourceCache.GetResource<RSIResource>(FireRsiPath).RSI;
|
|
||||||
|
|
||||||
for (var i = 0; i < FireStates; i++)
|
|
||||||
{
|
|
||||||
if (!fire.TryGetState((i + 1).ToString(), out var state))
|
|
||||||
throw new ArgumentOutOfRangeException($"Fire RSI doesn't have state \"{i}\"!");
|
|
||||||
|
|
||||||
_frames[i] = state.GetFrames(RsiDirection.South);
|
|
||||||
_frameDelays[i] = state.GetDelays();
|
|
||||||
_frameCounter[i] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void FrameUpdate(FrameEventArgs args)
|
|
||||||
{
|
|
||||||
base.FrameUpdate(args);
|
|
||||||
|
|
||||||
for (var i = 0; i < FireStates; i++)
|
|
||||||
{
|
|
||||||
var delays = _frameDelays[i];
|
|
||||||
if (delays.Length == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var frameCount = _frameCounter[i];
|
|
||||||
_timer[i] += args.DeltaSeconds;
|
|
||||||
var time = delays[frameCount];
|
|
||||||
|
|
||||||
if (_timer[i] < time) continue;
|
|
||||||
_timer[i] -= time;
|
|
||||||
_frameCounter[i] = (frameCount + 1) % _frames[i].Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Draw(in OverlayDrawArgs args)
|
|
||||||
{
|
|
||||||
if (args.MapId == MapId.Nullspace)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var drawHandle = args.WorldHandle;
|
|
||||||
var xformQuery = _entManager.GetEntityQuery<TransformComponent>();
|
|
||||||
var overlayQuery = _entManager.GetEntityQuery<GasTileOverlayComponent>();
|
|
||||||
var gridState = (args.WorldBounds,
|
|
||||||
args.WorldHandle,
|
|
||||||
_frames,
|
|
||||||
_frameCounter,
|
|
||||||
_shader,
|
|
||||||
overlayQuery,
|
|
||||||
xformQuery,
|
|
||||||
_xformSys);
|
|
||||||
|
|
||||||
var mapUid = _mapSystem.GetMapOrInvalid(args.MapId);
|
|
||||||
|
|
||||||
if (args.Space != OverlaySpace.WorldSpaceEntities)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// TODO: WorldBounds callback.
|
|
||||||
_mapManager.FindGridsIntersecting(args.MapId, args.WorldAABB, ref gridState,
|
|
||||||
static (EntityUid uid, MapGridComponent grid,
|
|
||||||
ref (Box2Rotated WorldBounds,
|
|
||||||
DrawingHandleWorld drawHandle,
|
|
||||||
Texture[][] frames,
|
|
||||||
int[] frameCounter,
|
|
||||||
ShaderInstance shader,
|
|
||||||
EntityQuery<GasTileOverlayComponent> overlayQuery,
|
|
||||||
EntityQuery<TransformComponent> xformQuery,
|
|
||||||
SharedTransformSystem xformSys) state) =>
|
|
||||||
{
|
|
||||||
if (!state.overlayQuery.TryGetComponent(uid, out var comp) ||
|
|
||||||
!state.xformQuery.TryGetComponent(uid, out var gridXform))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var (_, _, worldMatrix, invMatrix) = state.xformSys.GetWorldPositionRotationMatrixWithInv(gridXform);
|
|
||||||
state.drawHandle.SetTransform(worldMatrix);
|
|
||||||
var floatBounds = invMatrix.TransformBox(state.WorldBounds).Enlarged(grid.TileSize);
|
|
||||||
var localBounds = new Box2i(
|
|
||||||
(int)MathF.Floor(floatBounds.Left),
|
|
||||||
(int)MathF.Floor(floatBounds.Bottom),
|
|
||||||
(int)MathF.Ceiling(floatBounds.Right),
|
|
||||||
(int)MathF.Ceiling(floatBounds.Top));
|
|
||||||
|
|
||||||
// Currently it would be faster to group drawing by gas rather than by chunk, but if the textures are
|
|
||||||
// ever moved to a single atlas, that should no longer be the case. So this is just grouping draw calls
|
|
||||||
// by chunk, even though its currently slower.
|
|
||||||
|
|
||||||
state.drawHandle.UseShader(state.shader);
|
|
||||||
foreach (var chunk in comp.Chunks.Values)
|
|
||||||
{
|
|
||||||
var enumerator = new GasChunkEnumerator(chunk);
|
|
||||||
|
|
||||||
while (enumerator.MoveNext(out var gas))
|
|
||||||
{
|
|
||||||
if (gas.FireState == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var index = chunk.Origin + (enumerator.X, enumerator.Y);
|
|
||||||
if (!localBounds.Contains(index))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var fireState = gas.FireState - 1;
|
|
||||||
var texture = state.frames[fireState][state.frameCounter[fireState]];
|
|
||||||
state.drawHandle.DrawTexture(texture, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
drawHandle.UseShader(null);
|
|
||||||
drawHandle.SetTransform(Matrix3x2.Identity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,263 +0,0 @@
|
|||||||
using Content.Client.Atmos.EntitySystems;
|
|
||||||
using Content.Client.Graphics;
|
|
||||||
using Content.Client.Resources;
|
|
||||||
using Content.Shared.Atmos;
|
|
||||||
using Content.Shared.Atmos.Components;
|
|
||||||
using Content.Shared.Atmos.EntitySystems;
|
|
||||||
using Content.Shared.CCVar;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Client.ResourceManagement;
|
|
||||||
using Robust.Shared.Configuration;
|
|
||||||
using Robust.Shared.Enums;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Map.Components;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using System.Numerics;
|
|
||||||
using Color = Robust.Shared.Maths.Color;
|
|
||||||
using Texture = Robust.Client.Graphics.Texture;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Overlays;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Overlay responsible for rendering heat distortion shader.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class GasTileHeatBlurOverlay : Overlay
|
|
||||||
{
|
|
||||||
public override bool RequestScreenTexture { get; set; } = true;
|
|
||||||
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
|
||||||
private static readonly ProtoId<ShaderPrototype> HeatOverlayShader = "HeatBlur";
|
|
||||||
|
|
||||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
|
||||||
[Dependency] private readonly IClyde _clyde = default!;
|
|
||||||
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
|
||||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
|
||||||
|
|
||||||
private readonly SharedTransformSystem _xformSys;
|
|
||||||
private readonly ShaderInstance _shader;
|
|
||||||
|
|
||||||
private readonly Texture _noiseTexture;
|
|
||||||
private readonly Texture _heatGradientTexture;
|
|
||||||
private List<Entity<MapGridComponent>> _intersectingGrids = new();
|
|
||||||
private readonly OverlayResourceCache<CachedResources> _resources = new();
|
|
||||||
|
|
||||||
// Overlay settings
|
|
||||||
private const float
|
|
||||||
ShaderSpilling = 2.5f; // for example 4f - spills shader one tile from hotspot, 2.5f - spills it half tile
|
|
||||||
|
|
||||||
private const float ShaderStrength = 0.04f; // Makes waves stronger
|
|
||||||
private const float ShaderScale = 1f; // Makes more waves
|
|
||||||
private const float ShaderSpeed = 0.4f; // Makes waves run faster
|
|
||||||
|
|
||||||
// Overlay settings for reduced motion setting
|
|
||||||
private const float ShaderStrengthForReducedMotion = 0.01f;
|
|
||||||
private const float ShaderScaleReducedMotion = 0.5f;
|
|
||||||
private const float ShaderSpeedReducedMotion = 0.25f;
|
|
||||||
|
|
||||||
private const int MinDistortionTemp = 300; // Distortion starts to show up at this temperature in Kelvins
|
|
||||||
private const int MaxDistortionTemp = 2000; // Maximum distortion strength at this temperature in Kelvins
|
|
||||||
|
|
||||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
|
||||||
|
|
||||||
public GasTileHeatBlurOverlay()
|
|
||||||
{
|
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
_xformSys = _entManager.System<SharedTransformSystem>();
|
|
||||||
|
|
||||||
_noiseTexture = _resourceCache.GetTexture("/Textures/Effects/HeatBlur/perlin_noise.png");
|
|
||||||
_heatGradientTexture = _resourceCache.GetTexture("/Textures/Effects/HeatBlur/soft_circle.png");
|
|
||||||
|
|
||||||
_shader = _proto.Index(HeatOverlayShader).InstanceUnique();
|
|
||||||
_configManager.OnValueChanged(CCVars.ReducedMotion, SetReducedMotion, invokeImmediately: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetReducedMotion(bool reducedMotion)
|
|
||||||
{
|
|
||||||
_shader.SetParameter("strength_scale", reducedMotion ? ShaderStrengthForReducedMotion : ShaderStrength);
|
|
||||||
_shader.SetParameter("spatial_scale", reducedMotion ? ShaderScaleReducedMotion : ShaderScale);
|
|
||||||
_shader.SetParameter("speed_scale", reducedMotion ? ShaderSpeedReducedMotion : ShaderSpeed);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
|
||||||
{
|
|
||||||
if (args.MapId == MapId.Nullspace)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var res = _resources.GetForViewport(args.Viewport, static _ => new CachedResources());
|
|
||||||
|
|
||||||
var target = args.Viewport.RenderTarget;
|
|
||||||
|
|
||||||
// Probably the resolution of the game window changed, remake the textures.
|
|
||||||
if (res.HeatTarget?.Texture.Size != target.Size)
|
|
||||||
{
|
|
||||||
res.HeatTarget?.Dispose();
|
|
||||||
res.HeatTarget = _clyde.CreateRenderTarget(
|
|
||||||
target.Size,
|
|
||||||
new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb),
|
|
||||||
name: nameof(GasTileHeatBlurOverlaySystem));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.HeatBlurTarget?.Texture.Size != target.Size)
|
|
||||||
{
|
|
||||||
res.HeatBlurTarget?.Dispose();
|
|
||||||
res.HeatBlurTarget = _clyde.CreateRenderTarget(
|
|
||||||
target.Size,
|
|
||||||
new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb),
|
|
||||||
name: $"{nameof(GasTileHeatBlurOverlaySystem)}-blur");
|
|
||||||
}
|
|
||||||
|
|
||||||
var overlayQuery = _entManager.GetEntityQuery<GasTileOverlayComponent>();
|
|
||||||
|
|
||||||
args.WorldHandle.UseShader(_proto.Index(UnshadedShader).Instance());
|
|
||||||
|
|
||||||
var mapId = args.MapId;
|
|
||||||
var worldAABB = args.WorldAABB;
|
|
||||||
var worldBounds = args.WorldBounds;
|
|
||||||
var worldHandle = args.WorldHandle;
|
|
||||||
var worldToViewportLocal = args.Viewport.GetWorldToLocalMatrix();
|
|
||||||
|
|
||||||
// If there is no distortion after checking all visible tiles, we can bail early
|
|
||||||
var anyDistortion = false;
|
|
||||||
|
|
||||||
// We're rendering in the context of the heat target texture, which will encode data as to where and how strong
|
|
||||||
// the heat distortion will be
|
|
||||||
args.WorldHandle.RenderInRenderTarget(res.HeatTarget,
|
|
||||||
() =>
|
|
||||||
{
|
|
||||||
_intersectingGrids.Clear();
|
|
||||||
_mapManager.FindGridsIntersecting(mapId, worldAABB, ref _intersectingGrids);
|
|
||||||
foreach (var grid in _intersectingGrids)
|
|
||||||
{
|
|
||||||
if (!overlayQuery.TryGetComponent(grid.Owner, out var comp))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var gridEntToWorld = _xformSys.GetWorldMatrix(grid.Owner);
|
|
||||||
var gridEntToViewportLocal = gridEntToWorld * worldToViewportLocal;
|
|
||||||
|
|
||||||
if (!Matrix3x2.Invert(gridEntToViewportLocal, out var viewportLocalToGridEnt))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var uvToUi = Matrix3Helpers.CreateScale(res.HeatTarget.Size.X, -res.HeatTarget.Size.Y);
|
|
||||||
var uvToGridEnt = uvToUi * viewportLocalToGridEnt;
|
|
||||||
|
|
||||||
// Because we want the actual distortion to be calculated based on the grid coordinates*, we need
|
|
||||||
// to pass a matrix transformation to go from the viewport coordinates to grid coordinates.
|
|
||||||
// * (why? because otherwise the effect would shimmer like crazy as you moved around, think
|
|
||||||
// moving a piece of warped glass above a picture instead of placing the warped glass on the
|
|
||||||
// paper and moving them together)
|
|
||||||
_shader.SetParameter("grid_ent_from_viewport_local", uvToGridEnt);
|
|
||||||
|
|
||||||
// Draw commands (like DrawRect) will be using grid coordinates from here
|
|
||||||
worldHandle.SetTransform(gridEntToViewportLocal);
|
|
||||||
|
|
||||||
// We only care about tiles that fit in these bounds
|
|
||||||
var worldToGridLocal = _xformSys.GetInvWorldMatrix(grid.Owner);
|
|
||||||
var floatBounds = worldToGridLocal.TransformBox(worldBounds).Enlarged(grid.Comp.TileSize);
|
|
||||||
|
|
||||||
var localBounds = new Box2i(
|
|
||||||
(int)MathF.Floor(floatBounds.Left),
|
|
||||||
(int)MathF.Floor(floatBounds.Bottom),
|
|
||||||
(int)MathF.Ceiling(floatBounds.Right),
|
|
||||||
(int)MathF.Ceiling(floatBounds.Top));
|
|
||||||
|
|
||||||
// for each tile and its gas --->
|
|
||||||
foreach (var chunk in comp.Chunks.Values)
|
|
||||||
{
|
|
||||||
var enumerator = new GasChunkEnumerator(chunk);
|
|
||||||
|
|
||||||
while (enumerator.MoveNext(out var tileGas))
|
|
||||||
{
|
|
||||||
// Check and make sure the tile is within the viewport/screen
|
|
||||||
var tilePosition = chunk.Origin + (enumerator.X, enumerator.Y);
|
|
||||||
if (!localBounds.Contains(tilePosition))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Get the distortion strength from the temperature and bail if it's not hot enough
|
|
||||||
var strength = GetHeatDistortionStrength(tileGas.ByteGasTemperature);
|
|
||||||
if (strength <= 0f)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
anyDistortion = true;
|
|
||||||
|
|
||||||
// Encode the strength in the red channel
|
|
||||||
// alpha set to 1 as tile is active
|
|
||||||
worldHandle.DrawTextureRect(
|
|
||||||
_heatGradientTexture,
|
|
||||||
Box2.CenteredAround(tilePosition + grid.Comp.TileSizeHalfVector,
|
|
||||||
grid.Comp.TileSizeVector * ShaderSpilling),
|
|
||||||
new Color(strength, 0f, 0f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// This clears the buffer to all zero first...
|
|
||||||
new Color(0, 0, 0, 0));
|
|
||||||
|
|
||||||
// no distortion, no need to render
|
|
||||||
if (!anyDistortion)
|
|
||||||
{
|
|
||||||
args.WorldHandle.UseShader(null);
|
|
||||||
args.WorldHandle.SetTransform(Matrix3x2.Identity);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Draw(in OverlayDrawArgs args)
|
|
||||||
{
|
|
||||||
var res = _resources.GetForViewport(args.Viewport, static _ => new CachedResources());
|
|
||||||
|
|
||||||
if (ScreenTexture is null || res.HeatTarget is null || res.HeatBlurTarget is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_shader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
|
|
||||||
_shader.SetParameter("NOISE_TEXTURE", _noiseTexture);
|
|
||||||
|
|
||||||
args.WorldHandle.UseShader(_shader);
|
|
||||||
args.WorldHandle.DrawTextureRect(res.HeatTarget.Texture, args.WorldBounds);
|
|
||||||
|
|
||||||
args.WorldHandle.UseShader(null);
|
|
||||||
args.WorldHandle.SetTransform(Matrix3x2.Identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void DisposeBehavior()
|
|
||||||
{
|
|
||||||
_resources.Dispose();
|
|
||||||
|
|
||||||
_configManager.UnsubValueChanged(CCVars.ReducedMotion, SetReducedMotion);
|
|
||||||
base.DisposeBehavior();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the strength of the heat distortion effect based on the temperature of the tile.
|
|
||||||
/// The strength is a value between 0 and 1, where 0 means no distortion and 1 means maximum distortion.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="temp">The temperature of the tile.</param>
|
|
||||||
/// <returns>The strength of the heat distortion effect.</returns>
|
|
||||||
/// <seealso cref="ThermalByte"/>
|
|
||||||
private static float GetHeatDistortionStrength(ThermalByte temp)
|
|
||||||
{
|
|
||||||
if (!temp.TryGetTemperature(out var kelvinTemp))
|
|
||||||
{
|
|
||||||
return 0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
var strength = (kelvinTemp - MinDistortionTemp) / (MaxDistortionTemp - MinDistortionTemp);
|
|
||||||
|
|
||||||
return MathHelper.Clamp01(strength);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class CachedResources : IDisposable
|
|
||||||
{
|
|
||||||
public IRenderTexture? HeatTarget;
|
|
||||||
public IRenderTexture? HeatBlurTarget;
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
HeatTarget?.Dispose();
|
|
||||||
HeatBlurTarget?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,302 @@
|
|||||||
|
using System.Numerics;
|
||||||
|
using Content.Client.Atmos.Components;
|
||||||
|
using Content.Client.Atmos.EntitySystems;
|
||||||
|
using Content.Shared.Atmos;
|
||||||
|
using Content.Shared.Atmos.Components;
|
||||||
|
using Content.Shared.Atmos.EntitySystems;
|
||||||
|
using Content.Shared.Atmos.Prototypes;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Client.ResourceManagement;
|
||||||
|
using Robust.Shared.Enums;
|
||||||
|
using Robust.Shared.Graphics.RSI;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Map.Components;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Timing;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Client.Atmos.Overlays
|
||||||
|
{
|
||||||
|
public sealed class GasTileOverlay : Overlay
|
||||||
|
{
|
||||||
|
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
||||||
|
|
||||||
|
private readonly IEntityManager _entManager;
|
||||||
|
private readonly IMapManager _mapManager;
|
||||||
|
private readonly SharedAtmosphereSystem _atmosphereSystem;
|
||||||
|
private readonly SharedMapSystem _mapSystem;
|
||||||
|
private readonly SharedTransformSystem _xformSys;
|
||||||
|
|
||||||
|
public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities | OverlaySpace.WorldSpaceBelowWorld;
|
||||||
|
private readonly ShaderInstance _shader;
|
||||||
|
|
||||||
|
// Gas overlays
|
||||||
|
private readonly float[] _timer;
|
||||||
|
private readonly float[][] _frameDelays;
|
||||||
|
private readonly int[] _frameCounter;
|
||||||
|
|
||||||
|
// TODO combine textures into a single texture atlas.
|
||||||
|
private readonly Texture[][] _frames;
|
||||||
|
|
||||||
|
// Fire overlays
|
||||||
|
private const int FireStates = 3;
|
||||||
|
private const string FireRsiPath = "/Textures/Effects/fire.rsi";
|
||||||
|
|
||||||
|
private readonly float[] _fireTimer = new float[FireStates];
|
||||||
|
private readonly float[][] _fireFrameDelays = new float[FireStates][];
|
||||||
|
private readonly int[] _fireFrameCounter = new int[FireStates];
|
||||||
|
private readonly Texture[][] _fireFrames = new Texture[FireStates][];
|
||||||
|
|
||||||
|
private int _gasCount;
|
||||||
|
|
||||||
|
public const int GasOverlayZIndex = (int) Shared.DrawDepth.DrawDepth.Effects; // Under ghosts, above mostly everything else
|
||||||
|
|
||||||
|
public GasTileOverlay(GasTileOverlaySystem system, IEntityManager entManager, IResourceCache resourceCache, IPrototypeManager protoMan, SpriteSystem spriteSys, SharedTransformSystem xformSys)
|
||||||
|
{
|
||||||
|
_entManager = entManager;
|
||||||
|
_mapManager = IoCManager.Resolve<IMapManager>();
|
||||||
|
_atmosphereSystem = entManager.System<SharedAtmosphereSystem>();
|
||||||
|
_mapSystem = entManager.System<SharedMapSystem>();
|
||||||
|
_xformSys = xformSys;
|
||||||
|
_shader = protoMan.Index(UnshadedShader).Instance();
|
||||||
|
ZIndex = GasOverlayZIndex;
|
||||||
|
|
||||||
|
_gasCount = system.VisibleGasId.Length;
|
||||||
|
_timer = new float[_gasCount];
|
||||||
|
_frameDelays = new float[_gasCount][];
|
||||||
|
_frameCounter = new int[_gasCount];
|
||||||
|
_frames = new Texture[_gasCount][];
|
||||||
|
|
||||||
|
for (var i = 0; i < _gasCount; i++)
|
||||||
|
{
|
||||||
|
var gasPrototype = _atmosphereSystem.GetGas(system.VisibleGasId[i]);
|
||||||
|
|
||||||
|
SpriteSpecifier overlay;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(gasPrototype.GasOverlaySprite) && !string.IsNullOrEmpty(gasPrototype.GasOverlayState))
|
||||||
|
overlay = new SpriteSpecifier.Rsi(new (gasPrototype.GasOverlaySprite), gasPrototype.GasOverlayState);
|
||||||
|
else if (!string.IsNullOrEmpty(gasPrototype.GasOverlayTexture))
|
||||||
|
overlay = new SpriteSpecifier.Texture(new (gasPrototype.GasOverlayTexture));
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (overlay)
|
||||||
|
{
|
||||||
|
case SpriteSpecifier.Rsi animated:
|
||||||
|
var rsi = resourceCache.GetResource<RSIResource>(animated.RsiPath).RSI;
|
||||||
|
var stateId = animated.RsiState;
|
||||||
|
|
||||||
|
if (!rsi.TryGetState(stateId, out var state))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_frames[i] = state.GetFrames(RsiDirection.South);
|
||||||
|
_frameDelays[i] = state.GetDelays();
|
||||||
|
_frameCounter[i] = 0;
|
||||||
|
break;
|
||||||
|
case SpriteSpecifier.Texture texture:
|
||||||
|
_frames[i] = new[] { spriteSys.Frame0(texture) };
|
||||||
|
_frameDelays[i] = Array.Empty<float>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var fire = resourceCache.GetResource<RSIResource>(FireRsiPath).RSI;
|
||||||
|
|
||||||
|
for (var i = 0; i < FireStates; i++)
|
||||||
|
{
|
||||||
|
if (!fire.TryGetState((i + 1).ToString(), out var state))
|
||||||
|
throw new ArgumentOutOfRangeException($"Fire RSI doesn't have state \"{i}\"!");
|
||||||
|
|
||||||
|
_fireFrames[i] = state.GetFrames(RsiDirection.South);
|
||||||
|
_fireFrameDelays[i] = state.GetDelays();
|
||||||
|
_fireFrameCounter[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected override void FrameUpdate(FrameEventArgs args)
|
||||||
|
{
|
||||||
|
base.FrameUpdate(args);
|
||||||
|
|
||||||
|
for (var i = 0; i < _gasCount; i++)
|
||||||
|
{
|
||||||
|
var delays = _frameDelays[i];
|
||||||
|
if (delays.Length == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var frameCount = _frameCounter[i];
|
||||||
|
_timer[i] += args.DeltaSeconds;
|
||||||
|
var time = delays[frameCount];
|
||||||
|
|
||||||
|
if (_timer[i] < time)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_timer[i] -= time;
|
||||||
|
_frameCounter[i] = (frameCount + 1) % _frames[i].Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < FireStates; i++)
|
||||||
|
{
|
||||||
|
var delays = _fireFrameDelays[i];
|
||||||
|
if (delays.Length == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var frameCount = _fireFrameCounter[i];
|
||||||
|
_fireTimer[i] += args.DeltaSeconds;
|
||||||
|
var time = delays[frameCount];
|
||||||
|
|
||||||
|
if (_fireTimer[i] < time) continue;
|
||||||
|
_fireTimer[i] -= time;
|
||||||
|
_fireFrameCounter[i] = (frameCount + 1) % _fireFrames[i].Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Draw(in OverlayDrawArgs args)
|
||||||
|
{
|
||||||
|
if (args.MapId == MapId.Nullspace)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var drawHandle = args.WorldHandle;
|
||||||
|
var xformQuery = _entManager.GetEntityQuery<TransformComponent>();
|
||||||
|
var overlayQuery = _entManager.GetEntityQuery<GasTileOverlayComponent>();
|
||||||
|
var gridState = (args.WorldBounds,
|
||||||
|
args.WorldHandle,
|
||||||
|
_gasCount,
|
||||||
|
_frames,
|
||||||
|
_frameCounter,
|
||||||
|
_fireFrames,
|
||||||
|
_fireFrameCounter,
|
||||||
|
_shader,
|
||||||
|
overlayQuery,
|
||||||
|
xformQuery,
|
||||||
|
_xformSys);
|
||||||
|
|
||||||
|
var mapUid = _mapSystem.GetMapOrInvalid(args.MapId);
|
||||||
|
|
||||||
|
if (_entManager.TryGetComponent<MapAtmosphereComponent>(mapUid, out var atmos))
|
||||||
|
DrawMapOverlay(drawHandle, args, mapUid, atmos);
|
||||||
|
|
||||||
|
if (args.Space != OverlaySpace.WorldSpaceEntities)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: WorldBounds callback.
|
||||||
|
_mapManager.FindGridsIntersecting(args.MapId, args.WorldAABB, ref gridState,
|
||||||
|
static (EntityUid uid, MapGridComponent grid,
|
||||||
|
ref (Box2Rotated WorldBounds,
|
||||||
|
DrawingHandleWorld drawHandle,
|
||||||
|
int gasCount,
|
||||||
|
Texture[][] frames,
|
||||||
|
int[] frameCounter,
|
||||||
|
Texture[][] fireFrames,
|
||||||
|
int[] fireFrameCounter,
|
||||||
|
ShaderInstance shader,
|
||||||
|
EntityQuery<GasTileOverlayComponent> overlayQuery,
|
||||||
|
EntityQuery<TransformComponent> xformQuery,
|
||||||
|
SharedTransformSystem xformSys) state) =>
|
||||||
|
{
|
||||||
|
if (!state.overlayQuery.TryGetComponent(uid, out var comp) ||
|
||||||
|
!state.xformQuery.TryGetComponent(uid, out var gridXform))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var (_, _, worldMatrix, invMatrix) = state.xformSys.GetWorldPositionRotationMatrixWithInv(gridXform);
|
||||||
|
state.drawHandle.SetTransform(worldMatrix);
|
||||||
|
var floatBounds = invMatrix.TransformBox(state.WorldBounds).Enlarged(grid.TileSize);
|
||||||
|
var localBounds = new Box2i(
|
||||||
|
(int) MathF.Floor(floatBounds.Left),
|
||||||
|
(int) MathF.Floor(floatBounds.Bottom),
|
||||||
|
(int) MathF.Ceiling(floatBounds.Right),
|
||||||
|
(int) MathF.Ceiling(floatBounds.Top));
|
||||||
|
|
||||||
|
// Currently it would be faster to group drawing by gas rather than by chunk, but if the textures are
|
||||||
|
// ever moved to a single atlas, that should no longer be the case. So this is just grouping draw calls
|
||||||
|
// by chunk, even though its currently slower.
|
||||||
|
|
||||||
|
state.drawHandle.UseShader(null);
|
||||||
|
foreach (var chunk in comp.Chunks.Values)
|
||||||
|
{
|
||||||
|
var enumerator = new GasChunkEnumerator(chunk);
|
||||||
|
|
||||||
|
while (enumerator.MoveNext(out var gas))
|
||||||
|
{
|
||||||
|
if (gas.Opacity == null!)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var tilePosition = chunk.Origin + (enumerator.X, enumerator.Y);
|
||||||
|
if (!localBounds.Contains(tilePosition))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (var i = 0; i < state.gasCount; i++)
|
||||||
|
{
|
||||||
|
var opacity = gas.Opacity[i];
|
||||||
|
if (opacity > 0)
|
||||||
|
state.drawHandle.DrawTexture(state.frames[i][state.frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// And again for fire, with the unshaded shader
|
||||||
|
state.drawHandle.UseShader(state.shader);
|
||||||
|
foreach (var chunk in comp.Chunks.Values)
|
||||||
|
{
|
||||||
|
var enumerator = new GasChunkEnumerator(chunk);
|
||||||
|
|
||||||
|
while (enumerator.MoveNext(out var gas))
|
||||||
|
{
|
||||||
|
if (gas.FireState == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var index = chunk.Origin + (enumerator.X, enumerator.Y);
|
||||||
|
if (!localBounds.Contains(index))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var fireState = gas.FireState - 1;
|
||||||
|
var texture = state.fireFrames[fireState][state.fireFrameCounter[fireState]];
|
||||||
|
state.drawHandle.DrawTexture(texture, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
drawHandle.UseShader(null);
|
||||||
|
drawHandle.SetTransform(Matrix3x2.Identity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawMapOverlay(
|
||||||
|
DrawingHandleWorld handle,
|
||||||
|
OverlayDrawArgs args,
|
||||||
|
EntityUid map,
|
||||||
|
MapAtmosphereComponent atmos)
|
||||||
|
{
|
||||||
|
var mapGrid = _entManager.HasComponent<MapGridComponent>(map);
|
||||||
|
|
||||||
|
// map-grid atmospheres get drawn above grids
|
||||||
|
if (mapGrid && args.Space != OverlaySpace.WorldSpaceEntities)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Normal map atmospheres get drawn below grids
|
||||||
|
if (!mapGrid && args.Space != OverlaySpace.WorldSpaceBelowWorld)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var bottomLeft = args.WorldAABB.BottomLeft.Floored();
|
||||||
|
var topRight = args.WorldAABB.TopRight.Ceiled();
|
||||||
|
|
||||||
|
for (var x = bottomLeft.X; x <= topRight.X; x++)
|
||||||
|
{
|
||||||
|
for (var y = bottomLeft.Y; y <= topRight.Y; y++)
|
||||||
|
{
|
||||||
|
var tilePosition = new Vector2(x, y);
|
||||||
|
|
||||||
|
for (var i = 0; i < atmos.OverlayData.Opacity.Length; i++)
|
||||||
|
{
|
||||||
|
var opacity = atmos.OverlayData.Opacity[i];
|
||||||
|
|
||||||
|
if (opacity > 0)
|
||||||
|
handle.DrawTexture(_frames[i][_frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,248 +0,0 @@
|
|||||||
using Content.Client.Atmos.Components;
|
|
||||||
using Content.Shared.Atmos;
|
|
||||||
using Content.Shared.Atmos.Components;
|
|
||||||
using Content.Shared.Atmos.EntitySystems;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Client.ResourceManagement;
|
|
||||||
using Robust.Shared.Enums;
|
|
||||||
using Robust.Shared.Graphics.RSI;
|
|
||||||
using Robust.Shared.Map;
|
|
||||||
using Robust.Shared.Map.Components;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Timing;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
using System.Numerics;
|
|
||||||
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
|
|
||||||
|
|
||||||
namespace Content.Client.Atmos.Overlays;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Overlay responsible for rendering visible atmos gasses (like plasma for example) usin.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class GasTileVisibleGasOverlay : Overlay
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
|
||||||
[Dependency] private readonly IResourceCache _resourceCache = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
|
||||||
|
|
||||||
private static readonly ProtoId<ShaderPrototype> UnshadedShader = "unshaded";
|
|
||||||
|
|
||||||
private readonly SharedAtmosphereSystem _atmosphereSystem;
|
|
||||||
private readonly SharedMapSystem _mapSystem;
|
|
||||||
private readonly SharedTransformSystem _xformSys;
|
|
||||||
private readonly SharedGasTileOverlaySystem _gasTileOverlaySystem;
|
|
||||||
private readonly SpriteSystem _spriteSystem;
|
|
||||||
|
|
||||||
public override OverlaySpace Space => OverlaySpace.WorldSpaceEntities | OverlaySpace.WorldSpaceBelowWorld;
|
|
||||||
private readonly ShaderInstance _shader;
|
|
||||||
|
|
||||||
// Gas overlays
|
|
||||||
private readonly float[] _timer;
|
|
||||||
private readonly float[][] _frameDelays;
|
|
||||||
private readonly int[] _frameCounter;
|
|
||||||
|
|
||||||
// TODO combine textures into a single texture atlas.
|
|
||||||
private readonly Texture[][] _frames;
|
|
||||||
|
|
||||||
private readonly int _gasCount;
|
|
||||||
|
|
||||||
public const int GasOverlayZIndex = (int)DrawDepth.Gasses; // Under ghosts and fire, above mostly everything else
|
|
||||||
|
|
||||||
public GasTileVisibleGasOverlay()
|
|
||||||
{
|
|
||||||
IoCManager.InjectDependencies(this);
|
|
||||||
_atmosphereSystem = _entManager.System<SharedAtmosphereSystem>();
|
|
||||||
_mapSystem = _entManager.System<SharedMapSystem>();
|
|
||||||
_xformSys = _entManager.System<SharedTransformSystem>();
|
|
||||||
_gasTileOverlaySystem = _entManager.System<SharedGasTileOverlaySystem>();
|
|
||||||
_spriteSystem = _entManager.System<SpriteSystem>();
|
|
||||||
|
|
||||||
_shader = _protoManager.Index(UnshadedShader).Instance();
|
|
||||||
ZIndex = GasOverlayZIndex;
|
|
||||||
|
|
||||||
_gasCount = _gasTileOverlaySystem.VisibleGasId.Length;
|
|
||||||
_timer = new float[_gasCount];
|
|
||||||
_frameDelays = new float[_gasCount][];
|
|
||||||
_frameCounter = new int[_gasCount];
|
|
||||||
_frames = new Texture[_gasCount][];
|
|
||||||
|
|
||||||
for (var i = 0; i < _gasCount; i++)
|
|
||||||
{
|
|
||||||
var gasPrototype = _atmosphereSystem.GetGas(_gasTileOverlaySystem.VisibleGasId[i]);
|
|
||||||
|
|
||||||
switch (gasPrototype.GasOverlaySprite)
|
|
||||||
{
|
|
||||||
case SpriteSpecifier.Rsi animated:
|
|
||||||
var rsi = _resourceCache.GetResource<RSIResource>(animated.RsiPath).RSI;
|
|
||||||
var stateId = animated.RsiState;
|
|
||||||
|
|
||||||
if (!rsi.TryGetState(stateId, out var state))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_frames[i] = state.GetFrames(RsiDirection.South);
|
|
||||||
_frameDelays[i] = state.GetDelays();
|
|
||||||
_frameCounter[i] = 0;
|
|
||||||
break;
|
|
||||||
case SpriteSpecifier.Texture texture:
|
|
||||||
_frames[i] = new[] { _spriteSystem.Frame0(texture) };
|
|
||||||
_frameDelays[i] = Array.Empty<float>();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void FrameUpdate(FrameEventArgs args)
|
|
||||||
{
|
|
||||||
base.FrameUpdate(args);
|
|
||||||
|
|
||||||
for (var i = 0; i < _gasCount; i++)
|
|
||||||
{
|
|
||||||
var delays = _frameDelays[i];
|
|
||||||
if (delays.Length == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var frameCount = _frameCounter[i];
|
|
||||||
_timer[i] += args.DeltaSeconds;
|
|
||||||
var time = delays[frameCount];
|
|
||||||
|
|
||||||
if (_timer[i] < time)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_timer[i] -= time;
|
|
||||||
_frameCounter[i] = (frameCount + 1) % _frames[i].Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Draw(in OverlayDrawArgs args)
|
|
||||||
{
|
|
||||||
if (args.MapId == MapId.Nullspace)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var drawHandle = args.WorldHandle;
|
|
||||||
var xformQuery = _entManager.GetEntityQuery<TransformComponent>();
|
|
||||||
var overlayQuery = _entManager.GetEntityQuery<GasTileOverlayComponent>();
|
|
||||||
var gridState = (args.WorldBounds,
|
|
||||||
args.WorldHandle,
|
|
||||||
_gasCount,
|
|
||||||
_frames,
|
|
||||||
_frameCounter,
|
|
||||||
_shader,
|
|
||||||
overlayQuery,
|
|
||||||
xformQuery,
|
|
||||||
_xformSys);
|
|
||||||
|
|
||||||
var mapUid = _mapSystem.GetMapOrInvalid(args.MapId);
|
|
||||||
|
|
||||||
if (_entManager.TryGetComponent<MapAtmosphereComponent>(mapUid, out var atmos))
|
|
||||||
DrawMapOverlay(drawHandle, args, mapUid, atmos);
|
|
||||||
|
|
||||||
if (args.Space != OverlaySpace.WorldSpaceEntities)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// TODO: WorldBounds callback.
|
|
||||||
_mapManager.FindGridsIntersecting(args.MapId,
|
|
||||||
args.WorldAABB,
|
|
||||||
ref gridState,
|
|
||||||
static (EntityUid uid,
|
|
||||||
MapGridComponent grid,
|
|
||||||
ref (Box2Rotated WorldBounds,
|
|
||||||
DrawingHandleWorld drawHandle,
|
|
||||||
int gasCount,
|
|
||||||
Texture[][] frames,
|
|
||||||
int[] frameCounter,
|
|
||||||
ShaderInstance shader,
|
|
||||||
EntityQuery<GasTileOverlayComponent> overlayQuery,
|
|
||||||
EntityQuery<TransformComponent> xformQuery,
|
|
||||||
SharedTransformSystem xformSys) state) =>
|
|
||||||
{
|
|
||||||
if (!state.overlayQuery.TryGetComponent(uid, out var comp) ||
|
|
||||||
!state.xformQuery.TryGetComponent(uid, out var gridXform))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var (_, _, worldMatrix, invMatrix) = state.xformSys.GetWorldPositionRotationMatrixWithInv(gridXform);
|
|
||||||
state.drawHandle.SetTransform(worldMatrix);
|
|
||||||
var floatBounds = invMatrix.TransformBox(state.WorldBounds).Enlarged(grid.TileSize);
|
|
||||||
var localBounds = new Box2i(
|
|
||||||
(int)MathF.Floor(floatBounds.Left),
|
|
||||||
(int)MathF.Floor(floatBounds.Bottom),
|
|
||||||
(int)MathF.Ceiling(floatBounds.Right),
|
|
||||||
(int)MathF.Ceiling(floatBounds.Top));
|
|
||||||
|
|
||||||
// Currently it would be faster to group drawing by gas rather than by chunk, but if the textures are
|
|
||||||
// ever moved to a single atlas, that should no longer be the case. So this is just grouping draw calls
|
|
||||||
// by chunk, even though its currently slower.
|
|
||||||
|
|
||||||
state.drawHandle.UseShader(null);
|
|
||||||
foreach (var chunk in comp.Chunks.Values)
|
|
||||||
{
|
|
||||||
var enumerator = new GasChunkEnumerator(chunk);
|
|
||||||
|
|
||||||
while (enumerator.MoveNext(out var gas))
|
|
||||||
{
|
|
||||||
if (gas.Opacity == null!)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var tilePosition = chunk.Origin + (enumerator.X, enumerator.Y);
|
|
||||||
if (!localBounds.Contains(tilePosition))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (var i = 0; i < state.gasCount; i++)
|
|
||||||
{
|
|
||||||
var opacity = gas.Opacity[i];
|
|
||||||
if (opacity > 0)
|
|
||||||
{
|
|
||||||
state.drawHandle.DrawTexture(state.frames[i][state.frameCounter[i]],
|
|
||||||
tilePosition,
|
|
||||||
Color.White.WithAlpha(opacity));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
drawHandle.UseShader(null);
|
|
||||||
drawHandle.SetTransform(Matrix3x2.Identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawMapOverlay(
|
|
||||||
DrawingHandleWorld handle,
|
|
||||||
OverlayDrawArgs args,
|
|
||||||
EntityUid map,
|
|
||||||
MapAtmosphereComponent atmos)
|
|
||||||
{
|
|
||||||
var mapGrid = _entManager.HasComponent<MapGridComponent>(map);
|
|
||||||
|
|
||||||
// map-grid atmospheres get drawn above grids
|
|
||||||
if (mapGrid && args.Space != OverlaySpace.WorldSpaceEntities)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Normal map atmospheres get drawn below grids
|
|
||||||
if (!mapGrid && args.Space != OverlaySpace.WorldSpaceBelowWorld)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var bottomLeft = args.WorldAABB.BottomLeft.Floored();
|
|
||||||
var topRight = args.WorldAABB.TopRight.Ceiled();
|
|
||||||
|
|
||||||
for (var x = bottomLeft.X; x <= topRight.X; x++)
|
|
||||||
{
|
|
||||||
for (var y = bottomLeft.Y; y <= topRight.Y; y++)
|
|
||||||
{
|
|
||||||
var tilePosition = new Vector2(x, y);
|
|
||||||
|
|
||||||
for (var i = 0; i < atmos.OverlayData.Opacity.Length; i++)
|
|
||||||
{
|
|
||||||
var opacity = atmos.OverlayData.Opacity[i];
|
|
||||||
|
|
||||||
if (opacity > 0)
|
|
||||||
handle.DrawTexture(_frames[i][_frameCounter[i]], tilePosition, Color.White.WithAlpha(opacity));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +1,41 @@
|
|||||||
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Content.Shared.Atmos.Components;
|
using static Content.Shared.Atmos.Components.GasAnalyzerComponent;
|
||||||
|
|
||||||
namespace Content.Client.Atmos.UI;
|
namespace Content.Client.Atmos.UI
|
||||||
|
|
||||||
public sealed class GasAnalyzerBoundUserInterface : BoundUserInterface
|
|
||||||
{
|
{
|
||||||
[ViewVariables]
|
public sealed class GasAnalyzerBoundUserInterface : BoundUserInterface
|
||||||
private GasAnalyzerWindow? _window;
|
|
||||||
|
|
||||||
public GasAnalyzerBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
|
||||||
{
|
{
|
||||||
}
|
[ViewVariables]
|
||||||
|
private GasAnalyzerWindow? _window;
|
||||||
|
|
||||||
protected override void Open()
|
public GasAnalyzerBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||||
{
|
{
|
||||||
base.Open();
|
}
|
||||||
|
|
||||||
_window = this.CreateWindowCenteredLeft<GasAnalyzerWindow>();
|
protected override void Open()
|
||||||
_window.OnClose += Close;
|
{
|
||||||
}
|
base.Open();
|
||||||
|
|
||||||
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
|
_window = this.CreateWindowCenteredLeft<GasAnalyzerWindow>();
|
||||||
{
|
_window.OnClose += Close;
|
||||||
if (_window == null)
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
if (message is not GasAnalyzerUserMessage cast)
|
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
|
||||||
return;
|
{
|
||||||
|
if (_window == null)
|
||||||
|
return;
|
||||||
|
if (message is not GasAnalyzerUserMessage cast)
|
||||||
|
return;
|
||||||
|
_window.Populate(cast);
|
||||||
|
}
|
||||||
|
|
||||||
_window.Populate(cast);
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
base.Dispose(disposing);
|
||||||
|
|
||||||
|
if (disposing)
|
||||||
|
_window?.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Client.UserInterface.Controls;
|
using Content.Client.UserInterface.Controls;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
using Content.Shared.Atmos.Components;
|
|
||||||
using Content.Shared.Atmos.EntitySystems;
|
|
||||||
using Content.Shared.Temperature;
|
using Content.Shared.Temperature;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
@@ -10,6 +8,7 @@ using Robust.Client.UserInterface.Controls;
|
|||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
|
using static Content.Shared.Atmos.Components.GasAnalyzerComponent;
|
||||||
using Direction = Robust.Shared.Maths.Direction;
|
using Direction = Robust.Shared.Maths.Direction;
|
||||||
|
|
||||||
namespace Content.Client.Atmos.UI
|
namespace Content.Client.Atmos.UI
|
||||||
@@ -17,17 +16,25 @@ namespace Content.Client.Atmos.UI
|
|||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class GasAnalyzerWindow : DefaultWindow
|
public sealed partial class GasAnalyzerWindow : DefaultWindow
|
||||||
{
|
{
|
||||||
private readonly SharedAtmosphereSystem _atmosphere;
|
|
||||||
private NetEntity _currentEntity = NetEntity.Invalid;
|
private NetEntity _currentEntity = NetEntity.Invalid;
|
||||||
|
|
||||||
public GasAnalyzerWindow()
|
public GasAnalyzerWindow()
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
_atmosphere = IoCManager.Resolve<IEntityManager>().System<SharedAtmosphereSystem>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Populate(GasAnalyzerUserMessage msg)
|
public void Populate(GasAnalyzerUserMessage msg)
|
||||||
{
|
{
|
||||||
|
if (msg.Error != null)
|
||||||
|
{
|
||||||
|
CTopBox.AddChild(new Label
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("gas-analyzer-window-error-text", ("errorText", msg.Error)),
|
||||||
|
FontColorOverride = Color.Red
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (msg.NodeGasMixes.Length == 0)
|
if (msg.NodeGasMixes.Length == 0)
|
||||||
{
|
{
|
||||||
CTopBox.AddChild(new Label
|
CTopBox.AddChild(new Label
|
||||||
@@ -322,31 +329,31 @@ namespace Content.Client.Atmos.UI
|
|||||||
|
|
||||||
for (var j = 0; j < gasMix.Gases.Length; j++)
|
for (var j = 0; j < gasMix.Gases.Length; j++)
|
||||||
{
|
{
|
||||||
var gasEntry = gasMix.Gases[j];
|
var gas = gasMix.Gases[j];
|
||||||
var gasProto = _atmosphere.GetGas(gasEntry.Gas);
|
var color = Color.FromHex($"#{gas.Color}", Color.White);
|
||||||
// Add to the table
|
// Add to the table
|
||||||
tableKey.AddChild(new Label
|
tableKey.AddChild(new Label
|
||||||
{
|
{
|
||||||
Text = Loc.GetString(gasProto.Name)
|
Text = Loc.GetString(gas.Name)
|
||||||
});
|
});
|
||||||
tableVal.AddChild(new Label
|
tableVal.AddChild(new Label
|
||||||
{
|
{
|
||||||
Text = Loc.GetString("gas-analyzer-window-molarity-text",
|
Text = Loc.GetString("gas-analyzer-window-molarity-text",
|
||||||
("mol", $"{gasEntry.Amount:0.00}")),
|
("mol", $"{gas.Amount:0.00}")),
|
||||||
Align = Label.AlignMode.Right,
|
Align = Label.AlignMode.Right,
|
||||||
});
|
});
|
||||||
tablePercent.AddChild(new Label
|
tablePercent.AddChild(new Label
|
||||||
{
|
{
|
||||||
Text = Loc.GetString("gas-analyzer-window-percentage-text",
|
Text = Loc.GetString("gas-analyzer-window-percentage-text",
|
||||||
("percentage", $"{(gasEntry.Amount / totalGasAmount * 100):0.0}")),
|
("percentage", $"{(gas.Amount / totalGasAmount * 100):0.0}")),
|
||||||
Align = Label.AlignMode.Right
|
Align = Label.AlignMode.Right
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add to the gas bar //TODO: highlight the currently hover one
|
// Add to the gas bar //TODO: highlight the currently hover one
|
||||||
gasBar.AddEntry(gasEntry.Amount, gasProto.Color, tooltip: Loc.GetString("gas-analyzer-window-molarity-percentage-text",
|
gasBar.AddEntry(gas.Amount, color, tooltip: Loc.GetString("gas-analyzer-window-molarity-percentage-text",
|
||||||
("gasName", Loc.GetString(gasProto.Name)),
|
("gasName", gas.Name),
|
||||||
("amount", $"{gasEntry.Amount:0.##}"),
|
("amount", $"{gas.Amount:0.##}"),
|
||||||
("percentage", $"{(gasEntry.Amount / totalGasAmount * 100):0.#}")));
|
("percentage", $"{(gas.Amount / totalGasAmount * 100):0.#}")));
|
||||||
}
|
}
|
||||||
|
|
||||||
dataContainer.AddChild(gasBar);
|
dataContainer.AddChild(gasBar);
|
||||||
|
|||||||
@@ -37,9 +37,10 @@ namespace Content.Client.Atmos.UI
|
|||||||
_window.SelectGasPressed += OnSelectGasPressed;
|
_window.SelectGasPressed += OnSelectGasPressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnToggleStatusButtonPressed(bool status)
|
private void OnToggleStatusButtonPressed()
|
||||||
{
|
{
|
||||||
SendMessage(new GasFilterToggleStatusMessage(status));
|
if (_window is null) return;
|
||||||
|
SendMessage(new GasFilterToggleStatusMessage(_window.FilterStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnFilterTransferRatePressed(string value)
|
private void OnFilterTransferRatePressed(string value)
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
<DefaultWindow xmlns="https://spacestation14.io"
|
<DefaultWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
|
||||||
MinSize="480 400" Title="Filter">
|
MinSize="480 400" Title="Filter">
|
||||||
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
||||||
<controls:SwitchButton
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
Name="ToggleStatusButton"
|
<Label Text="{Loc comp-gas-filter-ui-filter-status}"/>
|
||||||
HorizontalAlignment="Left"
|
<Button Name="ToggleStatusButton"/>
|
||||||
Pressed="True" />
|
</BoxContainer>
|
||||||
|
|
||||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
<Label Text="{Loc comp-gas-filter-ui-filter-transfer-rate}"/>
|
<Label Text="{Loc comp-gas-filter-ui-filter-transfer-rate}"/>
|
||||||
|
|||||||
@@ -18,10 +18,11 @@ namespace Content.Client.Atmos.UI
|
|||||||
{
|
{
|
||||||
private readonly ButtonGroup _buttonGroup = new();
|
private readonly ButtonGroup _buttonGroup = new();
|
||||||
|
|
||||||
|
public bool FilterStatus = true;
|
||||||
public string? SelectedGas;
|
public string? SelectedGas;
|
||||||
public string? CurrentGasId;
|
public string? CurrentGasId;
|
||||||
|
|
||||||
public event Action<bool>? ToggleStatusButtonPressed;
|
public event Action? ToggleStatusButtonPressed;
|
||||||
public event Action<string>? FilterTransferRateChanged;
|
public event Action<string>? FilterTransferRateChanged;
|
||||||
public event Action? SelectGasPressed;
|
public event Action? SelectGasPressed;
|
||||||
|
|
||||||
@@ -29,7 +30,8 @@ namespace Content.Client.Atmos.UI
|
|||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
|
|
||||||
ToggleStatusButton.OnToggled += _ => ToggleStatusButtonPressed?.Invoke(ToggleStatusButton.Pressed);
|
ToggleStatusButton.OnPressed += _ => SetFilterStatus(!FilterStatus);
|
||||||
|
ToggleStatusButton.OnPressed += _ => ToggleStatusButtonPressed?.Invoke();
|
||||||
|
|
||||||
FilterTransferRateInput.OnTextChanged += _ => SetFilterRate.Disabled = false;
|
FilterTransferRateInput.OnTextChanged += _ => SetFilterRate.Disabled = false;
|
||||||
SetFilterRate.OnPressed += _ =>
|
SetFilterRate.OnPressed += _ =>
|
||||||
@@ -51,7 +53,15 @@ namespace Content.Client.Atmos.UI
|
|||||||
|
|
||||||
public void SetFilterStatus(bool enabled)
|
public void SetFilterStatus(bool enabled)
|
||||||
{
|
{
|
||||||
ToggleStatusButton.Pressed = enabled;
|
FilterStatus = enabled;
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
ToggleStatusButton.Text = Loc.GetString("comp-gas-filter-ui-status-enabled");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ToggleStatusButton.Text = Loc.GetString("comp-gas-filter-ui-status-disabled");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetGasFiltered(string? id, string name)
|
public void SetGasFiltered(string? id, string name)
|
||||||
|
|||||||
@@ -33,9 +33,10 @@ namespace Content.Client.Atmos.UI
|
|||||||
_window.MixerNodePercentageChanged += OnMixerSetPercentagePressed;
|
_window.MixerNodePercentageChanged += OnMixerSetPercentagePressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnToggleStatusButtonPressed(bool status)
|
private void OnToggleStatusButtonPressed()
|
||||||
{
|
{
|
||||||
SendMessage(new GasMixerToggleStatusMessage(status));
|
if (_window is null) return;
|
||||||
|
SendMessage(new GasMixerToggleStatusMessage(_window.MixerStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMixerOutputPressurePressed(string value)
|
private void OnMixerOutputPressurePressed(string value)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<DefaultWindow xmlns="https://spacestation14.io"
|
<DefaultWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
|
||||||
MinSize="200 200" Title="Gas Mixer">
|
MinSize="200 200" Title="Gas Mixer">
|
||||||
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
||||||
<controls:SwitchButton
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
Name="ToggleStatusButton"
|
<Label Text="{Loc comp-gas-mixer-ui-mixer-status}"/>
|
||||||
HorizontalAlignment="Left"
|
<Control MinSize="5 0" />
|
||||||
Pressed="True" />
|
<Button Name="ToggleStatusButton"/>
|
||||||
|
</BoxContainer>
|
||||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
<Label Text="{Loc comp-gas-mixer-ui-mixer-output-pressure}"/>
|
<Label Text="{Loc comp-gas-mixer-ui-mixer-output-pressure}"/>
|
||||||
<Control MinSize="5 0" />
|
<Control MinSize="5 0" />
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ namespace Content.Client.Atmos.UI
|
|||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class GasMixerWindow : DefaultWindow
|
public sealed partial class GasMixerWindow : DefaultWindow
|
||||||
{
|
{
|
||||||
public event Action<bool>? ToggleStatusButtonPressed;
|
public bool MixerStatus = true;
|
||||||
|
|
||||||
|
public event Action? ToggleStatusButtonPressed;
|
||||||
public event Action<string>? MixerOutputPressureChanged;
|
public event Action<string>? MixerOutputPressureChanged;
|
||||||
public event Action<string>? MixerNodePercentageChanged;
|
public event Action<string>? MixerNodePercentageChanged;
|
||||||
|
|
||||||
@@ -31,7 +33,8 @@ namespace Content.Client.Atmos.UI
|
|||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
|
|
||||||
ToggleStatusButton.OnToggled += _ => ToggleStatusButtonPressed?.Invoke(ToggleStatusButton.Pressed);
|
ToggleStatusButton.OnPressed += _ => SetMixerStatus(!MixerStatus);
|
||||||
|
ToggleStatusButton.OnPressed += _ => ToggleStatusButtonPressed?.Invoke();
|
||||||
|
|
||||||
MixerPressureOutputInput.OnTextChanged += _ => SetOutputPressureButton.Disabled = false;
|
MixerPressureOutputInput.OnTextChanged += _ => SetOutputPressureButton.Disabled = false;
|
||||||
SetOutputPressureButton.OnPressed += _ =>
|
SetOutputPressureButton.OnPressed += _ =>
|
||||||
@@ -80,7 +83,15 @@ namespace Content.Client.Atmos.UI
|
|||||||
|
|
||||||
public void SetMixerStatus(bool enabled)
|
public void SetMixerStatus(bool enabled)
|
||||||
{
|
{
|
||||||
ToggleStatusButton.Pressed = enabled;
|
MixerStatus = enabled;
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
ToggleStatusButton.Text = Loc.GetString("comp-gas-mixer-ui-status-enabled");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ToggleStatusButton.Text = Loc.GetString("comp-gas-mixer-ui-status-disabled");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,9 +42,12 @@ public sealed class GasPressurePumpBoundUserInterface(EntityUid owner, Enum uiKe
|
|||||||
_window.SetOutputPressure(pump.TargetPressure);
|
_window.SetOutputPressure(pump.TargetPressure);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnToggleStatusButtonPressed(bool status)
|
private void OnToggleStatusButtonPressed()
|
||||||
{
|
{
|
||||||
SendPredictedMessage(new GasPressurePumpToggleStatusMessage(status));
|
if (_window is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SendPredictedMessage(new GasPressurePumpToggleStatusMessage(_window.PumpStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPumpOutputPressurePressed(float value)
|
private void OnPumpOutputPressurePressed(float value)
|
||||||
|
|||||||
@@ -4,10 +4,8 @@
|
|||||||
SetSize="340 110" MinSize="340 110" Title="Pressure Pump">
|
SetSize="340 110" MinSize="340 110" Title="Pressure Pump">
|
||||||
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
||||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
<controls:SwitchButton
|
<Label Text="{Loc comp-gas-pump-ui-pump-status}" Margin="0 0 5 0"/>
|
||||||
Name="ToggleStatusButton"
|
<Button Name="ToggleStatusButton"/>
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Pressed="True" />
|
|
||||||
<Control HorizontalExpand="True"/>
|
<Control HorizontalExpand="True"/>
|
||||||
<Button HorizontalAlignment="Right" Name="SetOutputPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-rate}" Disabled="True" Margin="0 0 5 0"/>
|
<Button HorizontalAlignment="Right" Name="SetOutputPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-rate}" Disabled="True" Margin="0 0 5 0"/>
|
||||||
<Button Name="SetMaxPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-max}" />
|
<Button Name="SetMaxPressureButton" Text="{Loc comp-gas-pump-ui-pump-set-max}" />
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ namespace Content.Client.Atmos.UI
|
|||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class GasPressurePumpWindow : FancyWindow
|
public sealed partial class GasPressurePumpWindow : FancyWindow
|
||||||
{
|
{
|
||||||
public event Action<bool>? ToggleStatusButtonPressed;
|
public bool PumpStatus = true;
|
||||||
|
|
||||||
|
public event Action? ToggleStatusButtonPressed;
|
||||||
public event Action<float>? PumpOutputPressureChanged;
|
public event Action<float>? PumpOutputPressureChanged;
|
||||||
|
|
||||||
public float MaxPressure
|
public float MaxPressure
|
||||||
@@ -31,7 +33,8 @@ namespace Content.Client.Atmos.UI
|
|||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
|
|
||||||
ToggleStatusButton.OnToggled += _ => ToggleStatusButtonPressed?.Invoke(ToggleStatusButton.Pressed);
|
ToggleStatusButton.OnPressed += _ => SetPumpStatus(!PumpStatus);
|
||||||
|
ToggleStatusButton.OnPressed += _ => ToggleStatusButtonPressed?.Invoke();
|
||||||
|
|
||||||
PumpPressureOutputInput.OnValueChanged += _ => SetOutputPressureButton.Disabled = false;
|
PumpPressureOutputInput.OnValueChanged += _ => SetOutputPressureButton.Disabled = false;
|
||||||
|
|
||||||
@@ -56,7 +59,15 @@ namespace Content.Client.Atmos.UI
|
|||||||
|
|
||||||
public void SetPumpStatus(bool enabled)
|
public void SetPumpStatus(bool enabled)
|
||||||
{
|
{
|
||||||
ToggleStatusButton.Pressed = enabled;
|
PumpStatus = enabled;
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
ToggleStatusButton.Text = Loc.GetString("comp-gas-pump-ui-status-enabled");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ToggleStatusButton.Text = Loc.GetString("comp-gas-pump-ui-status-disabled");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace Content.Client.Atmos.UI
|
|||||||
|
|
||||||
_window = this.CreateWindow<GasThermomachineWindow>();
|
_window = this.CreateWindow<GasThermomachineWindow>();
|
||||||
|
|
||||||
_window.ToggleStatusButton.OnToggled += _ => OnToggleStatusButtonPressed();
|
_window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed();
|
||||||
_window.TemperatureSpinbox.OnValueChanged += _ => OnTemperatureChanged(_window.TemperatureSpinbox.Value);
|
_window.TemperatureSpinbox.OnValueChanged += _ => OnTemperatureChanged(_window.TemperatureSpinbox.Value);
|
||||||
_window.Entity = Owner;
|
_window.Entity = Owner;
|
||||||
Update();
|
Update();
|
||||||
@@ -45,6 +45,9 @@ namespace Content.Client.Atmos.UI
|
|||||||
|
|
||||||
private void OnToggleStatusButtonPressed()
|
private void OnToggleStatusButtonPressed()
|
||||||
{
|
{
|
||||||
|
if (_window is null) return;
|
||||||
|
|
||||||
|
_window.SetActive(!_window.Active);
|
||||||
SendPredictedMessage(new GasThermomachineToggleMessage());
|
SendPredictedMessage(new GasThermomachineToggleMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
MinSize="300 120" Title="{Loc comp-gas-thermomachine-ui-title-freezer}">
|
MinSize="300 120" Title="{Loc comp-gas-thermomachine-ui-title-freezer}">
|
||||||
<BoxContainer Name="VboxContainer" Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
<BoxContainer Name="VboxContainer" Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
||||||
<controls:SwitchButton
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
Name="ToggleStatusButton"
|
<Label Text="{Loc comp-gas-thermomachine-ui-toggle}"/>
|
||||||
HorizontalAlignment="Left"
|
<Control MinSize="5 0" />
|
||||||
Pressed="True"
|
<Button Access="Public" Name="ToggleStatusButton"/>
|
||||||
Access="Public" />
|
</BoxContainer>
|
||||||
<BoxContainer Name="SpinboxHBox" Orientation="Horizontal">
|
<BoxContainer Name="SpinboxHBox" Orientation="Horizontal">
|
||||||
<Label Text="{Loc comp-gas-thermomachine-ui-temperature}"/>
|
<Label Text="{Loc comp-gas-thermomachine-ui-temperature}"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ public sealed partial class GasThermomachineWindow : FancyWindow
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||||
|
|
||||||
|
public bool Active = true;
|
||||||
|
|
||||||
public FloatSpinBox TemperatureSpinbox;
|
public FloatSpinBox TemperatureSpinbox;
|
||||||
|
|
||||||
public EntityUid Entity;
|
public EntityUid Entity;
|
||||||
@@ -28,7 +30,15 @@ public sealed partial class GasThermomachineWindow : FancyWindow
|
|||||||
|
|
||||||
public void SetActive(bool active)
|
public void SetActive(bool active)
|
||||||
{
|
{
|
||||||
ToggleStatusButton.Pressed = active;
|
Active = active;
|
||||||
|
if (active)
|
||||||
|
{
|
||||||
|
ToggleStatusButton.Text = Loc.GetString("comp-gas-thermomachine-ui-status-enabled");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ToggleStatusButton.Text = Loc.GetString("comp-gas-thermomachine-ui-status-disabled");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTemperature(float temperature)
|
public void SetTemperature(float temperature)
|
||||||
|
|||||||
@@ -38,9 +38,11 @@ namespace Content.Client.Atmos.UI
|
|||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnToggleStatusButtonPressed(bool status)
|
private void OnToggleStatusButtonPressed()
|
||||||
{
|
{
|
||||||
SendPredictedMessage(new GasVolumePumpToggleStatusMessage(status));
|
if (_window is null) return;
|
||||||
|
|
||||||
|
SendPredictedMessage(new GasVolumePumpToggleStatusMessage(_window.PumpStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPumpTransferRatePressed(string value)
|
private void OnPumpTransferRatePressed(string value)
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
MinSize="200 120" Title="Volume Pump">
|
MinSize="200 120" Title="Volume Pump">
|
||||||
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
<BoxContainer Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
||||||
<controls:SwitchButton
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
Name="ToggleStatusButton"
|
<Label Text="{Loc comp-gas-pump-ui-pump-status}"/>
|
||||||
HorizontalAlignment="Left"
|
<Control MinSize="5 0" />
|
||||||
Pressed="True" />
|
<Button Name="ToggleStatusButton"/>
|
||||||
|
</BoxContainer>
|
||||||
|
|
||||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
<Label Text="{Loc comp-gas-pump-ui-pump-transfer-rate}"/>
|
<Label Text="{Loc comp-gas-pump-ui-pump-transfer-rate}"/>
|
||||||
|
|||||||
@@ -19,14 +19,17 @@ namespace Content.Client.Atmos.UI
|
|||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class GasVolumePumpWindow : FancyWindow
|
public sealed partial class GasVolumePumpWindow : FancyWindow
|
||||||
{
|
{
|
||||||
public event Action<bool>? ToggleStatusButtonPressed;
|
public bool PumpStatus = true;
|
||||||
|
|
||||||
|
public event Action? ToggleStatusButtonPressed;
|
||||||
public event Action<string>? PumpTransferRateChanged;
|
public event Action<string>? PumpTransferRateChanged;
|
||||||
|
|
||||||
public GasVolumePumpWindow()
|
public GasVolumePumpWindow()
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
|
|
||||||
ToggleStatusButton.OnToggled += _ => ToggleStatusButtonPressed?.Invoke(ToggleStatusButton.Pressed);
|
ToggleStatusButton.OnPressed += _ => SetPumpStatus(!PumpStatus);
|
||||||
|
ToggleStatusButton.OnPressed += _ => ToggleStatusButtonPressed?.Invoke();
|
||||||
|
|
||||||
PumpTransferRateInput.OnTextChanged += _ => SetTransferRateButton.Disabled = false;
|
PumpTransferRateInput.OnTextChanged += _ => SetTransferRateButton.Disabled = false;
|
||||||
SetTransferRateButton.OnPressed += _ =>
|
SetTransferRateButton.OnPressed += _ =>
|
||||||
@@ -49,7 +52,15 @@ namespace Content.Client.Atmos.UI
|
|||||||
|
|
||||||
public void SetPumpStatus(bool enabled)
|
public void SetPumpStatus(bool enabled)
|
||||||
{
|
{
|
||||||
ToggleStatusButton.Pressed = enabled;
|
PumpStatus = enabled;
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
ToggleStatusButton.Text = Loc.GetString("comp-gas-pump-ui-status-enabled");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ToggleStatusButton.Text = Loc.GetString("comp-gas-pump-ui-status-disabled");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public sealed class SpaceHeaterBoundUserInterface : BoundUserInterface
|
|||||||
|
|
||||||
_window = this.CreateWindow<SpaceHeaterWindow>();
|
_window = this.CreateWindow<SpaceHeaterWindow>();
|
||||||
|
|
||||||
_window.ToggleStatusButton.OnToggled += _ => OnToggleStatusButtonPressed();
|
_window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed();
|
||||||
_window.IncreaseTempRange.OnPressed += _ => OnTemperatureRangeChanged(_window.TemperatureChangeDelta);
|
_window.IncreaseTempRange.OnPressed += _ => OnTemperatureRangeChanged(_window.TemperatureChangeDelta);
|
||||||
_window.DecreaseTempRange.OnPressed += _ => OnTemperatureRangeChanged(-_window.TemperatureChangeDelta);
|
_window.DecreaseTempRange.OnPressed += _ => OnTemperatureRangeChanged(-_window.TemperatureChangeDelta);
|
||||||
_window.ModeSelector.OnItemSelected += OnModeChanged;
|
_window.ModeSelector.OnItemSelected += OnModeChanged;
|
||||||
@@ -34,6 +34,7 @@ public sealed class SpaceHeaterBoundUserInterface : BoundUserInterface
|
|||||||
|
|
||||||
private void OnToggleStatusButtonPressed()
|
private void OnToggleStatusButtonPressed()
|
||||||
{
|
{
|
||||||
|
_window?.SetActive(!_window.Active);
|
||||||
SendMessage(new SpaceHeaterToggleMessage());
|
SendMessage(new SpaceHeaterToggleMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
<DefaultWindow xmlns="https://spacestation14.io"
|
<DefaultWindow xmlns="https://spacestation14.io"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
|
||||||
MinSize="280 160" Title="{Loc comp-space-heater-ui-title}">
|
MinSize="280 160" Title="{Loc comp-space-heater-ui-title}">
|
||||||
|
|
||||||
<BoxContainer Name="VboxContainer" Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
<BoxContainer Name="VboxContainer" Orientation="Vertical" Margin="5 5 5 5" SeparationOverride="10">
|
||||||
|
|
||||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
<controls:SwitchButton
|
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||||
Name="ToggleStatusButton"
|
<Button Text="{Loc comp-space-heater-ui-status-disabled}" Access="Public" Name="ToggleStatusButton"/>
|
||||||
HorizontalExpand="True"
|
</BoxContainer>
|
||||||
Access="Public" />
|
|
||||||
<BoxContainer Orientation="Horizontal" SeparationOverride="5">
|
<BoxContainer Orientation="Horizontal" SeparationOverride="5">
|
||||||
<Label Text="{Loc comp-space-heater-ui-mode}"/>
|
<Label Text="{Loc comp-space-heater-ui-mode}"/>
|
||||||
<OptionButton Access="Public" Name="ModeSelector"/>
|
<OptionButton Access="Public" Name="ModeSelector"/>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public sealed partial class SpaceHeaterWindow : DefaultWindow
|
|||||||
{
|
{
|
||||||
// To account for a minimum delta temperature for atmos equalization to trigger we use a fixed step for target temperature increment/decrement
|
// To account for a minimum delta temperature for atmos equalization to trigger we use a fixed step for target temperature increment/decrement
|
||||||
public int TemperatureChangeDelta = 5;
|
public int TemperatureChangeDelta = 5;
|
||||||
|
public bool Active;
|
||||||
|
|
||||||
// Temperatures range bounds in Kelvin (K)
|
// Temperatures range bounds in Kelvin (K)
|
||||||
public float MinTemp;
|
public float MinTemp;
|
||||||
@@ -48,7 +49,17 @@ public sealed partial class SpaceHeaterWindow : DefaultWindow
|
|||||||
|
|
||||||
public void SetActive(bool active)
|
public void SetActive(bool active)
|
||||||
{
|
{
|
||||||
|
Active = active;
|
||||||
ToggleStatusButton.Pressed = active;
|
ToggleStatusButton.Pressed = active;
|
||||||
|
|
||||||
|
if (active)
|
||||||
|
{
|
||||||
|
ToggleStatusButton.Text = Loc.GetString("comp-space-heater-ui-status-enabled");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ToggleStatusButton.Text = Loc.GetString("comp-space-heater-ui-status-disabled");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTemperature(float targetTemperature)
|
public void SetTemperature(float targetTemperature)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Shared.BarSign;
|
using Content.Shared.BarSign;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.UserInterface;
|
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Client.BarSign.Ui;
|
namespace Content.Client.BarSign.Ui;
|
||||||
@@ -17,12 +16,13 @@ public sealed class BarSignBoundUserInterface(EntityUid owner, Enum uiKey) : Bou
|
|||||||
{
|
{
|
||||||
base.Open();
|
base.Open();
|
||||||
|
|
||||||
|
var sign = EntMan.GetComponentOrNull<BarSignComponent>(Owner)?.Current is { } current
|
||||||
|
? _prototype.Index(current)
|
||||||
|
: null;
|
||||||
var allSigns = BarSignSystem.GetAllBarSigns(_prototype)
|
var allSigns = BarSignSystem.GetAllBarSigns(_prototype)
|
||||||
.OrderBy(p => Loc.GetString(p.Name))
|
.OrderBy(p => Loc.GetString(p.Name))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
_menu = new(sign, allSigns);
|
||||||
_menu = this.CreateWindow<BarSignMenu>();
|
|
||||||
_menu.LoadSigns(allSigns);
|
|
||||||
|
|
||||||
_menu.OnSignSelected += id =>
|
_menu.OnSignSelected += id =>
|
||||||
{
|
{
|
||||||
@@ -30,17 +30,16 @@ public sealed class BarSignBoundUserInterface(EntityUid owner, Enum uiKey) : Bou
|
|||||||
};
|
};
|
||||||
|
|
||||||
_menu.OnClose += Close;
|
_menu.OnClose += Close;
|
||||||
_menu.OpenToLeft();
|
_menu.OpenCentered();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
if (!EntMan.TryGetComponent<BarSignComponent>(Owner, out var signComp)
|
if (!EntMan.TryGetComponent<BarSignComponent>(Owner, out var signComp))
|
||||||
|| !_prototype.Resolve(signComp.Current, out var signPrototype))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_menu?.UpdateState(signPrototype);
|
if (_prototype.Resolve(signComp.Current, out var signPrototype))
|
||||||
|
_menu?.UpdateState(signPrototype);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,23 @@ namespace Content.Client.BarSign.Ui;
|
|||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class BarSignMenu : FancyWindow
|
public sealed partial class BarSignMenu : FancyWindow
|
||||||
{
|
{
|
||||||
private List<BarSignPrototype> _cachedPrototypes = new();
|
private string? _currentId;
|
||||||
|
|
||||||
|
private readonly List<BarSignPrototype> _cachedPrototypes = new();
|
||||||
|
|
||||||
public event Action<string>? OnSignSelected;
|
public event Action<string>? OnSignSelected;
|
||||||
|
|
||||||
public BarSignMenu()
|
public BarSignMenu(BarSignPrototype? currentSign, List<BarSignPrototype> signs)
|
||||||
{
|
{
|
||||||
RobustXamlLoader.Load(this);
|
RobustXamlLoader.Load(this);
|
||||||
|
_currentId = currentSign?.ID;
|
||||||
|
|
||||||
|
_cachedPrototypes.Clear();
|
||||||
|
_cachedPrototypes = signs;
|
||||||
|
foreach (var proto in _cachedPrototypes)
|
||||||
|
{
|
||||||
|
SignOptions.AddItem(Loc.GetString(proto.Name));
|
||||||
|
}
|
||||||
|
|
||||||
SignOptions.OnItemSelected += idx =>
|
SignOptions.OnItemSelected += idx =>
|
||||||
{
|
{
|
||||||
@@ -22,21 +32,18 @@ public sealed partial class BarSignMenu : FancyWindow
|
|||||||
SignOptions.SelectId(idx.Id);
|
SignOptions.SelectId(idx.Id);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
if (currentSign != null)
|
||||||
|
|
||||||
public void LoadSigns(List<BarSignPrototype> signs)
|
|
||||||
{
|
|
||||||
_cachedPrototypes.Clear();
|
|
||||||
_cachedPrototypes = signs;
|
|
||||||
|
|
||||||
foreach (var proto in _cachedPrototypes)
|
|
||||||
{
|
{
|
||||||
SignOptions.AddItem(Loc.GetString(proto.Name));
|
var idx = _cachedPrototypes.IndexOf(currentSign);
|
||||||
|
SignOptions.TrySelectId(idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateState(BarSignPrototype newSign)
|
public void UpdateState(BarSignPrototype newSign)
|
||||||
{
|
{
|
||||||
|
if (_currentId != null && newSign.ID == _currentId)
|
||||||
|
return;
|
||||||
|
_currentId = newSign.ID;
|
||||||
var idx = _cachedPrototypes.IndexOf(newSign);
|
var idx = _cachedPrototypes.IndexOf(newSign);
|
||||||
SignOptions.TrySelectId(idx);
|
SignOptions.TrySelectId(idx);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
using Content.Shared.Body.Systems;
|
||||||
|
|
||||||
|
namespace Content.Client.Body.Systems;
|
||||||
|
|
||||||
|
public sealed class BodySystem : SharedBodySystem
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
using Content.Shared.Body.Systems;
|
||||||
|
|
||||||
|
namespace Content.Client.Body.Systems;
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public sealed class MetabolizerSystem : SharedMetabolizerSystem;
|
||||||
@@ -1,264 +0,0 @@
|
|||||||
using System.Linq;
|
|
||||||
using Content.Shared.Body;
|
|
||||||
using Content.Shared.CCVar;
|
|
||||||
using Content.Shared.Humanoid.Markings;
|
|
||||||
using Content.Shared.Humanoid;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Shared.Configuration;
|
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Client.Body;
|
|
||||||
|
|
||||||
public sealed class VisualBodySystem : SharedVisualBodySystem
|
|
||||||
{
|
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
|
||||||
[Dependency] private readonly MarkingManager _marking = default!;
|
|
||||||
[Dependency] private readonly SpriteSystem _sprite = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
SubscribeLocalEvent<VisualOrganComponent, OrganGotInsertedEvent>(OnOrganGotInserted);
|
|
||||||
SubscribeLocalEvent<VisualOrganComponent, OrganGotRemovedEvent>(OnOrganGotRemoved);
|
|
||||||
SubscribeLocalEvent<VisualOrganComponent, AfterAutoHandleStateEvent>(OnOrganState);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<VisualOrganMarkingsComponent, OrganGotInsertedEvent>(OnMarkingsGotInserted);
|
|
||||||
SubscribeLocalEvent<VisualOrganMarkingsComponent, OrganGotRemovedEvent>(OnMarkingsGotRemoved);
|
|
||||||
SubscribeLocalEvent<VisualOrganMarkingsComponent, AfterAutoHandleStateEvent>(OnMarkingsState);
|
|
||||||
|
|
||||||
SubscribeLocalEvent<VisualOrganMarkingsComponent, BodyRelayedEvent<HumanoidLayerVisibilityChangedEvent>>(OnMarkingsChangedVisibility);
|
|
||||||
|
|
||||||
Subs.CVar(_cfg, CCVars.AccessibilityClientCensorNudity, OnCensorshipChanged, true);
|
|
||||||
Subs.CVar(_cfg, CCVars.AccessibilityServerCensorNudity, OnCensorshipChanged, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnCensorshipChanged(bool value)
|
|
||||||
{
|
|
||||||
var query = AllEntityQuery<OrganComponent, VisualOrganMarkingsComponent>();
|
|
||||||
while (query.MoveNext(out var ent, out var organComp, out var markingsComp))
|
|
||||||
{
|
|
||||||
if (organComp.Body is not { } body)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
RemoveMarkings((ent, markingsComp), body);
|
|
||||||
ApplyMarkings((ent, markingsComp), body);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnOrganGotInserted(Entity<VisualOrganComponent> ent, ref OrganGotInsertedEvent args)
|
|
||||||
{
|
|
||||||
ApplyVisual(ent, args.Target);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnOrganGotRemoved(Entity<VisualOrganComponent> ent, ref OrganGotRemovedEvent args)
|
|
||||||
{
|
|
||||||
RemoveVisual(ent, args.Target);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnOrganState(Entity<VisualOrganComponent> ent, ref AfterAutoHandleStateEvent args)
|
|
||||||
{
|
|
||||||
if (Comp<OrganComponent>(ent).Body is not { } body)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ApplyVisual(ent, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyVisual(Entity<VisualOrganComponent> ent, EntityUid target)
|
|
||||||
{
|
|
||||||
if (!_sprite.LayerMapTryGet(target, ent.Comp.Layer, out var index, true))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_sprite.LayerSetData(target, index, ent.Comp.Data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveVisual(Entity<VisualOrganComponent> ent, EntityUid target)
|
|
||||||
{
|
|
||||||
if (!_sprite.LayerMapTryGet(target, ent.Comp.Layer, out var index, true))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_sprite.LayerSetRsiState(target, index, RSI.StateId.Invalid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMarkingsGotInserted(Entity<VisualOrganMarkingsComponent> ent, ref OrganGotInsertedEvent args)
|
|
||||||
{
|
|
||||||
ApplyMarkings(ent, args.Target);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMarkingsGotRemoved(Entity<VisualOrganMarkingsComponent> ent, ref OrganGotRemovedEvent args)
|
|
||||||
{
|
|
||||||
RemoveMarkings(ent, args.Target);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMarkingsState(Entity<VisualOrganMarkingsComponent> ent, ref AfterAutoHandleStateEvent args)
|
|
||||||
{
|
|
||||||
if (Comp<OrganComponent>(ent).Body is not { } body)
|
|
||||||
return;
|
|
||||||
|
|
||||||
RemoveMarkings(ent, body);
|
|
||||||
ApplyMarkings(ent, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void SetOrganColor(Entity<VisualOrganComponent> ent, Color color)
|
|
||||||
{
|
|
||||||
base.SetOrganColor(ent, color);
|
|
||||||
|
|
||||||
if (Comp<OrganComponent>(ent).Body is not { } body)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ApplyVisual(ent, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void SetOrganMarkings(Entity<VisualOrganMarkingsComponent> ent, Dictionary<HumanoidVisualLayers, List<Marking>> markings)
|
|
||||||
{
|
|
||||||
base.SetOrganMarkings(ent, markings);
|
|
||||||
|
|
||||||
if (Comp<OrganComponent>(ent).Body is not { } body)
|
|
||||||
return;
|
|
||||||
|
|
||||||
RemoveMarkings(ent, body);
|
|
||||||
ApplyMarkings(ent, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void SetOrganAppearance(Entity<VisualOrganComponent> ent, PrototypeLayerData data)
|
|
||||||
{
|
|
||||||
base.SetOrganAppearance(ent, data);
|
|
||||||
|
|
||||||
if (Comp<OrganComponent>(ent).Body is not { } body)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ApplyVisual(ent, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<Marking> AllMarkings(Entity<VisualOrganMarkingsComponent> ent)
|
|
||||||
{
|
|
||||||
foreach (var markings in ent.Comp.Markings.Values)
|
|
||||||
{
|
|
||||||
foreach (var marking in markings)
|
|
||||||
{
|
|
||||||
yield return marking;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var censorNudity = _cfg.GetCVar(CCVars.AccessibilityClientCensorNudity) || _cfg.GetCVar(CCVars.AccessibilityServerCensorNudity);
|
|
||||||
if (!censorNudity)
|
|
||||||
yield break;
|
|
||||||
|
|
||||||
var group = _prototype.Index(ent.Comp.MarkingData.Group);
|
|
||||||
foreach (var layer in ent.Comp.MarkingData.Layers)
|
|
||||||
{
|
|
||||||
if (!group.Limits.TryGetValue(layer, out var layerLimits))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (layerLimits.NudityDefault.Count < 1)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var markings = ent.Comp.Markings.GetValueOrDefault(layer) ?? [];
|
|
||||||
if (markings.Any(marking => _marking.TryGetMarking(marking, out var proto) && proto.BodyPart == layer))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var marking in layerLimits.NudityDefault)
|
|
||||||
{
|
|
||||||
yield return new(marking, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ApplyMarkings(Entity<VisualOrganMarkingsComponent> ent, EntityUid target)
|
|
||||||
{
|
|
||||||
var applied = new List<Marking>();
|
|
||||||
foreach (var marking in AllMarkings(ent))
|
|
||||||
{
|
|
||||||
if (!_marking.TryGetMarking(marking, out var proto))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!_sprite.LayerMapTryGet(target, proto.BodyPart, out var index, true))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (var i = 0; i < proto.Sprites.Count; i++)
|
|
||||||
{
|
|
||||||
var sprite = proto.Sprites[i];
|
|
||||||
|
|
||||||
DebugTools.Assert(sprite is SpriteSpecifier.Rsi);
|
|
||||||
if (sprite is not SpriteSpecifier.Rsi rsi)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var layerId = $"{proto.ID}-{rsi.RsiState}";
|
|
||||||
|
|
||||||
if (!_sprite.LayerMapTryGet(target, layerId, out _, false))
|
|
||||||
{
|
|
||||||
var layer = _sprite.AddLayer(target, sprite, index + i + 1);
|
|
||||||
_sprite.LayerMapSet(target, layerId, layer);
|
|
||||||
_sprite.LayerSetSprite(target, layerId, rsi);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (marking.MarkingColors is not null && i < marking.MarkingColors.Count)
|
|
||||||
_sprite.LayerSetColor(target, layerId, marking.MarkingColors[i]);
|
|
||||||
else
|
|
||||||
_sprite.LayerSetColor(target, layerId, Color.White);
|
|
||||||
}
|
|
||||||
|
|
||||||
applied.Add(marking);
|
|
||||||
}
|
|
||||||
ent.Comp.AppliedMarkings = applied;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveMarkings(Entity<VisualOrganMarkingsComponent> ent, EntityUid target)
|
|
||||||
{
|
|
||||||
foreach (var marking in ent.Comp.AppliedMarkings)
|
|
||||||
{
|
|
||||||
if (!_marking.TryGetMarking(marking, out var proto))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var sprite in proto.Sprites)
|
|
||||||
{
|
|
||||||
DebugTools.Assert(sprite is SpriteSpecifier.Rsi);
|
|
||||||
if (sprite is not SpriteSpecifier.Rsi rsi)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var layerId = $"{proto.ID}-{rsi.RsiState}";
|
|
||||||
|
|
||||||
if (!_sprite.LayerMapTryGet(target, layerId, out var index, false))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_sprite.LayerMapRemove(target, layerId);
|
|
||||||
_sprite.RemoveLayer(target, index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnMarkingsChangedVisibility(Entity<VisualOrganMarkingsComponent> ent, ref BodyRelayedEvent<HumanoidLayerVisibilityChangedEvent> args)
|
|
||||||
{
|
|
||||||
if (!ent.Comp.HideableLayers.Contains(args.Args.Layer))
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var markings in ent.Comp.Markings.Values)
|
|
||||||
{
|
|
||||||
foreach (var marking in markings)
|
|
||||||
{
|
|
||||||
if (!_marking.TryGetMarking(marking, out var proto))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (proto.BodyPart != args.Args.Layer && !(ent.Comp.DependentHidingLayers.TryGetValue(args.Args.Layer, out var dependent) && dependent.Contains(proto.BodyPart)))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var sprite in proto.Sprites)
|
|
||||||
{
|
|
||||||
DebugTools.Assert(sprite is SpriteSpecifier.Rsi);
|
|
||||||
if (sprite is not SpriteSpecifier.Rsi rsi)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var layerId = $"{proto.ID}-{rsi.RsiState}";
|
|
||||||
|
|
||||||
if (!_sprite.LayerMapTryGet(args.Body.Owner, layerId, out var index, true))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_sprite.LayerSetVisible(args.Body.Owner, index, args.Args.Visible);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,6 @@ using Content.Client.Cargo.UI;
|
|||||||
using Content.Shared.Cargo.Components;
|
using Content.Shared.Cargo.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.UserInterface;
|
using Robust.Client.UserInterface;
|
||||||
using Content.Shared._DV.Cargo.Components; // DeltaV: Bounty claim messages
|
|
||||||
|
|
||||||
namespace Content.Client.Cargo.BUI;
|
namespace Content.Client.Cargo.BUI;
|
||||||
|
|
||||||
@@ -31,18 +30,6 @@ public sealed class CargoBountyConsoleBoundUserInterface : BoundUserInterface
|
|||||||
{
|
{
|
||||||
SendMessage(new BountySkipMessage(id));
|
SendMessage(new BountySkipMessage(id));
|
||||||
};
|
};
|
||||||
|
|
||||||
// DeltaV: bounty claim stuff begins
|
|
||||||
_menu.OnClaimButtonPressed += id =>
|
|
||||||
{
|
|
||||||
SendMessage(new BountyClaimedMessage(id));
|
|
||||||
};
|
|
||||||
|
|
||||||
_menu.OnStatusOptionSelected += (id, status) =>
|
|
||||||
{
|
|
||||||
SendMessage(new BountySetStatusMessage(id, status));
|
|
||||||
};
|
|
||||||
// DeltaV: bounty claim stuff ends
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateState(BoundUserInterfaceState message)
|
protected override void UpdateState(BoundUserInterfaceState message)
|
||||||
|
|||||||
@@ -70,9 +70,9 @@ namespace Content.Client.Cargo.BUI
|
|||||||
|
|
||||||
_menu.OnClose += Close;
|
_menu.OnClose += Close;
|
||||||
|
|
||||||
_menu.OnItemSelected += (row) =>
|
_menu.OnItemSelected += (args) =>
|
||||||
{
|
{
|
||||||
if (row == null)
|
if (args.Button.Parent is not CargoProductRow row)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
description.Clear();
|
description.Clear();
|
||||||
@@ -175,23 +175,23 @@ namespace Content.Client.Cargo.BUI
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveOrder(CargoOrderData? order)
|
private void RemoveOrder(ButtonEventArgs args)
|
||||||
{
|
{
|
||||||
if (order == null)
|
if (args.Button.Parent?.Parent is not CargoOrderRow row || row.Order == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SendMessage(new CargoConsoleRemoveOrderMessage(order.OrderId));
|
SendMessage(new CargoConsoleRemoveOrderMessage(row.Order.OrderId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApproveOrder(CargoOrderData? order)
|
private void ApproveOrder(ButtonEventArgs args)
|
||||||
{
|
{
|
||||||
if (order == null)
|
if (args.Button.Parent?.Parent is not CargoOrderRow row || row.Order == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (OrderCount >= OrderCapacity)
|
if (OrderCount >= OrderCapacity)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SendMessage(new CargoConsoleApproveOrderMessage(order.OrderId));
|
SendMessage(new CargoConsoleApproveOrderMessage(row.Order.OrderId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,6 @@
|
|||||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
|
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
|
||||||
<RichTextLabel Name="RewardLabel"/>
|
<RichTextLabel Name="RewardLabel"/>
|
||||||
<RichTextLabel Name="ManifestLabel"/>
|
<RichTextLabel Name="ManifestLabel"/>
|
||||||
<RichTextLabel Name="ClaimedBylabel"/> <!-- DeltaV bounty claim -->
|
|
||||||
<RichTextLabel Name="StatusLabel"/> <!-- DeltaV bounty claim -->
|
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<Control MinWidth="10"/>
|
<Control MinWidth="10"/>
|
||||||
<BoxContainer Orientation="Vertical" MinWidth="120">
|
<BoxContainer Orientation="Vertical" MinWidth="120">
|
||||||
@@ -19,22 +17,14 @@
|
|||||||
<Button Name="PrintButton"
|
<Button Name="PrintButton"
|
||||||
Text="{Loc 'bounty-console-label-button-text'}"
|
Text="{Loc 'bounty-console-label-button-text'}"
|
||||||
HorizontalExpand="False"
|
HorizontalExpand="False"
|
||||||
StyleClasses="OpenBoth"/>
|
HorizontalAlignment="Right"
|
||||||
|
StyleClasses="OpenRight"/>
|
||||||
<Button Name="SkipButton"
|
<Button Name="SkipButton"
|
||||||
Text="{Loc 'bounty-console-skip-button-text'}"
|
Text="{Loc 'bounty-console-skip-button-text'}"
|
||||||
HorizontalExpand="True"
|
HorizontalExpand="False"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
StyleClasses="OpenLeft"/>
|
StyleClasses="OpenLeft"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
<BoxContainer Orientation="Horizontal" MinWidth="120"> <!-- Begin DeltaV bounty claim content -->
|
|
||||||
<Button Name="ClaimButton"
|
|
||||||
Text= "{Loc 'bounty-console-claim-button-text'}"
|
|
||||||
HorizontalExpand="False"
|
|
||||||
StyleClasses="OpenRight"/>
|
|
||||||
<OptionButton Name="BountyStatusSelector"
|
|
||||||
Access="Public"
|
|
||||||
StyleClasses="OpenBoth"
|
|
||||||
HorizontalExpand="True"/>
|
|
||||||
</BoxContainer> <!-- End DeltaV content-->
|
|
||||||
<RichTextLabel Name="IdLabel" HorizontalAlignment="Right" Margin="0 0 5 0"/>
|
<RichTextLabel Name="IdLabel" HorizontalAlignment="Right" Margin="0 0 5 0"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ public sealed partial class BountyEntry : BoxContainer
|
|||||||
|
|
||||||
public Action? OnLabelButtonPressed;
|
public Action? OnLabelButtonPressed;
|
||||||
public Action? OnSkipButtonPressed;
|
public Action? OnSkipButtonPressed;
|
||||||
public Action? OnClaimButtonPressed; // DeltaV
|
|
||||||
public Action? OnStatusOptionSelected; // DeltaV
|
|
||||||
|
|
||||||
public TimeSpan EndTime;
|
public TimeSpan EndTime;
|
||||||
public TimeSpan UntilNextSkip;
|
public TimeSpan UntilNextSkip;
|
||||||
@@ -47,20 +45,6 @@ public sealed partial class BountyEntry : BoxContainer
|
|||||||
|
|
||||||
PrintButton.OnPressed += _ => OnLabelButtonPressed?.Invoke();
|
PrintButton.OnPressed += _ => OnLabelButtonPressed?.Invoke();
|
||||||
SkipButton.OnPressed += _ => OnSkipButtonPressed?.Invoke();
|
SkipButton.OnPressed += _ => OnSkipButtonPressed?.Invoke();
|
||||||
|
|
||||||
// Begin DeltaV bounty claiming
|
|
||||||
ClaimButton.OnPressed += _ => OnClaimButtonPressed?.Invoke();
|
|
||||||
BountyStatusSelector.AddItem(Loc.GetString($"bounty-console-status-{nameof(CargoBountyStatus.Undelivered)}"), 0);
|
|
||||||
BountyStatusSelector.AddItem(Loc.GetString($"bounty-console-status-{nameof(CargoBountyStatus.Waiting)}"), 1);
|
|
||||||
BountyStatusSelector.AddItem(Loc.GetString($"bounty-console-status-{nameof(CargoBountyStatus.OnShuttle)}"), 2);
|
|
||||||
|
|
||||||
BountyStatusSelector.Select((int) bounty.Status);
|
|
||||||
BountyStatusSelector.ToolTip = Loc.GetString($"bounty-console-status-tooltip-{bounty.Status.ToString()}");
|
|
||||||
|
|
||||||
var claimedByText = string.IsNullOrEmpty(bounty.ClaimedBy) ? Loc.GetString("bounty-console-claimed-by-none") : bounty.ClaimedBy;
|
|
||||||
ClaimedBylabel.SetMarkup(Loc.GetString("bounty-console-claimed-by", ("claimant", claimedByText)));
|
|
||||||
StatusLabel.SetMarkup(Loc.GetString($"bounty-console-status-formatted-{bounty.Status.ToString()}"));
|
|
||||||
// End DeltaV bounty claiming
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateSkipButton(float deltaSeconds)
|
private void UpdateSkipButton(float deltaSeconds)
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
<!--DeltaV - SetSize was 550, now 750 to accomodate bounty claim UI -->
|
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
|
||||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
Title="{Loc 'bounty-console-menu-title'}"
|
Title="{Loc 'bounty-console-menu-title'}"
|
||||||
SetSize="750 420"
|
SetSize="550 420"
|
||||||
MinSize="400 350">
|
MinSize="400 350">
|
||||||
<BoxContainer Orientation="Vertical"
|
<BoxContainer Orientation="Vertical"
|
||||||
VerticalExpand="True"
|
VerticalExpand="True"
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ public sealed partial class CargoBountyMenu : FancyWindow
|
|||||||
{
|
{
|
||||||
public Action<string>? OnLabelButtonPressed;
|
public Action<string>? OnLabelButtonPressed;
|
||||||
public Action<string>? OnSkipButtonPressed;
|
public Action<string>? OnSkipButtonPressed;
|
||||||
public Action<string>? OnClaimButtonPressed; // DeltaV
|
|
||||||
public Action<string, int>? OnStatusOptionSelected; // DeltaV
|
|
||||||
|
|
||||||
public CargoBountyMenu()
|
public CargoBountyMenu()
|
||||||
{
|
{
|
||||||
@@ -33,8 +31,6 @@ public sealed partial class CargoBountyMenu : FancyWindow
|
|||||||
var entry = new BountyEntry(b, untilNextSkip);
|
var entry = new BountyEntry(b, untilNextSkip);
|
||||||
entry.OnLabelButtonPressed += () => OnLabelButtonPressed?.Invoke(b.Id);
|
entry.OnLabelButtonPressed += () => OnLabelButtonPressed?.Invoke(b.Id);
|
||||||
entry.OnSkipButtonPressed += () => OnSkipButtonPressed?.Invoke(b.Id);
|
entry.OnSkipButtonPressed += () => OnSkipButtonPressed?.Invoke(b.Id);
|
||||||
entry.OnClaimButtonPressed += () => OnClaimButtonPressed?.Invoke(b.Id); // DeltaV
|
|
||||||
entry.BountyStatusSelector.OnItemSelected += args => OnStatusOptionSelected?.Invoke(b.Id, args.Id); // DeltaV
|
|
||||||
|
|
||||||
BountyEntriesContainer.AddChild(entry);
|
BountyEntriesContainer.AddChild(entry);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,226 +1,86 @@
|
|||||||
<controls:FancyWindow
|
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||||
xmlns="https://spacestation14.io"
|
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
SetSize="600 600"
|
||||||
MinSize="540 390"
|
MinSize="600 600">
|
||||||
SetSize="995 600">
|
<BoxContainer Orientation="Vertical" Margin="15 5 15 10">
|
||||||
|
<BoxContainer Orientation="Horizontal">
|
||||||
<!-- Main Container -->
|
<Label Text="{Loc 'cargo-console-menu-account-name-label'}"
|
||||||
<BoxContainer Orientation="Vertical"
|
StyleClasses="LabelKeyText" />
|
||||||
VerticalExpand="True">
|
<RichTextLabel Name="AccountNameLabel"
|
||||||
|
Text="{Loc 'cargo-console-menu-account-name-none-text'}" />
|
||||||
<TabContainer Name="TabContainer" VerticalExpand="True">
|
|
||||||
<!-- Sub-Main Container -->
|
|
||||||
<BoxContainer Orientation="Horizontal"
|
|
||||||
VerticalExpand="True"
|
|
||||||
Margin="8 4 8 6">
|
|
||||||
|
|
||||||
<!-- Left Part -->
|
|
||||||
<BoxContainer Orientation="Vertical"
|
|
||||||
SeparationOverride="4"
|
|
||||||
Margin="0 0 8 0"
|
|
||||||
HorizontalExpand="True">
|
|
||||||
|
|
||||||
<!-- Info -->
|
|
||||||
<BoxContainer Orientation="Vertical">
|
|
||||||
<GridContainer Columns="3">
|
|
||||||
|
|
||||||
<!-- Account -->
|
|
||||||
<Label Text="{Loc 'cargo-console-menu-account-name-label'}"
|
|
||||||
StyleClasses="LabelKeyText" />
|
|
||||||
|
|
||||||
<PanelContainer StyleClasses="LowDivider" Margin="0 -2"/>
|
|
||||||
|
|
||||||
<RichTextLabel Name="AccountNameLabel"
|
|
||||||
Text="{Loc 'cargo-console-menu-account-name-none-text'}"
|
|
||||||
Margin="4 0"/>
|
|
||||||
|
|
||||||
<!-- Balance -->
|
|
||||||
<Label Text="{Loc 'cargo-console-menu-points-label'}"
|
|
||||||
StyleClasses="LabelKeyText"/>
|
|
||||||
|
|
||||||
<PanelContainer StyleClasses="LowDivider" Margin="0 -2"/>
|
|
||||||
|
|
||||||
<RichTextLabel Name="PointsLabel"
|
|
||||||
Text="$0"
|
|
||||||
Margin="4 0" />
|
|
||||||
|
|
||||||
<!-- Orders Count/Capacity -->
|
|
||||||
<Label Text="{Loc 'cargo-console-menu-order-capacity-label'}"
|
|
||||||
StyleClasses="LabelKeyText" />
|
|
||||||
|
|
||||||
<PanelContainer StyleClasses="LowDivider" Margin="0 -2 0 -1"/>
|
|
||||||
|
|
||||||
<Label Name="ShuttleCapacityLabel"
|
|
||||||
Text="0/20"
|
|
||||||
Margin="4 0"/>
|
|
||||||
</GridContainer>
|
|
||||||
|
|
||||||
<PanelContainer StyleClasses="LowDivider" Margin="0 4.5 -8 0"/>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<!-- Search -->
|
|
||||||
<BoxContainer Orientation="Horizontal"
|
|
||||||
Margin="0 2 0 0">
|
|
||||||
|
|
||||||
<LineEdit Name="SearchBar"
|
|
||||||
PlaceHolder="{Loc 'cargo-console-menu-search-bar-placeholder'}"
|
|
||||||
HorizontalExpand="True" />
|
|
||||||
|
|
||||||
<OptionButton Name="Categories"
|
|
||||||
Prefix="{Loc 'cargo-console-menu-categories-label'}"
|
|
||||||
StyleClasses="OpenLeft"/>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<!-- Product list -->
|
|
||||||
<ScrollContainer
|
|
||||||
HorizontalExpand="False"
|
|
||||||
VerticalExpand="True"
|
|
||||||
HScrollEnabled="False">
|
|
||||||
|
|
||||||
<BoxContainer Name="Products"
|
|
||||||
Orientation="Vertical"
|
|
||||||
HorizontalExpand="True"
|
|
||||||
VerticalExpand="True">
|
|
||||||
|
|
||||||
<!-- Products get added here by code -->
|
|
||||||
</BoxContainer>
|
|
||||||
</ScrollContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<PanelContainer StyleClasses="LowDivider" Margin="0 -8"/>
|
|
||||||
|
|
||||||
<!-- Right Part -->
|
|
||||||
<BoxContainer Orientation="Vertical"
|
|
||||||
SizeFlagsStretchRatio="0.8"
|
|
||||||
HorizontalExpand="True"
|
|
||||||
Name="RightPart">
|
|
||||||
|
|
||||||
<!-- Requests Part -->
|
|
||||||
<BoxContainer Orientation="Vertical"
|
|
||||||
VerticalExpand="True"
|
|
||||||
SizeFlagsStretchRatio="2">
|
|
||||||
|
|
||||||
<!-- Title -->
|
|
||||||
<controls:StripeBack>
|
|
||||||
<Label Text="{Loc 'cargo-console-menu-requests-label'}"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Margin="4"/>
|
|
||||||
</controls:StripeBack>
|
|
||||||
|
|
||||||
<PanelContainer VerticalExpand="True"
|
|
||||||
Margin="0 -4 0 0">
|
|
||||||
|
|
||||||
<!-- Background -->
|
|
||||||
<PanelContainer.PanelOverride>
|
|
||||||
<gfx:StyleBoxFlat BackgroundColor="#040404" />
|
|
||||||
</PanelContainer.PanelOverride>
|
|
||||||
|
|
||||||
<BoxContainer Orientation="Vertical">
|
|
||||||
<ScrollContainer VerticalExpand="True">
|
|
||||||
<BoxContainer Name="Requests"
|
|
||||||
Orientation="Vertical"
|
|
||||||
StyleClasses="transparentItemList"
|
|
||||||
VerticalExpand="True"
|
|
||||||
SeparationOverride="8"
|
|
||||||
Margin="8">
|
|
||||||
|
|
||||||
<!-- Requests are added here by code -->
|
|
||||||
</BoxContainer>
|
|
||||||
</ScrollContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</PanelContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<!-- Orders Part -->
|
|
||||||
<BoxContainer Orientation="Vertical"
|
|
||||||
VerticalExpand="True">
|
|
||||||
|
|
||||||
<!-- Title -->
|
|
||||||
<controls:StripeBack>
|
|
||||||
<Label Text="{Loc 'cargo-console-menu-orders-label'}"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
Margin="4"/>
|
|
||||||
</controls:StripeBack>
|
|
||||||
|
|
||||||
<PanelContainer VerticalExpand="True"
|
|
||||||
Margin="0 -4 0 0">
|
|
||||||
|
|
||||||
<!-- Background -->
|
|
||||||
<PanelContainer.PanelOverride>
|
|
||||||
<gfx:StyleBoxFlat BackgroundColor="#040404" />
|
|
||||||
</PanelContainer.PanelOverride>
|
|
||||||
|
|
||||||
<BoxContainer Orientation="Vertical"
|
|
||||||
Margin="6">
|
|
||||||
<ScrollContainer VerticalExpand="True">
|
|
||||||
<BoxContainer Orientation="Vertical"
|
|
||||||
StyleClasses="transparentItemList"
|
|
||||||
VerticalExpand="True"
|
|
||||||
SeparationOverride="6">
|
|
||||||
|
|
||||||
<!-- Orders are added here by code -->
|
|
||||||
</BoxContainer>
|
|
||||||
</ScrollContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</PanelContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
<!-- Funds tab -->
|
|
||||||
<BoxContainer Orientation="Vertical" Margin="15">
|
|
||||||
<BoxContainer Orientation="Horizontal">
|
|
||||||
<RichTextLabel Name="TransferLimitLabel" Margin="0 0 15 0"/>
|
|
||||||
<RichTextLabel Name="UnlimitedNotifier" Text="{Loc 'cargo-console-menu-account-action-transfer-limit-unlimited-notifier'}"/>
|
|
||||||
</BoxContainer>
|
|
||||||
<BoxContainer Orientation="Horizontal">
|
|
||||||
<RichTextLabel Text="{Loc 'cargo-console-menu-account-action-select'}" Margin="0 0 10 0"/>
|
|
||||||
<OptionButton Name="ActionOptions"/>
|
|
||||||
</BoxContainer>
|
|
||||||
<Control MinHeight="5"/>
|
|
||||||
<BoxContainer Orientation="Horizontal">
|
|
||||||
<RichTextLabel Name="AmountText" Text="{ Loc 'cargo-console-menu-account-action-amount'}"/>
|
|
||||||
<SpinBox Name="TransferSpinBox" MinWidth="100" Value="10"/>
|
|
||||||
</BoxContainer>
|
|
||||||
<Control MinHeight="15"/>
|
|
||||||
<BoxContainer HorizontalAlignment="Center">
|
|
||||||
<Button Name="AccountActionButton" Text="{ Loc 'cargo-console-menu-account-action-button'}" MinHeight="45" MinWidth="120"/>
|
|
||||||
</BoxContainer>
|
|
||||||
<Control VerticalExpand="True"/>
|
|
||||||
<BoxContainer VerticalAlignment="Bottom" HorizontalAlignment="Center">
|
|
||||||
<Button Name="AccountLimitToggleButton" Text="{ Loc 'cargo-console-menu-toggle-account-lock-button'}" MinHeight="45" MinWidth="120"/>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</TabContainer>
|
|
||||||
|
|
||||||
<!-- Footer -->
|
|
||||||
<!-- TODO: Create customControls element -->
|
|
||||||
<BoxContainer Orientation="Vertical"
|
|
||||||
VerticalAlignment="Bottom">
|
|
||||||
|
|
||||||
<PanelContainer StyleClasses="LowDivider" />
|
|
||||||
|
|
||||||
<BoxContainer Orientation="Horizontal"
|
|
||||||
Margin="12 0 6 2"
|
|
||||||
VerticalAlignment="Bottom">
|
|
||||||
|
|
||||||
<!-- Footer title -->
|
|
||||||
<Label Text="{Loc 'cargo-console-menu-flavor-left'}"
|
|
||||||
StyleClasses="WindowFooterText" />
|
|
||||||
|
|
||||||
<!-- Version -->
|
|
||||||
<Label Text="{Loc 'cargo-console-menu-flavor-right'}"
|
|
||||||
StyleClasses="WindowFooterText"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
HorizontalExpand="True"
|
|
||||||
Margin="0 0 4 0" />
|
|
||||||
|
|
||||||
<TextureRect StyleClasses="NTLogoDark"
|
|
||||||
Stretch="KeepAspectCentered"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
SetSize="19 19"/>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Horizontal">
|
||||||
|
<Label Text="{Loc 'cargo-console-menu-points-label'}"
|
||||||
|
StyleClasses="LabelKeyText" />
|
||||||
|
<RichTextLabel Name="PointsLabel"
|
||||||
|
Text="$0" />
|
||||||
|
</BoxContainer>
|
||||||
|
<Control MinHeight="10"/>
|
||||||
|
<TabContainer Name="TabContainer" VerticalExpand="True">
|
||||||
|
<BoxContainer Orientation="Vertical" VerticalExpand="True">
|
||||||
|
<BoxContainer Orientation="Horizontal">
|
||||||
|
<OptionButton Name="Categories"
|
||||||
|
Prefix="{Loc 'cargo-console-menu-categories-label'}"
|
||||||
|
HorizontalExpand="True" />
|
||||||
|
<LineEdit Name="SearchBar"
|
||||||
|
PlaceHolder="{Loc 'cargo-console-menu-search-bar-placeholder'}"
|
||||||
|
HorizontalExpand="True" />
|
||||||
|
</BoxContainer>
|
||||||
|
<Control MinHeight="5"/>
|
||||||
|
<ScrollContainer HorizontalExpand="True"
|
||||||
|
VerticalExpand="True"
|
||||||
|
SizeFlagsStretchRatio="2">
|
||||||
|
<BoxContainer Name="Products"
|
||||||
|
Orientation="Vertical"
|
||||||
|
HorizontalExpand="True"
|
||||||
|
VerticalExpand="True">
|
||||||
|
<!-- Products get added here by code -->
|
||||||
|
</BoxContainer>
|
||||||
|
</ScrollContainer>
|
||||||
|
<Control MinHeight="5" Name="OrdersSpacer"/>
|
||||||
|
<PanelContainer VerticalExpand="True"
|
||||||
|
SizeFlagsStretchRatio="1"
|
||||||
|
Name="Orders">
|
||||||
|
<PanelContainer.PanelOverride>
|
||||||
|
<gfx:StyleBoxFlat BackgroundColor="#000000" />
|
||||||
|
</PanelContainer.PanelOverride>
|
||||||
|
<ScrollContainer VerticalExpand="True">
|
||||||
|
<BoxContainer Orientation="Vertical" Margin="5">
|
||||||
|
<Label Text="{Loc 'cargo-console-menu-requests-label'}" />
|
||||||
|
<BoxContainer Name="Requests"
|
||||||
|
Orientation="Vertical"
|
||||||
|
VerticalExpand="True">
|
||||||
|
<!-- Requests are added here by code -->
|
||||||
|
</BoxContainer>
|
||||||
|
</BoxContainer>
|
||||||
|
</ScrollContainer>
|
||||||
|
</PanelContainer>
|
||||||
|
</BoxContainer>
|
||||||
|
<!-- Funds tab -->
|
||||||
|
<BoxContainer Orientation="Vertical" Margin="15">
|
||||||
|
<BoxContainer Orientation="Horizontal">
|
||||||
|
<RichTextLabel Name="TransferLimitLabel" Margin="0 0 15 0"/>
|
||||||
|
<RichTextLabel Name="UnlimitedNotifier" Text="{Loc 'cargo-console-menu-account-action-transfer-limit-unlimited-notifier'}"/>
|
||||||
|
</BoxContainer>
|
||||||
|
<BoxContainer Orientation="Horizontal">
|
||||||
|
<RichTextLabel Text="{Loc 'cargo-console-menu-account-action-select'}" Margin="0 0 10 0"/>
|
||||||
|
<OptionButton Name="ActionOptions"/>
|
||||||
|
</BoxContainer>
|
||||||
|
<Control MinHeight="5"/>
|
||||||
|
<BoxContainer Orientation="Horizontal">
|
||||||
|
<RichTextLabel Name="AmountText" Text="{ Loc 'cargo-console-menu-account-action-amount'}"/>
|
||||||
|
<SpinBox Name="TransferSpinBox" MinWidth="100" Value="10"/>
|
||||||
|
</BoxContainer>
|
||||||
|
<Control MinHeight="15"/>
|
||||||
|
<BoxContainer HorizontalAlignment="Center">
|
||||||
|
<Button Name="AccountActionButton" Text="{ Loc 'cargo-console-menu-account-action-button'}" MinHeight="45" MinWidth="120"/>
|
||||||
|
</BoxContainer>
|
||||||
|
<Control VerticalExpand="True"/>
|
||||||
|
<BoxContainer VerticalAlignment="Bottom" HorizontalAlignment="Center">
|
||||||
|
<Button Name="AccountLimitToggleButton" Text="{ Loc 'cargo-console-menu-toggle-account-lock-button'}" MinHeight="45" MinWidth="120"/>
|
||||||
|
</BoxContainer>
|
||||||
|
</BoxContainer>
|
||||||
|
</TabContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</controls:FancyWindow>
|
</controls:FancyWindow>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using Content.Shared.Cargo.Components;
|
|||||||
using Content.Shared.Cargo.Prototypes;
|
using Content.Shared.Cargo.Prototypes;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.XAML;
|
using Robust.Client.UserInterface.XAML;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
@@ -30,9 +29,9 @@ namespace Content.Client.Cargo.UI
|
|||||||
private readonly EntityQuery<CargoOrderConsoleComponent> _orderConsoleQuery;
|
private readonly EntityQuery<CargoOrderConsoleComponent> _orderConsoleQuery;
|
||||||
private readonly EntityQuery<StationBankAccountComponent> _bankQuery;
|
private readonly EntityQuery<StationBankAccountComponent> _bankQuery;
|
||||||
|
|
||||||
public event Action<CargoProductRow?>? OnItemSelected;
|
public event Action<ButtonEventArgs>? OnItemSelected;
|
||||||
public event Action<CargoOrderData?>? OnOrderApproved;
|
public event Action<ButtonEventArgs>? OnOrderApproved;
|
||||||
public event Action<CargoOrderData?>? OnOrderCanceled;
|
public event Action<ButtonEventArgs>? OnOrderCanceled;
|
||||||
|
|
||||||
public event Action<ProtoId<CargoAccountPrototype>?, int>? OnAccountAction;
|
public event Action<ProtoId<CargoAccountPrototype>?, int>? OnAccountAction;
|
||||||
|
|
||||||
@@ -165,7 +164,7 @@ namespace Content.Client.Cargo.UI
|
|||||||
};
|
};
|
||||||
button.MainButton.OnPressed += args =>
|
button.MainButton.OnPressed += args =>
|
||||||
{
|
{
|
||||||
OnItemSelected?.Invoke(button);
|
OnItemSelected?.Invoke(args);
|
||||||
};
|
};
|
||||||
Products.AddChild(button);
|
Products.AddChild(button);
|
||||||
}
|
}
|
||||||
@@ -211,66 +210,38 @@ namespace Content.Client.Cargo.UI
|
|||||||
|
|
||||||
foreach (var order in orders)
|
foreach (var order in orders)
|
||||||
{
|
{
|
||||||
if (order.Approved || !_protoManager.Resolve(order.Product, out var productProto))
|
if (order.Approved)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var product = _protoManager.Index<EntityPrototype>(productProto.Product);
|
var product = _protoManager.Index<EntityPrototype>(order.ProductId);
|
||||||
var productName = productProto.Name;
|
var productName = product.Name;
|
||||||
var requester = !string.IsNullOrEmpty(order.Requester) ?
|
|
||||||
order.Requester : Loc.GetString("cargo-console-menu-order-row-alerts-requester-unknown");
|
|
||||||
var account = _protoManager.Index(order.Account);
|
var account = _protoManager.Index(order.Account);
|
||||||
|
|
||||||
var row = new CargoOrderRow
|
var row = new CargoOrderRow
|
||||||
{
|
{
|
||||||
Order = order,
|
Order = order,
|
||||||
|
|
||||||
Title =
|
|
||||||
{
|
|
||||||
Text = Loc.GetString(
|
|
||||||
"cargo-console-menu-order-row-title",
|
|
||||||
("productName", productName),
|
|
||||||
("orderAmount", order.OrderQuantity),
|
|
||||||
("orderPrice", productProto.Cost)),
|
|
||||||
},
|
|
||||||
|
|
||||||
Stride =
|
|
||||||
{
|
|
||||||
PanelOverride = new StyleBoxFlat
|
|
||||||
{
|
|
||||||
BackgroundColor = account.Color,
|
|
||||||
ContentMarginBottomOverride = 2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
Icon = { Texture = _spriteSystem.Frame0(product) },
|
Icon = { Texture = _spriteSystem.Frame0(product) },
|
||||||
|
|
||||||
ProductName =
|
ProductName =
|
||||||
{
|
{
|
||||||
Text = Loc.GetString(
|
Text = Loc.GetString(
|
||||||
"cargo-console-menu-populate-orders-cargo-order-row-product-name-text",
|
"cargo-console-menu-populate-orders-cargo-order-row-product-name-text",
|
||||||
("orderRequester", requester),
|
("productName", productName),
|
||||||
|
("orderAmount", order.OrderQuantity),
|
||||||
|
("orderRequester", order.Requester),
|
||||||
("accountColor", account.Color),
|
("accountColor", account.Color),
|
||||||
("account", Loc.GetString(account.Code)))
|
("account", Loc.GetString(account.Code)))
|
||||||
},
|
},
|
||||||
|
|
||||||
Description =
|
Description =
|
||||||
{
|
{
|
||||||
Text = !string.IsNullOrEmpty(order.Reason) ?
|
Text = Loc.GetString("cargo-console-menu-order-reason-description",
|
||||||
Loc.GetString(
|
("reason", order.Reason))
|
||||||
"cargo-console-menu-order-row-product-description",
|
|
||||||
("orderReason", order.Reason))
|
|
||||||
:
|
|
||||||
Loc.GetString(
|
|
||||||
"cargo-console-menu-order-row-product-description",
|
|
||||||
("orderReason", Loc.GetString("cargo-console-menu-order-row-alerts-reason-absent")))
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
row.Cancel.OnPressed += (args) => { OnOrderCanceled?.Invoke(args); };
|
||||||
row.Cancel.OnPressed += (args) => { OnOrderCanceled?.Invoke(order); };
|
|
||||||
|
|
||||||
// TODO: Disable based on access.
|
// TODO: Disable based on access.
|
||||||
row.SetApproveVisible(orderConsole.Mode != CargoOrderConsoleMode.SendToPrimary);
|
row.SetApproveVisible(orderConsole.Mode != CargoOrderConsoleMode.SendToPrimary);
|
||||||
row.Approve.OnPressed += (args) => { OnOrderApproved?.Invoke(order); };
|
row.Approve.OnPressed += (args) => { OnOrderApproved?.Invoke(args); };
|
||||||
Requests.AddChild(row);
|
Requests.AddChild(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -323,7 +294,8 @@ namespace Content.Client.Cargo.UI
|
|||||||
TransferSpinBox.Value > bankAccount.Accounts[orderConsole.Account] * orderConsole.TransferLimit ||
|
TransferSpinBox.Value > bankAccount.Accounts[orderConsole.Account] * orderConsole.TransferLimit ||
|
||||||
_timing.CurTime < orderConsole.NextAccountActionTime;
|
_timing.CurTime < orderConsole.NextAccountActionTime;
|
||||||
|
|
||||||
RightPart.Visible = orderConsole.Mode != CargoOrderConsoleMode.PrintSlip;
|
OrdersSpacer.Visible = orderConsole.Mode != CargoOrderConsoleMode.PrintSlip;
|
||||||
|
Orders.Visible = orderConsole.Mode != CargoOrderConsoleMode.PrintSlip;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,53 +1,33 @@
|
|||||||
<DefaultWindow xmlns="https://spacestation14.io"
|
<DefaultWindow xmlns="https://spacestation14.io"
|
||||||
Title="{Loc 'cargo-console-order-menu-title'}"
|
Title="{Loc 'cargo-console-order-menu-title'}">
|
||||||
MinSize="460 261">
|
|
||||||
<BoxContainer Orientation="Vertical">
|
<BoxContainer Orientation="Vertical">
|
||||||
<GridContainer Columns="2">
|
<GridContainer Columns="2">
|
||||||
<Label Text="{Loc 'cargo-console-order-menu-product-label'}"
|
<Label Text="{Loc 'cargo-console-order-menu-product-label'}" />
|
||||||
StyleClasses="LabelKeyText" />
|
|
||||||
|
|
||||||
<Label Name="ProductName"
|
<Label Name="ProductName"
|
||||||
Access="Public" />
|
Access="Public" />
|
||||||
|
<Label Text="{Loc 'cargo-console-order-menu-description-label'}" />
|
||||||
<Label Text="{Loc 'cargo-console-order-menu-description-label'}"
|
|
||||||
StyleClasses="LabelKeyText" />
|
|
||||||
|
|
||||||
<RichTextLabel Name="Description"
|
<RichTextLabel Name="Description"
|
||||||
Access="Public"
|
Access="Public"
|
||||||
HorizontalExpand="True"
|
VerticalExpand="True"
|
||||||
MaxWidth="460" />
|
SetWidth="350"/>
|
||||||
|
<Label Text="{Loc 'cargo-console-order-menu-cost-label'}" />
|
||||||
<Label Text="{Loc 'cargo-console-order-menu-cost-label'}"
|
|
||||||
StyleClasses="LabelKeyText" />
|
|
||||||
|
|
||||||
<Label Name="PointCost"
|
<Label Name="PointCost"
|
||||||
Access="Public" />
|
Access="Public" />
|
||||||
|
<Label Text="{Loc 'cargo-console-order-menu-requester-label'}" />
|
||||||
<Label Text="{Loc 'cargo-console-order-menu-requester-label'}"
|
|
||||||
StyleClasses="LabelKeyText" />
|
|
||||||
|
|
||||||
<LineEdit Name="Requester"
|
<LineEdit Name="Requester"
|
||||||
Access="Public" />
|
Access="Public" />
|
||||||
|
<Label Text="{Loc 'cargo-console-order-menu-reason-label'}" />
|
||||||
<Label Text="{Loc 'cargo-console-order-menu-reason-label'}"
|
|
||||||
StyleClasses="LabelKeyText" />
|
|
||||||
|
|
||||||
<LineEdit Name="Reason"
|
<LineEdit Name="Reason"
|
||||||
Access="Public" />
|
Access="Public" />
|
||||||
|
<Label Text="{Loc 'cargo-console-order-menu-amount-label'}" />
|
||||||
<Label Text="{Loc 'cargo-console-order-menu-amount-label'}"
|
|
||||||
StyleClasses="LabelKeyText" />
|
|
||||||
|
|
||||||
<SpinBox Name="Amount"
|
<SpinBox Name="Amount"
|
||||||
Access="Public"
|
Access="Public"
|
||||||
HorizontalExpand="True"
|
HorizontalExpand="True"
|
||||||
Value="1" />
|
Value="1" />
|
||||||
</GridContainer>
|
</GridContainer>
|
||||||
<Control VerticalExpand="True"/>
|
|
||||||
<PanelContainer StyleClasses="LowDivider" Margin="0 6 0 2"/>
|
|
||||||
<Button Name="SubmitButton"
|
<Button Name="SubmitButton"
|
||||||
Access="Public"
|
Access="Public"
|
||||||
Text="{Loc 'cargo-console-order-menu-submit-button'}"
|
Text="{Loc 'cargo-console-order-menu-submit-button'}"
|
||||||
VerticalAlignment="Bottom" />
|
TextAlign="Center" />
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</DefaultWindow>
|
</DefaultWindow>
|
||||||
|
|||||||
@@ -1,81 +1,33 @@
|
|||||||
<PanelContainer
|
<PanelContainer xmlns="https://spacestation14.io"
|
||||||
xmlns="https://spacestation14.io"
|
HorizontalExpand="True"
|
||||||
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
Margin="0 1">
|
||||||
HorizontalExpand="True"
|
<BoxContainer Orientation="Horizontal"
|
||||||
StyleClasses="BackgroundPanel">
|
HorizontalExpand="True">
|
||||||
|
<TextureRect Name="Icon"
|
||||||
<!-- Main Container -->
|
Access="Public"
|
||||||
<BoxContainer Orientation="Vertical"
|
MinSize="32 32"
|
||||||
HorizontalExpand="True"
|
RectClipContent="True" />
|
||||||
SeparationOverride="6"
|
<Control MinWidth="5"/>
|
||||||
Margin="-14 -2">
|
<BoxContainer Orientation="Vertical"
|
||||||
|
HorizontalExpand="True"
|
||||||
<BoxContainer Orientation="Vertical">
|
VerticalExpand="True">
|
||||||
<Control>
|
<RichTextLabel Name="ProductName"
|
||||||
<PanelContainer StyleClasses="WindowHeadingBackground" />
|
Access="Public"
|
||||||
|
HorizontalExpand="True"
|
||||||
<BoxContainer Margin="6">
|
StyleClasses="LabelSubText" />
|
||||||
<Label Name="Title"
|
<Label Name="Description"
|
||||||
Access="Public"
|
Access="Public"
|
||||||
MaxHeight="28"
|
HorizontalExpand="True"
|
||||||
StyleClasses="LabelKeyText"/>
|
StyleClasses="LabelSubText"
|
||||||
</BoxContainer>
|
ClipText="True" />
|
||||||
</Control>
|
</BoxContainer>
|
||||||
|
<Button Name="Approve"
|
||||||
<PanelContainer Name="Stride"
|
|
||||||
Access="Public"
|
Access="Public"
|
||||||
StyleClasses="LowDivider" />
|
Text="{Loc 'cargo-console-menu-cargo-order-row-approve-button'}"
|
||||||
</BoxContainer>
|
StyleClasses="OpenRight" />
|
||||||
|
<Button Name="Cancel"
|
||||||
<!-- Info -->
|
Access="Public"
|
||||||
<BoxContainer>
|
Text="{Loc 'cargo-console-menu-cargo-order-row-cancel-button'}"
|
||||||
<TextureRect Name="Icon"
|
StyleClasses="OpenLeft" />
|
||||||
Access="Public"
|
|
||||||
MinSize="32 32"
|
|
||||||
Margin="4"
|
|
||||||
Stretch="KeepAspectCentered"
|
|
||||||
RectClipContent="True"
|
|
||||||
VerticalAlignment="Center"/>
|
|
||||||
|
|
||||||
<PanelContainer StyleClasses="LowDivider" Margin="4 0"/>
|
|
||||||
|
|
||||||
<BoxContainer Orientation="Vertical"
|
|
||||||
HorizontalExpand="True"
|
|
||||||
VerticalExpand="True">
|
|
||||||
|
|
||||||
<RichTextLabel Name="ProductName"
|
|
||||||
Access="Public"
|
|
||||||
HorizontalExpand="True"
|
|
||||||
VerticalExpand="True"
|
|
||||||
StyleClasses="LabelSubText" />
|
|
||||||
|
|
||||||
<Label Name="Description"
|
|
||||||
Access="Public"
|
|
||||||
HorizontalExpand="True"
|
|
||||||
VerticalExpand="True"
|
|
||||||
StyleClasses="LabelSubText"
|
|
||||||
ClipText="True" />
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|
||||||
<BoxContainer Orientation="Vertical">
|
|
||||||
<PanelContainer StyleClasses="LowDivider" />
|
|
||||||
|
|
||||||
<!-- Buttons -->
|
|
||||||
<!-- Btn's position hardcoded (args.Button.Parent?.Parent?.Parent type) in CargoConsoleBUI 158 & 166 line -->
|
|
||||||
<BoxContainer Margin="6">
|
|
||||||
<Button Name="Approve"
|
|
||||||
Access="Public"
|
|
||||||
Text="{Loc 'cargo-console-menu-order-row-button-approve'}"
|
|
||||||
StyleClasses="OpenRight"
|
|
||||||
HorizontalExpand="True"/>
|
|
||||||
|
|
||||||
<Button Name="Cancel"
|
|
||||||
Access="Public"
|
|
||||||
Text="{Loc 'cargo-console-menu-order-row-button-cancel'}"
|
|
||||||
StyleClasses="OpenLeft"
|
|
||||||
HorizontalExpand="True" />
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</PanelContainer>
|
</PanelContainer>
|
||||||
|
|||||||
@@ -1,34 +1,26 @@
|
|||||||
<BoxContainer xmlns="https://spacestation14.io"
|
<PanelContainer xmlns="https://spacestation14.io"
|
||||||
HorizontalExpand="True">
|
HorizontalExpand="True">
|
||||||
<PanelContainer HorizontalExpand="True">
|
<Button Name="MainButton"
|
||||||
<!-- Btn position hardcoded (args.Button.Parent?.Parent type) in CargoConsoleBUI 71 line -->
|
ToolTip=""
|
||||||
<Button Name="MainButton"
|
Access="Public"
|
||||||
ToolTip=""
|
HorizontalExpand="True"
|
||||||
Access="Public"
|
VerticalExpand="True"
|
||||||
VerticalExpand="False"
|
StyleClasses="OpenBoth"/>
|
||||||
StyleClasses="OpenBoth" />
|
<BoxContainer Orientation="Horizontal"
|
||||||
|
HorizontalExpand="True">
|
||||||
<!-- Icon & Name -->
|
<TextureRect Name="Icon"
|
||||||
<BoxContainer Orientation="Horizontal"
|
Access="Public"
|
||||||
HorizontalExpand="True"
|
MinSize="32 32"
|
||||||
Margin="4 0">
|
RectClipContent="True" />
|
||||||
|
<Label Name="ProductName"
|
||||||
<TextureRect Name="Icon"
|
Access="Public"
|
||||||
Access="Public"
|
HorizontalExpand="True" />
|
||||||
MinSize="32 32"
|
<PanelContainer StyleClasses="BackgroundDark">
|
||||||
RectClipContent="True" />
|
<Label Name="PointCost"
|
||||||
|
|
||||||
<Label Name="ProductName"
|
|
||||||
Access="Public"
|
Access="Public"
|
||||||
HorizontalExpand="True"
|
MinSize="52 32"
|
||||||
ClipText="True" />
|
Align="Right"
|
||||||
</BoxContainer>
|
Margin="0 0 5 0"/>
|
||||||
</PanelContainer>
|
</PanelContainer>
|
||||||
|
</BoxContainer>
|
||||||
<Label Name="PointCost"
|
</PanelContainer>
|
||||||
Access="Public"
|
|
||||||
MinSize="56 32"
|
|
||||||
Align="Right"
|
|
||||||
Margin="0 0 5 0"
|
|
||||||
HorizontalAlignment="Right"/>
|
|
||||||
</BoxContainer>
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ using Robust.Client.UserInterface.XAML;
|
|||||||
namespace Content.Client.Cargo.UI
|
namespace Content.Client.Cargo.UI
|
||||||
{
|
{
|
||||||
[GenerateTypedNameReferences]
|
[GenerateTypedNameReferences]
|
||||||
public sealed partial class CargoProductRow : BoxContainer
|
public sealed partial class CargoProductRow : PanelContainer
|
||||||
{
|
{
|
||||||
public CargoProductPrototype? Product { get; set; }
|
public CargoProductPrototype? Product { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -34,10 +34,7 @@ namespace Content.Client.Cargo.UI
|
|||||||
|
|
||||||
foreach (var order in orders)
|
foreach (var order in orders)
|
||||||
{
|
{
|
||||||
if (!protoManager.Resolve(order.Product, out var productProto))
|
var product = protoManager.Index<EntityPrototype>(order.ProductId);
|
||||||
continue;
|
|
||||||
|
|
||||||
var product = protoManager.Index<EntityPrototype>(productProto.Product);
|
|
||||||
var productName = product.Name;
|
var productName = product.Name;
|
||||||
var account = protoManager.Index(order.Account);
|
var account = protoManager.Index(order.Account);
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem<TypingInd
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||||
|
[Dependency] private readonly SpriteSystem _sprite = default!;
|
||||||
|
|
||||||
protected override void OnAppearanceChange(EntityUid uid, TypingIndicatorComponent component, ref AppearanceChangeEvent args)
|
protected override void OnAppearanceChange(EntityUid uid, TypingIndicatorComponent component, ref AppearanceChangeEvent args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Shared.Chemistry.EntitySystems;
|
using Content.Shared.Chemistry.EntitySystems;
|
||||||
using Content.Shared.Atmos.Prototypes;
|
using Content.Shared.Atmos.Prototypes;
|
||||||
using Content.Shared.Body;
|
using Content.Shared.Body.Part;
|
||||||
using Content.Shared.Chemistry;
|
using Content.Shared.Chemistry;
|
||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||||
@@ -94,7 +94,7 @@ public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
//these bloat the hell out of blood/fat
|
//these bloat the hell out of blood/fat
|
||||||
if (entProto.HasComponent<OrganComponent>())
|
if (entProto.HasComponent<BodyPartComponent>())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//these feel obvious...
|
//these feel obvious...
|
||||||
@@ -116,7 +116,7 @@ public sealed class ChemistryGuideDataSystem : SharedChemistryGuideDataSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (extractableComponent.GrindableSolutionName is { } grindableSolutionId &&
|
if (extractableComponent.GrindableSolution is { } grindableSolutionId &&
|
||||||
entProto.TryGetComponent<SolutionContainerManagerComponent>(out var manager, EntityManager.ComponentFactory) &&
|
entProto.TryGetComponent<SolutionContainerManagerComponent>(out var manager, EntityManager.ComponentFactory) &&
|
||||||
_solutionContainer.TryGetSolution(manager, grindableSolutionId, out var grindableSolution))
|
_solutionContainer.TryGetSolution(manager, grindableSolutionId, out var grindableSolution))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
VerticalExpand="True"
|
VerticalExpand="True"
|
||||||
HorizontalExpand="True"
|
HorizontalExpand="True"
|
||||||
MinSize="100 150">
|
MinSize="100 150">
|
||||||
<PanelContainer VerticalExpand="True" StyleClasses="BackgroundPanelDark">
|
<PanelContainer VerticalExpand="True" StyleClasses="Inset">
|
||||||
<BoxContainer Name="GeneticScannerContents" Margin="5 5 5 5" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
|
<BoxContainer Name="GeneticScannerContents" Margin="5 5 5 5" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
|
||||||
<Label HorizontalAlignment="Center" Text="{Loc 'cloning-console-window-scanner-details-label'}" />
|
<Label HorizontalAlignment="Center" Text="{Loc 'cloning-console-window-scanner-details-label'}" />
|
||||||
<BoxContainer Orientation="Horizontal" VerticalExpand="True" HorizontalExpand="True">
|
<BoxContainer Orientation="Horizontal" VerticalExpand="True" HorizontalExpand="True">
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</PanelContainer>
|
</PanelContainer>
|
||||||
<Control MinSize="50 5" />
|
<Control MinSize="50 5" />
|
||||||
<PanelContainer VerticalExpand="True" StyleClasses="BackgroundPanelDark">
|
<PanelContainer VerticalExpand="True" StyleClasses="Inset">
|
||||||
<BoxContainer Name="CloningPodContents" Margin="5 5 5 5" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
|
<BoxContainer Name="CloningPodContents" Margin="5 5 5 5" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
|
||||||
<Label HorizontalAlignment="Center" Text="{Loc 'cloning-console-window-pod-details-label'}" />
|
<Label HorizontalAlignment="Center" Text="{Loc 'cloning-console-window-pod-details-label'}" />
|
||||||
<BoxContainer Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
|
<BoxContainer Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ public sealed class ClientClothingSystem : ClothingSystem
|
|||||||
// Select displacement maps
|
// Select displacement maps
|
||||||
var displacementData = inventory.Displacements.GetValueOrDefault(slot); //Default unsexed map
|
var displacementData = inventory.Displacements.GetValueOrDefault(slot); //Default unsexed map
|
||||||
|
|
||||||
var equipeeSex = CompOrNull<HumanoidProfileComponent>(equipee)?.Sex;
|
var equipeeSex = CompOrNull<HumanoidAppearanceComponent>(equipee)?.Sex;
|
||||||
if (equipeeSex != null)
|
if (equipeeSex != null)
|
||||||
{
|
{
|
||||||
switch (equipeeSex)
|
switch (equipeeSex)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Client.Hands.Systems;
|
using Content.Client.Hands.Systems;
|
||||||
|
using Content.Client.NPC.HTN;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.CombatMode;
|
using Content.Shared.CombatMode;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
@@ -58,6 +59,11 @@ public sealed class CombatModeSystem : SharedCombatModeSystem
|
|||||||
UpdateHud(entity);
|
UpdateHud(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool IsNpc(EntityUid uid)
|
||||||
|
{
|
||||||
|
return HasComp<HTNComponent>(uid);
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateHud(EntityUid entity)
|
private void UpdateHud(EntityUid entity)
|
||||||
{
|
{
|
||||||
if (entity != _playerManager.LocalEntity || !Timing.IsFirstTimePredicted)
|
if (entity != _playerManager.LocalEntity || !Timing.IsFirstTimePredicted)
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using Content.Shared.Body.Organ;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
|
||||||
|
namespace Content.Client.Commands;
|
||||||
|
|
||||||
|
public sealed class HideMechanismsCommand : LocalizedEntityCommands
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||||
|
[Dependency] private readonly SpriteSystem _spriteSystem = default!;
|
||||||
|
|
||||||
|
public override string Command => "hidemechanisms";
|
||||||
|
|
||||||
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
|
{
|
||||||
|
var query = EntityManager.AllEntityQueryEnumerator<OrganComponent, SpriteComponent>();
|
||||||
|
|
||||||
|
while (query.MoveNext(out var uid, out _, out var sprite))
|
||||||
|
{
|
||||||
|
_spriteSystem.SetContainerOccluded((uid, sprite), false);
|
||||||
|
|
||||||
|
var tempParent = uid;
|
||||||
|
while (_containerSystem.TryGetContainingContainer((tempParent, null, null), out var container))
|
||||||
|
{
|
||||||
|
if (!container.ShowContents)
|
||||||
|
{
|
||||||
|
_spriteSystem.SetContainerOccluded((uid, sprite), true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tempParent = container.Owner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using Content.Shared.Body.Organ;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
|
||||||
|
namespace Content.Client.Commands;
|
||||||
|
|
||||||
|
public sealed class ShowMechanismsCommand : LocalizedEntityCommands
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SpriteSystem _spriteSystem = default!;
|
||||||
|
|
||||||
|
public override string Command => "showmechanisms";
|
||||||
|
|
||||||
|
public override void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
|
{
|
||||||
|
var query = EntityManager.AllEntityQueryEnumerator<OrganComponent, SpriteComponent>();
|
||||||
|
|
||||||
|
while (query.MoveNext(out var uid, out _, out var sprite))
|
||||||
|
{
|
||||||
|
_spriteSystem.SetContainerOccluded((uid, sprite), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ namespace Content.Client.Communications.UI
|
|||||||
_menu.OnBroadcast += BroadcastButtonPressed;
|
_menu.OnBroadcast += BroadcastButtonPressed;
|
||||||
_menu.OnAlertLevel += AlertLevelSelected;
|
_menu.OnAlertLevel += AlertLevelSelected;
|
||||||
_menu.OnEmergencyLevel += EmergencyShuttleButtonPressed;
|
_menu.OnEmergencyLevel += EmergencyShuttleButtonPressed;
|
||||||
|
_menu.OnExfiltrationLevel += ExfiltrationShuttleButtonPressed; // DeltaV - Exfiltration shuttle
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AlertLevelSelected(string level)
|
public void AlertLevelSelected(string level)
|
||||||
@@ -47,6 +48,13 @@ namespace Content.Client.Communications.UI
|
|||||||
CallShuttle();
|
CallShuttle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Begin DeltaV - Exfiltration Shuttle
|
||||||
|
public void ExfiltrationShuttleButtonPressed()
|
||||||
|
{
|
||||||
|
SendMessage(new CommunicationsConsoleExfiltrationShuttleMessage(!_menu!.CountdownStarted));
|
||||||
|
}
|
||||||
|
// End DeltaV - Exfiltration Shuttle
|
||||||
|
|
||||||
public void AnnounceButtonPressed(string message)
|
public void AnnounceButtonPressed(string message)
|
||||||
{
|
{
|
||||||
var maxLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength);
|
var maxLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength);
|
||||||
@@ -86,6 +94,13 @@ namespace Content.Client.Communications.UI
|
|||||||
_menu.CurrentLevel = commsState.CurrentAlert;
|
_menu.CurrentLevel = commsState.CurrentAlert;
|
||||||
_menu.CountdownEnd = commsState.ExpectedCountdownEnd;
|
_menu.CountdownEnd = commsState.ExpectedCountdownEnd;
|
||||||
|
|
||||||
|
|
||||||
|
// Begin DeltaV - Exfiltration Shuttle
|
||||||
|
_menu.CanExfiltrate = commsState.CanCall;
|
||||||
|
_menu.ExfiltrationCountdownEnd = commsState.ExpectedExfiltrationCountdownEnd;
|
||||||
|
_menu.ExfiltrationShuttleButton.Disabled = !_menu.CanExfiltrate;
|
||||||
|
// End DeltaV - Exfiltration Shuttle
|
||||||
|
|
||||||
_menu.UpdateCountdown();
|
_menu.UpdateCountdown();
|
||||||
_menu.UpdateAlertLevels(commsState.AlertLevels, _menu.CurrentLevel);
|
_menu.UpdateAlertLevels(commsState.AlertLevels, _menu.CurrentLevel);
|
||||||
_menu.AlertLevelButton.Disabled = !_menu.AlertLevelSelectable;
|
_menu.AlertLevelButton.Disabled = !_menu.AlertLevelSelectable;
|
||||||
|
|||||||
@@ -52,10 +52,19 @@
|
|||||||
|
|
||||||
<RichTextLabel Name="CountdownLabel"/>
|
<RichTextLabel Name="CountdownLabel"/>
|
||||||
|
|
||||||
|
<!-- DeltaV - Exfiltration Shuttle -->
|
||||||
|
<RichTextLabel Name="ExfiltrationCountdownLabel"/>
|
||||||
|
|
||||||
<Button Name="EmergencyShuttleButton"
|
<Button Name="EmergencyShuttleButton"
|
||||||
Access="Public"
|
Access="Public"
|
||||||
Text="Placeholder Text"
|
Text="Placeholder Text"
|
||||||
ToolTip="{Loc 'comms-console-menu-emergency-shuttle-button-tooltip'}"/>
|
ToolTip="{Loc 'comms-console-menu-emergency-shuttle-button-tooltip'}"/>
|
||||||
|
|
||||||
|
<!-- DeltaV - Exfiltration Shuttle -->
|
||||||
|
<Button Name="ExfiltrationShuttleButton"
|
||||||
|
Access="Public"
|
||||||
|
Text="Placeholder Text"
|
||||||
|
ToolTip="{Loc 'comms-console-menu-exfiltration-shuttle-button-tooltip'}"/>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
</BoxContainer>
|
</BoxContainer>
|
||||||
|
|||||||
@@ -29,6 +29,12 @@ namespace Content.Client.Communications.UI
|
|||||||
public event Action<string>? OnAnnounce;
|
public event Action<string>? OnAnnounce;
|
||||||
public event Action<string>? OnBroadcast;
|
public event Action<string>? OnBroadcast;
|
||||||
|
|
||||||
|
// Begin DeltaV - Exfiltration Shuttle
|
||||||
|
public bool CanExfiltrate;
|
||||||
|
public TimeSpan? ExfiltrationCountdownEnd;
|
||||||
|
public event Action? OnExfiltrationLevel;
|
||||||
|
// End DeltaV - Exfiltration Shuttle
|
||||||
|
|
||||||
public CommunicationsConsoleMenu()
|
public CommunicationsConsoleMenu()
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
@@ -72,12 +78,18 @@ namespace Content.Client.Communications.UI
|
|||||||
|
|
||||||
EmergencyShuttleButton.OnPressed += _ => OnEmergencyLevel?.Invoke();
|
EmergencyShuttleButton.OnPressed += _ => OnEmergencyLevel?.Invoke();
|
||||||
EmergencyShuttleButton.Disabled = !CanCall;
|
EmergencyShuttleButton.Disabled = !CanCall;
|
||||||
|
|
||||||
|
// Begin DeltaV - Exfiltration Shuttle
|
||||||
|
ExfiltrationShuttleButton.OnPressed += _ => OnExfiltrationLevel?.Invoke();
|
||||||
|
ExfiltrationShuttleButton.Disabled = !CanExfiltrate;
|
||||||
|
// End DeltaV - Exfiltration Shuttle
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void FrameUpdate(FrameEventArgs args)
|
protected override void FrameUpdate(FrameEventArgs args)
|
||||||
{
|
{
|
||||||
base.FrameUpdate(args);
|
base.FrameUpdate(args);
|
||||||
UpdateCountdown();
|
UpdateCountdown();
|
||||||
|
UpdateExfiltrationCountdown(); // DeltaV - Exfiltration shuttle
|
||||||
}
|
}
|
||||||
|
|
||||||
// The current alert could make levels unselectable, so we need to ensure that the UI reacts properly.
|
// The current alert could make levels unselectable, so we need to ensure that the UI reacts properly.
|
||||||
@@ -117,6 +129,25 @@ namespace Content.Client.Communications.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Begin DeltaV - Exfiltration Shuttle
|
||||||
|
public void UpdateExfiltrationCountdown()
|
||||||
|
{
|
||||||
|
if (ExfiltrationCountdownEnd is null)
|
||||||
|
{
|
||||||
|
ExfiltrationCountdownLabel.SetMessage(string.Empty);
|
||||||
|
ExfiltrationShuttleButton.Text = Loc.GetString("comms-console-menu-call-exfiltration");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var exfiltrationDiff = MathHelper.Max((ExfiltrationCountdownEnd - _timing.CurTime) ?? TimeSpan.Zero, TimeSpan.Zero);
|
||||||
|
ExfiltrationShuttleButton.Text = Loc.GetString("comms-console-menu-recall-exfiltration");
|
||||||
|
|
||||||
|
var exfiltrationInfoText = Loc.GetString("comms-console-menu-exfiltration-time-remaining",
|
||||||
|
("time", exfiltrationDiff.ToString(@"hh\:mm\:ss", CultureInfo.CurrentCulture)));
|
||||||
|
ExfiltrationCountdownLabel.SetMessage(exfiltrationInfoText);
|
||||||
|
}
|
||||||
|
// End DeltaV - Exfiltration Shuttle
|
||||||
|
|
||||||
public void UpdateCountdown()
|
public void UpdateCountdown()
|
||||||
{
|
{
|
||||||
if (!CountdownStarted)
|
if (!CountdownStarted)
|
||||||
|
|||||||
@@ -291,6 +291,7 @@ namespace Content.Client.Construction
|
|||||||
_ghosts.Add(comp.GhostId, ghost.Value);
|
_ghosts.Add(comp.GhostId, ghost.Value);
|
||||||
|
|
||||||
var sprite = Comp<SpriteComponent>(ghost.Value);
|
var sprite = Comp<SpriteComponent>(ghost.Value);
|
||||||
|
_sprite.SetColor((ghost.Value, sprite), new Color(48, 255, 48, 128));
|
||||||
|
|
||||||
if (targetProto.TryGetComponent(out IconComponent? icon, EntityManager.ComponentFactory))
|
if (targetProto.TryGetComponent(out IconComponent? icon, EntityManager.ComponentFactory))
|
||||||
{
|
{
|
||||||
@@ -305,11 +306,20 @@ namespace Content.Client.Construction
|
|||||||
var targetSprite = EnsureComp<SpriteComponent>(dummy);
|
var targetSprite = EnsureComp<SpriteComponent>(dummy);
|
||||||
EntityManager.System<AppearanceSystem>().OnChangeData(dummy, targetSprite);
|
EntityManager.System<AppearanceSystem>().OnChangeData(dummy, targetSprite);
|
||||||
|
|
||||||
_sprite.CopySprite((dummy, targetSprite), (ghost.Value, sprite));
|
for (var i = 0; i < targetSprite.AllLayers.Count(); i++)
|
||||||
|
|
||||||
for (var i = 0; i < sprite.AllLayers.Count(); i++)
|
|
||||||
{
|
{
|
||||||
|
if (!targetSprite[i].Visible || !targetSprite[i].RsiState.IsValid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var rsi = targetSprite[i].Rsi ?? targetSprite.BaseRSI;
|
||||||
|
if (rsi is null || !rsi.TryGetState(targetSprite[i].RsiState, out var state) ||
|
||||||
|
state.StateId.Name is null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_sprite.AddBlankLayer((ghost.Value, sprite), i);
|
||||||
|
_sprite.LayerSetSprite((ghost.Value, sprite), i, new SpriteSpecifier.Rsi(rsi.Path, state.StateId.Name));
|
||||||
sprite.LayerSetShader(i, "unshaded");
|
sprite.LayerSetShader(i, "unshaded");
|
||||||
|
_sprite.LayerSetVisible((ghost.Value, sprite), i, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Del(dummy);
|
Del(dummy);
|
||||||
@@ -317,8 +327,6 @@ namespace Content.Client.Construction
|
|||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_sprite.SetColor((ghost.Value, sprite), new Color(48, 255, 48, 128));
|
|
||||||
|
|
||||||
if (prototype.CanBuildInImpassable)
|
if (prototype.CanBuildInImpassable)
|
||||||
EnsureComp<WallMountComponent>(ghost.Value).Arc = new(Math.Tau);
|
EnsureComp<WallMountComponent>(ghost.Value).Arc = new(Math.Tau);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using Content.Shared.Damage.Prototypes;
|
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Client.Damage;
|
namespace Content.Client.Damage;
|
||||||
|
|
||||||
@@ -57,7 +55,7 @@ public sealed partial class DamageVisualsComponent : Component
|
|||||||
/// (for example, Brute), and has a value
|
/// (for example, Brute), and has a value
|
||||||
/// of a DamageVisualizerSprite (see below)
|
/// of a DamageVisualizerSprite (see below)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("damageOverlayGroups")] public Dictionary<ProtoId<DamageGroupPrototype>, DamageVisualizerSprite>? DamageOverlayGroups;
|
[DataField("damageOverlayGroups")] public Dictionary<string, DamageVisualizerSprite>? DamageOverlayGroups;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets if you want sprites to overlay the
|
/// Sets if you want sprites to overlay the
|
||||||
@@ -86,7 +84,7 @@ public sealed partial class DamageVisualsComponent : Component
|
|||||||
/// what kind of damage combination
|
/// what kind of damage combination
|
||||||
/// you would want, on which threshold.
|
/// you would want, on which threshold.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[DataField("damageGroup")] public ProtoId<DamageGroupPrototype>? DamageGroup;
|
[DataField("damageGroup")] public string? DamageGroup;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this if you want incoming damage to be
|
/// Set this if you want incoming damage to be
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using System.Linq;
|
|||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Damage.Components;
|
using Content.Shared.Damage.Components;
|
||||||
using Content.Shared.Damage.Prototypes;
|
using Content.Shared.Damage.Prototypes;
|
||||||
using Content.Shared.Damage.Systems;
|
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
@@ -29,7 +28,6 @@ namespace Content.Client.Damage;
|
|||||||
public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponent>
|
public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponent>
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -176,7 +174,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
|
|||||||
// See if that group is in our entity's damage container.
|
// See if that group is in our entity's damage container.
|
||||||
else if (!damageVisComp.Overlay && damageVisComp.DamageGroup != null)
|
else if (!damageVisComp.Overlay && damageVisComp.DamageGroup != null)
|
||||||
{
|
{
|
||||||
if (!damageContainer.SupportedGroups.Contains(damageVisComp.DamageGroup.Value))
|
if (!damageContainer.SupportedGroups.Contains(damageVisComp.DamageGroup))
|
||||||
{
|
{
|
||||||
Log.Error($"Damage keys were invalid for entity {entity}.");
|
Log.Error($"Damage keys were invalid for entity {entity}.");
|
||||||
damageVisComp.Valid = false;
|
damageVisComp.Valid = false;
|
||||||
@@ -386,7 +384,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
|
|||||||
if (!AppearanceSystem.TryGetData<DamageVisualizerGroupData>(uid, DamageVisualizerKeys.DamageUpdateGroups,
|
if (!AppearanceSystem.TryGetData<DamageVisualizerGroupData>(uid, DamageVisualizerKeys.DamageUpdateGroups,
|
||||||
out var data, component))
|
out var data, component))
|
||||||
{
|
{
|
||||||
data = new DamageVisualizerGroupData(_damageable.GetDamagePerGroup(uid).Keys.ToList());
|
data = new DamageVisualizerGroupData(Comp<DamageableComponent>(uid).DamagePerGroup.Keys.ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateDamageVisuals(data.GroupList, (uid, damageComponent, spriteComponent, damageVisComp));
|
UpdateDamageVisuals(data.GroupList, (uid, damageComponent, spriteComponent, damageVisComp));
|
||||||
@@ -488,10 +486,11 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateDamageVisuals(Entity<DamageableComponent, SpriteComponent, DamageVisualsComponent> entity)
|
private void UpdateDamageVisuals(Entity<DamageableComponent, SpriteComponent, DamageVisualsComponent> entity)
|
||||||
{
|
{
|
||||||
|
var damageComponent = entity.Comp1;
|
||||||
var spriteComponent = entity.Comp2;
|
var spriteComponent = entity.Comp2;
|
||||||
var damageVisComp = entity.Comp3;
|
var damageVisComp = entity.Comp3;
|
||||||
|
|
||||||
if (!CheckThresholdBoundary(_damageable.GetTotalDamage(entity.AsNullable()), damageVisComp.LastDamageThreshold, damageVisComp, out var threshold))
|
if (!CheckThresholdBoundary(damageComponent.TotalDamage, damageVisComp.LastDamageThreshold, damageVisComp, out var threshold))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
damageVisComp.LastDamageThreshold = threshold;
|
damageVisComp.LastDamageThreshold = threshold;
|
||||||
@@ -514,11 +513,11 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
|
|||||||
/// according to the list of damage groups
|
/// according to the list of damage groups
|
||||||
/// passed into it.
|
/// passed into it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void UpdateDamageVisuals(List<ProtoId<DamageGroupPrototype>> delta, Entity<DamageableComponent, SpriteComponent, DamageVisualsComponent> entity)
|
private void UpdateDamageVisuals(List<string> delta, Entity<DamageableComponent, SpriteComponent, DamageVisualsComponent> entity)
|
||||||
{
|
{
|
||||||
|
var damageComponent = entity.Comp1;
|
||||||
var spriteComponent = entity.Comp2;
|
var spriteComponent = entity.Comp2;
|
||||||
var damageVisComp = entity.Comp3;
|
var damageVisComp = entity.Comp3;
|
||||||
var damage = _damageable.GetAllDamage((entity.Owner, entity.Comp1));
|
|
||||||
|
|
||||||
foreach (var damageGroup in delta)
|
foreach (var damageGroup in delta)
|
||||||
{
|
{
|
||||||
@@ -526,7 +525,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!_prototypeManager.TryIndex<DamageGroupPrototype>(damageGroup, out var damageGroupPrototype)
|
if (!_prototypeManager.TryIndex<DamageGroupPrototype>(damageGroup, out var damageGroupPrototype)
|
||||||
|| !damage.TryGetDamageInGroup(damageGroupPrototype, out var damageTotal))
|
|| !damageComponent.Damage.TryGetDamageInGroup(damageGroupPrototype, out var damageTotal))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!damageVisComp.LastThresholdPerGroup.TryGetValue(damageGroup, out var lastThreshold)
|
if (!damageVisComp.LastThresholdPerGroup.TryGetValue(damageGroup, out var lastThreshold)
|
||||||
@@ -591,7 +590,7 @@ public sealed class DamageVisualsSystem : VisualizerSystem<DamageVisualsComponen
|
|||||||
}
|
}
|
||||||
else if (damageVisComp.DamageGroup != null)
|
else if (damageVisComp.DamageGroup != null)
|
||||||
{
|
{
|
||||||
UpdateDamageVisuals(new() { damageVisComp.DamageGroup.Value }, entity);
|
UpdateDamageVisuals(new List<string>() { damageVisComp.DamageGroup }, entity);
|
||||||
}
|
}
|
||||||
else if (damageVisComp.DamageOverlay != null)
|
else if (damageVisComp.DamageOverlay != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
using Content.Shared.CCVar;
|
|
||||||
using Content.Shared.Drunk;
|
using Content.Shared.Drunk;
|
||||||
|
using Content.Shared.StatusEffect;
|
||||||
|
using Content.Shared.StatusEffectNew;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Configuration;
|
|
||||||
using Robust.Shared.Enums;
|
using Robust.Shared.Enums;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
@@ -11,23 +11,19 @@ namespace Content.Client.Drunk;
|
|||||||
|
|
||||||
public sealed class DrunkOverlay : Overlay
|
public sealed class DrunkOverlay : Overlay
|
||||||
{
|
{
|
||||||
private static readonly ProtoId<ShaderPrototype> DrunkShader = "Drunk";
|
private static readonly ProtoId<ShaderPrototype> Shader = "Drunk";
|
||||||
|
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
[Dependency] private readonly IEntitySystemManager _sysMan = default!;
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _configManager = default!;
|
|
||||||
private readonly Shared.StatusEffectNew.StatusEffectsSystem _statusEffectsSystem;
|
|
||||||
|
|
||||||
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||||
public override bool RequestScreenTexture => true;
|
public override bool RequestScreenTexture => true;
|
||||||
private readonly ShaderInstance _drunkShader;
|
private readonly ShaderInstance _drunkShader;
|
||||||
|
|
||||||
public float CurrentBoozePower = 0.0f;
|
public float CurrentBoozePower = 0.0f;
|
||||||
// Starting phase for the rotation effect.
|
|
||||||
// Needed so it doesn't always look the same for 0 motion.
|
|
||||||
public float Phase = 0f;
|
|
||||||
|
|
||||||
private const float VisualThreshold = 10.0f;
|
private const float VisualThreshold = 10.0f;
|
||||||
private const float PowerDivisor = 250.0f;
|
private const float PowerDivisor = 250.0f;
|
||||||
@@ -41,22 +37,12 @@ public sealed class DrunkOverlay : Overlay
|
|||||||
|
|
||||||
private const float BoozePowerScale = 8f;
|
private const float BoozePowerScale = 8f;
|
||||||
|
|
||||||
private float _visualScale = 0f;
|
private float _visualScale = 0;
|
||||||
private float _timeScale = 1f;
|
|
||||||
private float _distortionScale = 1f;
|
|
||||||
|
|
||||||
public DrunkOverlay()
|
public DrunkOverlay()
|
||||||
{
|
{
|
||||||
IoCManager.InjectDependencies(this);
|
IoCManager.InjectDependencies(this);
|
||||||
_statusEffectsSystem = _entityManager.System<Shared.StatusEffectNew.StatusEffectsSystem>();
|
_drunkShader = _prototypeManager.Index(Shader).InstanceUnique();
|
||||||
_drunkShader = _prototypeManager.Index(DrunkShader).InstanceUnique();
|
|
||||||
_configManager.OnValueChanged(CCVars.ReducedMotion, OnReducedMotionChanged, invokeImmediately: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnReducedMotionChanged(bool reducedMotion)
|
|
||||||
{
|
|
||||||
_timeScale = reducedMotion ? 0.0f : 1.0f;
|
|
||||||
_distortionScale = reducedMotion ? 4.0f : 1.0f; // Make the offset stronger to compensate the lack of motion.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void FrameUpdate(FrameEventArgs args)
|
protected override void FrameUpdate(FrameEventArgs args)
|
||||||
@@ -67,14 +53,15 @@ public sealed class DrunkOverlay : Overlay
|
|||||||
if (playerEntity == null)
|
if (playerEntity == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_statusEffectsSystem.TryGetMaxTime<DrunkStatusEffectComponent>(playerEntity.Value, out var status))
|
var statusSys = _sysMan.GetEntitySystem<Shared.StatusEffectNew.StatusEffectsSystem>();
|
||||||
|
if (!statusSys.TryGetMaxTime<DrunkStatusEffectComponent>(playerEntity.Value, out var status))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var time = status.Item2;
|
var time = status.Item2;
|
||||||
|
|
||||||
var power = time == null ? MaxBoozePower : (float)Math.Min((time - _timing.CurTime).Value.TotalSeconds, MaxBoozePower);
|
var power = time == null ? MaxBoozePower : (float) Math.Min((time - _timing.CurTime).Value.TotalSeconds, MaxBoozePower);
|
||||||
|
|
||||||
CurrentBoozePower += BoozePowerScale * (power - CurrentBoozePower) * args.DeltaSeconds / (power + 1);
|
CurrentBoozePower += BoozePowerScale * (power - CurrentBoozePower) * args.DeltaSeconds / (power+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
protected override bool BeforeDraw(in OverlayDrawArgs args)
|
||||||
@@ -95,12 +82,8 @@ public sealed class DrunkOverlay : Overlay
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var handle = args.WorldHandle;
|
var handle = args.WorldHandle;
|
||||||
|
|
||||||
_drunkShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
|
_drunkShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
|
||||||
_drunkShader.SetParameter("boozePower", _visualScale);
|
_drunkShader.SetParameter("boozePower", _visualScale);
|
||||||
_drunkShader.SetParameter("timeScale", _timeScale);
|
|
||||||
_drunkShader.SetParameter("distortionScale", _distortionScale);
|
|
||||||
_drunkShader.SetParameter("phase", Phase);
|
|
||||||
handle.UseShader(_drunkShader);
|
handle.UseShader(_drunkShader);
|
||||||
handle.DrawRect(args.WorldBounds, Color.White);
|
handle.DrawRect(args.WorldBounds, Color.White);
|
||||||
handle.UseShader(null);
|
handle.UseShader(null);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using Content.Shared.StatusEffectNew;
|
|||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.Player;
|
using Robust.Client.Player;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
using Robust.Shared.Random;
|
|
||||||
|
|
||||||
namespace Content.Client.Drunk;
|
namespace Content.Client.Drunk;
|
||||||
|
|
||||||
@@ -11,7 +10,6 @@ public sealed class DrunkSystem : SharedDrunkSystem
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IPlayerManager _player = default!;
|
[Dependency] private readonly IPlayerManager _player = default!;
|
||||||
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
|
||||||
|
|
||||||
private DrunkOverlay _overlay = default!;
|
private DrunkOverlay _overlay = default!;
|
||||||
|
|
||||||
@@ -31,10 +29,7 @@ public sealed class DrunkSystem : SharedDrunkSystem
|
|||||||
private void OnStatusApplied(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectAppliedEvent args)
|
private void OnStatusApplied(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectAppliedEvent args)
|
||||||
{
|
{
|
||||||
if (!_overlayMan.HasOverlay<DrunkOverlay>())
|
if (!_overlayMan.HasOverlay<DrunkOverlay>())
|
||||||
{
|
|
||||||
_overlay.Phase = _random.NextFloat(MathF.Tau); // random starting phase for movement effect
|
|
||||||
_overlayMan.AddOverlay(_overlay);
|
_overlayMan.AddOverlay(_overlay);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStatusRemoved(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRemovedEvent args)
|
private void OnStatusRemoved(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRemovedEvent args)
|
||||||
@@ -52,7 +47,6 @@ public sealed class DrunkSystem : SharedDrunkSystem
|
|||||||
private void OnPlayerAttached(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRelayedEvent<LocalPlayerAttachedEvent> args)
|
private void OnPlayerAttached(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRelayedEvent<LocalPlayerAttachedEvent> args)
|
||||||
{
|
{
|
||||||
_overlayMan.AddOverlay(_overlay);
|
_overlayMan.AddOverlay(_overlay);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPlayerDetached(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRelayedEvent<LocalPlayerDetachedEvent> args)
|
private void OnPlayerDetached(Entity<DrunkStatusEffectComponent> entity, ref StatusEffectRelayedEvent<LocalPlayerDetachedEvent> args)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user